diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp index 15805ca..dbb2c41 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -49,6 +49,15 @@ uint256 hashGenesisMerkleRoot("0x1a45b4482532abb29b10e234d3f13132230525a339ecea9 | |||
| 49 | CBlockIndex* pindexGenesisBlock = NULL; | 49 | CBlockIndex* pindexGenesisBlock = NULL; |
| 50 | int nBestHeight = -1; | 50 | int nBestHeight = -1; |
| 51 | uint256 hashBestChain = 0; | 51 | uint256 hashBestChain = 0; |
| 52 | // Blocks at the tip to re-verify on startup. 0 means the whole chain. 288 is | ||
| 53 | // about ten hours at a two-minute target -- far enough back to catch a bad tip, | ||
| 54 | // short enough that startup does not pay a RandomX hash per block for the whole | ||
| 55 | // history. /checkblocks=N overrides it. | ||
| 56 | int nCheckBlocksOnLoad = 288; | ||
| 57 | // Set by CTxDB::LoadBlockIndex when the tail of the chain fails verification. | ||
| 58 | // The repair runs in LoadBlockIndex() below, once that read-only handle and its | ||
| 59 | // cursor are closed. | ||
| 60 | CBlockIndex* pindexBadChainFork = NULL; | ||
| 52 | CBlockIndex* pindexBest = NULL; | 61 | CBlockIndex* pindexBest = NULL; |
| 53 | 62 | ||
| 54 | map<uint256, CBlock*> mapOrphanBlocks; | 63 | map<uint256, CBlock*> mapOrphanBlocks; |
| @@ -1577,6 +1586,72 @@ bool LoadBlockIndex(bool fAllowNew) | |||
| 1577 | return false; | 1586 | return false; |
| 1578 | txdb.Close(); | 1587 | txdb.Close(); |
| 1579 | 1588 | ||
| 1589 | // Repair a bad tip found during verification. | ||
| 1590 | // | ||
| 1591 | // This has to happen after the handle above is closed. CTxDB::LoadBlockIndex | ||
| 1592 | // walks the index with a cursor it never closes, so it is still holding read | ||
| 1593 | // locks -- a write transaction opened alongside it waits on them forever. | ||
| 1594 | // Measured, not guessed: the node came up, printed the diagnosis, and hung | ||
| 1595 | // there with nothing in any log. | ||
| 1596 | if (pindexBadChainFork) | ||
| 1597 | { | ||
| 1598 | CBlockIndex* pindexFork = pindexBadChainFork; | ||
| 1599 | pindexBadChainFork = NULL; | ||
| 1600 | |||
| 1601 | printf("LoadBlockIndex() : *** moving best chain back to height %d, discarding %d block(s)\n", | ||
| 1602 | pindexFork->nHeight, nBestHeight - pindexFork->nHeight); | ||
| 1603 | |||
| 1604 | vector<CBlockIndex*> vDisconnect; | ||
| 1605 | for (CBlockIndex* pindex = pindexBest; pindex && pindex != pindexFork; pindex = pindex->pprev) | ||
| 1606 | vDisconnect.push_back(pindex); | ||
| 1607 | |||
| 1608 | bool fRolledBack = false; | ||
| 1609 | try | ||
| 1610 | { | ||
| 1611 | CTxDB txdbWrite; | ||
| 1612 | txdbWrite.TxnBegin(); | ||
| 1613 | foreach(CBlockIndex* pindex, vDisconnect) | ||
| 1614 | { | ||
| 1615 | CBlock block; | ||
| 1616 | if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true)) | ||
| 1617 | throw runtime_error("ReadFromDisk for disconnect failed"); | ||
| 1618 | if (!block.DisconnectBlock(txdbWrite, pindex)) | ||
| 1619 | throw runtime_error("DisconnectBlock failed"); | ||
| 1620 | } | ||
| 1621 | if (!txdbWrite.WriteHashBestChain(pindexFork->GetBlockHash())) | ||
| 1622 | throw runtime_error("WriteHashBestChain failed"); | ||
| 1623 | txdbWrite.TxnCommit(); | ||
| 1624 | txdbWrite.Close(); | ||
| 1625 | fRolledBack = true; | ||
| 1626 | } | ||
| 1627 | catch (const std::exception& e) | ||
| 1628 | { | ||
| 1629 | printf("LoadBlockIndex() : rollback failed: %s\n", e.what()); | ||
| 1630 | } | ||
| 1631 | catch (...) | ||
| 1632 | { | ||
| 1633 | printf("LoadBlockIndex() : rollback failed\n"); | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | if (fRolledBack) | ||
| 1637 | { | ||
| 1638 | foreach(CBlockIndex* pindex, vDisconnect) | ||
| 1639 | if (pindex->pprev) | ||
| 1640 | pindex->pprev->pnext = NULL; | ||
| 1641 | |||
| 1642 | pindexBest = pindexFork; | ||
| 1643 | hashBestChain = pindexBest->GetBlockHash(); | ||
| 1644 | nBestHeight = pindexBest->nHeight; | ||
| 1645 | printf("LoadBlockIndex() : now at height %d, will re-download from peers\n", nBestHeight); | ||
| 1646 | } | ||
| 1647 | else | ||
| 1648 | { | ||
| 1649 | // Start anyway. The operator needs a running node to read this from. | ||
| 1650 | printf("LoadBlockIndex() : *** still on the bad chain at height %d -- back up the data directory and report this\n", | ||
| 1651 | nBestHeight); | ||
| 1652 | } | ||
| 1653 | } | ||
| 1654 | |||
| 1580 | // | 1655 | // |
| 1581 | // Init with genesis block | 1656 | // Init with genesis block |
| 1582 | // | 1657 | // |