Skip to content

Commit 3db0cc3

Browse files
committed
Merge #15402: Granular invalidateblock and RewindBlockIndex
519b0bc Make last disconnected block BLOCK_FAILED_VALID, even when aborted (Pieter Wuille) 8d22041 Optimization: don't add txn back to mempool after 10 invalidates (Pieter Wuille) 9ce9c37 Prevent callback overruns in InvalidateBlock and RewindBlockIndex (Pieter Wuille) 9bb32eb Release cs_main during InvalidateBlock iterations (Pieter Wuille) 9b1ff5c Call InvalidateBlock without cs_main held (Pieter Wuille) 241b2c7 Make RewindBlockIndex interruptible (Pieter Wuille) 880ce7d Call RewindBlockIndex without cs_main held (Pieter Wuille) 436f7d7 Release cs_main during RewindBlockIndex operation (Pieter Wuille) 1d34287 Merge the disconnection and erasing loops in RewindBlockIndex (Pieter Wuille) 32b2696 Move erasure of non-active blocks to a separate loop in RewindBlockIndex (Pieter Wuille) 9d6dcc5 Abstract EraseBlockData out of RewindBlockIndex (Pieter Wuille) Pull request description: This PR makes a number of improvements to the InvalidateBlock (`invalidateblock` RPC) and RewindBlockIndex functions, primarily around breaking up their long-term cs_main holding. In addition: * They're made safely interruptible (`bitcoind` can be shutdown, and no progress in either will be lost, though if incomplete, `invalidateblock` won't continue after restart and will need to be called again) * The validation queue is prevented from overflowing (meaning `invalidateblock` on a very old block will not drive bitcoind OOM) (see #14289). * `invalidateblock` won't bother to move transactions back into the mempool after 10 blocks (optimization). This is not an optimal solution, as we're relying on the scheduler call sites to make sure the scheduler doesn't overflow. Ideally, the scheduler would guarantee this directly, but that needs a few further changes (moving the signal emissions out of cs_main) to prevent deadlocks. I have manually tested the `invalidateblock` changes (including interrupting, and running with -checkblockindex and -checkmempool), but haven't tried the rewinding (which is probably becoming increasingly unnecessary, as very few pre-0.13.1 nodes remain that would care to upgrade). Tree-SHA512: 692e42758bd3d3efc2eb701984a8cb5db25fbeee32e7575df0183a00d0c2c30fdf72ce64c7625c32ad8c8bdc56313da72a7471658faeb0d39eefe39c4b8b8474
2 parents 726d066 + 519b0bc commit 3db0cc3

File tree

4 files changed

+211
-137
lines changed

4 files changed

+211
-137
lines changed

src/init.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,11 +1468,11 @@ bool AppInitMain(InitInterfaces& interfaces)
14681468

14691469
uiInterface.InitMessage(_("Loading block index..."));
14701470

1471-
LOCK(cs_main);
1472-
14731471
do {
14741472
const int64_t load_block_index_start_time = GetTimeMillis();
1473+
bool is_coinsview_empty;
14751474
try {
1475+
LOCK(cs_main);
14761476
UnloadBlockIndex();
14771477
pcoinsTip.reset();
14781478
pcoinsdbview.reset();
@@ -1544,7 +1544,7 @@ bool AppInitMain(InitInterfaces& interfaces)
15441544
// The on-disk coinsdb is now in a good state, create the cache
15451545
pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
15461546

1547-
bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
1547+
is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
15481548
if (!is_coinsview_empty) {
15491549
// LoadChainTip sets chainActive based on pcoinsTip's best block
15501550
if (!LoadChainTip(chainparams)) {
@@ -1553,18 +1553,25 @@ bool AppInitMain(InitInterfaces& interfaces)
15531553
}
15541554
assert(chainActive.Tip() != nullptr);
15551555
}
1556+
} catch (const std::exception& e) {
1557+
LogPrintf("%s\n", e.what());
1558+
strLoadError = _("Error opening block database");
1559+
break;
1560+
}
15561561

1557-
if (!fReset) {
1558-
// Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
1559-
// It both disconnects blocks based on chainActive, and drops block data in
1560-
// mapBlockIndex based on lack of available witness data.
1561-
uiInterface.InitMessage(_("Rewinding blocks..."));
1562-
if (!RewindBlockIndex(chainparams)) {
1563-
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
1564-
break;
1565-
}
1562+
if (!fReset) {
1563+
// Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
1564+
// It both disconnects blocks based on chainActive, and drops block data in
1565+
// mapBlockIndex based on lack of available witness data.
1566+
uiInterface.InitMessage(_("Rewinding blocks..."));
1567+
if (!RewindBlockIndex(chainparams)) {
1568+
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
1569+
break;
15661570
}
1571+
}
15671572

1573+
try {
1574+
LOCK(cs_main);
15681575
if (!is_coinsview_empty) {
15691576
uiInterface.InitMessage(_("Verifying blocks..."));
15701577
if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {

src/rpc/blockchain.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,15 +1579,15 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
15791579
uint256 hash(ParseHashV(request.params[0], "blockhash"));
15801580
CValidationState state;
15811581

1582+
CBlockIndex* pblockindex;
15821583
{
15831584
LOCK(cs_main);
1584-
CBlockIndex* pblockindex = LookupBlockIndex(hash);
1585+
pblockindex = LookupBlockIndex(hash);
15851586
if (!pblockindex) {
15861587
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
15871588
}
1588-
1589-
InvalidateBlock(state, Params(), pblockindex);
15901589
}
1590+
InvalidateBlock(state, Params(), pblockindex);
15911591

15921592
if (state.IsValid()) {
15931593
ActivateBestChain(state, Params());

0 commit comments

Comments
 (0)