bitcoin / bitcoin

Bitcoin Core integration/staging tree
https://bitcoincore.org/en/download
MIT License
79.9k stars 36.48k forks source link

Assertion failure in validation.cpp:4203 (re: pindexFirstNeverProcessed) #11782

Closed ajtowns closed 4 years ago

ajtowns commented 7 years ago

Reported by @rustyrussell on irc:

<rusty> Latest master branch, bitcoind in regtest mode:
bitcoind: validation.cpp:4203: void CheckBlockIndex(const Consensus::Params&): Assertion `(pindexFirstNeverProcessed != nullptr) == (pindex->nChainTx == 0)' failed.
<rusty> Pretty sure that was a .bitcoind dir from an older bitcoind.

I can reproduce this error with the following simple test case:

class RustyAssertTest(BitcoinTestFramework):
    def set_test_params(self):
        self.num_nodes = 1
        self.setup_clean_chain = True

    def run_test(self):
        self.log.info("initialise chain by activating segwit")
        self.restart_node(0, ["-vbparams=segwit:0:999999999999"])
        self.nodes[0].generate(500)
        assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'active')

        self.log.info("restart with segwit always active")
        self.restart_node(0)

or by hand by running:

$ rm -rf ~/.bitcoin/regtest
$ ./bitcoind -regtest -vbparams=segwit:0:999999999999 -daemon
$ ./bitcoin-cli -regtest generate 500
$ ./bitcoin-cli -regtest stop
$ ./bitcoind -regtest
bitcoind: validation.cpp:4213: void CheckBlockIndex(const Consensus::Params&): Assertion `(pindexFirstNeverProcessed != nullptr) == (pindex->nChainTx == 0)' failed.
Aborted

I believe what's happening is:

I don't think this bug can be hit on mainnet or testnet -- running an old client will either not recognise segwit at all and never store any witness data (so nChainTx won't be non-zero), or will see segwit started at the exact same block the current client does (so won't reduce the validation of any blocks). It also shouldn't impact most future bip 9 (or similar) deployments, as most of those presumably won't need to change the storage format.

So I think this might just warrant a cleaner error message rather than handling it properly. Perhaps RewindBlockIndex's test should change from:

if (IsWitnessEnabled(pprev) && !BLOCK_OPT_WITNESS && !chainActive) { ... }

to something like:

if (IsWitnessEnabled(pprev)) {
    if (!BLOCK_OPT_WITNESS && !chainActive) {
        ...
    } else if (BLOCK_OPT_WITNESS && pprev->nChainTx == 0) {
        LogPrintf("segwit activation height has changed, cannot reuse blockchain");
        return false;
    }
}
TheBlueMatt commented 7 years ago

Looks like the same issue as #11767

TheBlueMatt commented 7 years ago

The other option is to fix the bug ala https://github.com/TheBlueMatt/bitcoin/commit/3b0575bd40c76dcd323bb470a50533c354d1c60b though I agree its probably not worth fixing, people should just wipe their regtest chain instead.

maflcko commented 7 years ago

Why wipe? The commitments are not required, a reindex should do if you didn't violate consensus, no?

On Nov 28, 2017 18:44, "Matt Corallo" notifications@github.com wrote:

The other option is to fix the bug ala TheBlueMatt/bitcoin@3b0575b https://github.com/TheBlueMatt/bitcoin/commit/3b0575bd40c76dcd323bb470a50533c354d1c60b though I agree its probably not worth fixing, people should just wipe their regtest chain instead.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bitcoin/bitcoin/issues/11782#issuecomment-347702572, or mute the thread https://github.com/notifications/unsubscribe-auth/AGGmv6l54EQOnVII1nqQtqZiGkiCBPdMks5s7JrvgaJpZM4QtBse .

ajtowns commented 7 years ago

A reindex isn't sufficient to set BLOCK_OPT_WITNESS so bitcoind simply won't recognise the earlier blocks without redownloading them from a peer first:

$ rm -rf ~/.bitcoin/regtest
$ ./bitcoind -regtest -vbparams=segwit:0:999999999999 -daemon
$ ./bitcoin-cli -regtest generate 144
$ ./bitcoin-cli -regtest getblockchaininfo | grep -E 'blocks|headers'
  "blocks": 144,
  "headers": 144,
$ ./bitcoin-cli -regtest stop

$ ./bitcoind -regtest -daemon   # doesn't crash because segwit hadn't activated
$ ./bitcoin-cli -regtest getblockchaininfo | grep -E 'blocks|headers'
  "blocks": 0,
  "headers": 144,
$ ./bitcoin-cli -regtest stop

$ ./bitcoind -regtest -daemon -reindex
$ ./bitcoin-cli -regtest getblockchaininfo | grep -E 'blocks|headers'
  "blocks": 0,
  "headers": 144,
ajtowns commented 6 years ago

I had a go at making bitcoin give a more helpful error message in https://github.com/ajtowns/bitcoin/commits/rewindblockindex ; in particular https://github.com/ajtowns/bitcoin/commit/72e54daab692d000e3c282085f628fa5cd1ef927?diff=unified&w=1 . It seems to work, but I'm not sure if pprev can be relied upon to be valid at that point or if there's other things to be careful of though.

maflcko commented 4 years ago

The feature request didn't seem to attract much attention in the past. Also, the issue seems not important enough right now to keep it sitting around idle in the list of open issues.

Closing due to lack of interest. Pull requests with improvements are always welcome.