Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blockchain, fullblocktests, workmath, testhelper: add InvalidateBlock() method to BlockChain #2155

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

kcalvinalvin
Copy link
Collaborator

Depends on #2153

All of the code except for the last two commits are for refactoring code. The vast majority is just moving code from fullblocktests to testhelper so that the testing code for InvalidateBlock() can call the functions instead of having to copy over and duplicate functions.

The InvalidateBlock() method is operational and is tested but is not revealed through rpc in this PR.

@coveralls
Copy link

coveralls commented Apr 2, 2024

Pull Request Test Coverage Report for Build 8891501246

Details

  • 292 of 315 (92.7%) changed or added relevant lines in 5 files are covered.
  • 10 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.1%) to 56.978%

Changes Missing Coverage Covered Lines Changed/Added Lines %
blockchain/fullblocktests/generate.go 41 42 97.62%
blockchain/internal/testhelper/common.go 105 113 92.92%
blockchain/chain.go 76 90 84.44%
Files with Coverage Reduction New Missed Lines %
connmgr/connmanager.go 1 86.27%
peer/peer.go 9 73.72%
Totals Coverage Status
Change from base Build 8881487645: 0.1%
Covered Lines: 29567
Relevant Lines: 51892

💛 - Coveralls

@@ -0,0 +1,16 @@
testhelper
Copy link
Member

Choose a reason for hiding this comment

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

We could also make this an internal package if we don't envision any external usage (hidden from default godoc, can't be imported outside the project).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes. Made an internal package inside the package blockchain

@@ -14,6 +14,7 @@ import (
"strings"
"time"

"github.com/btcsuite/btcd/blockchain/testhelper"
Copy link
Member

Choose a reason for hiding this comment

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

Commit references invalidateblock and reconsiderblock, but only the latter was added in this PR.

Copy link
Member

Choose a reason for hiding this comment

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

I think for cases like the issue with the pruning bug w/ the utxo set cache, we actually want reconsiderblock, as invalidateblock marks all the dependents as invalid, so it won't attempt to reprocess anything after the target block.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll add it in as another PR so that it doesn't add on to the needed reviews on this PR.

Was holding it off because the test for reconsiderblock utilizes invalidateblock

}

if writeErr := b.index.flushToDB(); writeErr != nil {
log.Warnf("Error flushing block index changes to disk: %v", writeErr)
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, perhaps we should just hard fail here instead? As possible that we have unclean state in the db at this point, and accepting further blocks may cause cascading issues.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes.

b.index.UnsetStatusFlags(n, statusValid)
detachNodes.PushBack(n)
}
// Push back the block node being invalidated.
Copy link
Member

Choose a reason for hiding this comment

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

Style nit: missing space above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes.

chainGen func() (*BlockChain, []*chainhash.Hash, func())
}{
{
name: "One branch, invalidate once",
Copy link
Member

Choose a reason for hiding this comment

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

Should start with a lower case character for uniformity.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes.

source := rand.NewSource(time.Now().UnixNano())
rand := rand.New(source)

chain, params, tearDown := utxoCacheTestChain("TestInvalidateBlock-one-branch-invalidate-once")
Copy link
Member

Choose a reason for hiding this comment

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

I know we don't have the full linter active in this project, but can we wrap all this to 80 char columns to match most of the rest of the codebase?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes.

randIdx := rand.Intn(len(allSpends))

spend := allSpends[randIdx] // get
allSpends = append(allSpends[:randIdx], allSpends[randIdx+1:]...) // delete
Copy link
Member

Choose a reason for hiding this comment

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

var invalidateHash *chainhash.Hash

// Create a chain with 11 blocks.
for b := 0; b < 10; b++ {
Copy link
Member

Choose a reason for hiding this comment

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

Can consolidate into a helper func based on the other instance above where we make the same 11 block chain.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will finish this promptly

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest push

}

// Create a side chain with 7 blocks that builds on block 1.
var altSpends []*testhelper.SpendableOut
Copy link
Member

Choose a reason for hiding this comment

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

Same here re helper func for the 7 block chain.


for _, test := range tests {
chain, invalidateHashes, tearDown := test.chainGen()
func() {
Copy link
Member

Choose a reason for hiding this comment

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

Why the closure func that gets immediately executed?

Copy link
Member

Choose a reason for hiding this comment

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

We can also use t.Run here, then that way the test name gets printed during execution, and we can run just one of the sub-tests by name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Was doing this so that even when the test fails, we still run the teardown

Copy link
Collaborator

@Crypt-iQ Crypt-iQ left a comment

Choose a reason for hiding this comment

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

looks good, think the tests could be cleaned up a little and have more comments

allSpends = append(allSpends, newSpendableOuts...)

var nextSpendsTmp []*testhelper.SpendableOut
for i := 0; i < len(allSpends); i++ {
Copy link
Collaborator

Choose a reason for hiding this comment

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

A comment explaining what this is doing would be very helpful

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Addressed in the latest pushes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of randomly grabbing, doesn't this grab all of the utxos from allSpends?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh you're right. Fixed the code in the latest push.

}{
{
name: "One branch, invalidate once",
chainGen: func() (*BlockChain, []*chainhash.Hash, func()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

think this should be functions below rather than explicitly in full form here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could you clarify what you mean here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just mean moving the chainGen function into a function outside of the test so you just call chainGen:funcHere for readability. Just my preference, but it's non blocking

@Roasbeef
Copy link
Member

Dependent PR merged, needs a rebase!

@kcalvinalvin kcalvinalvin force-pushed the 2024-04-02-invalidate-block branch 2 times, most recently from 6b3238e to 7e9b796 Compare April 22, 2024 17:19
Some of the functions in difficulty.go are not dependent on any external
functions and they are needed to introduce testing code for the
invalidateblock and reconsiderblock methods that are to be added on in
later commits. Having the workmath package let's us reuse the code and
avoid dependency cycles.

The existing functions that were exported already (HashToBig,
CompactToBig, BigToCompact, CalcWork) are still kept in difficulty.go
to avoid breaking external code that depends on those exported
functions.
spendableOut and the functions related to it are is moved to package
testhelper and are exported.  This is done to make the code reusable
without introducing an import cycle when the testing code for
invalidateblock and reconsiderblock are added in follow up commits.
solveBlock is moved to testhelper and is exported.  This is done so that
the code can be reused without introducing import cycles.  The testing
code to be added in alter commits for invalidateblock and reconsider
block will use SolveBlock.
The variables are moved to testhelper so that they can be reused in the
blockchain package without introducing an import cycle.  The testing
code for invalidateblock and reconsiderblock that will be added in later
commits will be using these variables.
uniqueOpReturnScript is moved to testhelper and is exported so that the
code and be reused in package blockchain without introducing import
cycles.  The test code for invalidateblock and reconsiderblock that are
gonna be added in later commits uses the functions.
standardCoinbaseScript is moved to testhelper and is exported.  This
allows test code in package blockchain to reuse the code without
introducing an import cycle.  This code is used in the testing code
for invalidateblock and reconsiderblock that's added in the later
commits.
createCoinbaseTx's code is refactored out and placed in testhelper
package and is exported so that callers in package blockchain can reuse
the code without introducing import cycles.  The test code for
invalidateblock and reconsiderblock that'll be added in later commits
make use of this code.
createSpendTx is moved to testhelper so that the function can be used
for callers in package blockchain without introducing import cycles.
The test code for invalidateblock and reconsiderblock that are going to
be added in later commits make use of this code.
The block generating functions here allow for a test to create mock
blocks.  This is useful for testing invalidateblock and reconsiderblock
methods on blockchain that will be added in later commits.
Copy link
Collaborator

@Crypt-iQ Crypt-iQ left a comment

Choose a reason for hiding this comment

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

changes look good to me, only thing is whether reconsiderblock should be implemented instead

allSpends = append(allSpends, newSpendableOuts...)

var nextSpendsTmp []*testhelper.SpendableOut
for i := 0; i < len(allSpends); i++ {
Copy link
Collaborator

Choose a reason for hiding this comment

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

instead of randomly grabbing, doesn't this grab all of the utxos from allSpends?

InvalidateBlock() invalidates a given block and marks all its
descendents as invalid as well. The active chain tip changes if the
invalidated block is part of the best chain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants