| 5605 | } |
| 5606 | |
| 5607 | util::Result<CBlockIndex*> ChainstateManager::ActivateSnapshot( |
| 5608 | AutoFile& coins_file, |
| 5609 | const SnapshotMetadata& metadata, |
| 5610 | bool in_memory) |
| 5611 | { |
| 5612 | uint256 base_blockhash = metadata.m_base_blockhash; |
| 5613 | |
| 5614 | CBlockIndex* snapshot_start_block{}; |
| 5615 | |
| 5616 | { |
| 5617 | LOCK(::cs_main); |
| 5618 | |
| 5619 | if (this->CurrentChainstate().m_from_snapshot_blockhash) { |
| 5620 | return util::Error{Untranslated("Can't activate a snapshot-based chainstate more than once")}; |
| 5621 | } |
| 5622 | if (!GetParams().AssumeutxoForBlockhash(base_blockhash).has_value()) { |
| 5623 | auto available_heights = GetParams().GetAvailableSnapshotHeights(); |
| 5624 | std::string heights_formatted = util::Join(available_heights, ", ", [&](const auto& i) { return util::ToString(i); }); |
| 5625 | return util::Error{Untranslated(strprintf("assumeutxo block hash in snapshot metadata not recognized (hash: %s). The following snapshot heights are available: %s", |
| 5626 | base_blockhash.ToString(), |
| 5627 | heights_formatted))}; |
| 5628 | } |
| 5629 | |
| 5630 | snapshot_start_block = m_blockman.LookupBlockIndex(base_blockhash); |
| 5631 | if (!snapshot_start_block) { |
| 5632 | return util::Error{Untranslated(strprintf("The base block header (%s) must appear in the headers chain. Make sure all headers are syncing, and call loadtxoutset again", |
| 5633 | base_blockhash.ToString()))}; |
| 5634 | } |
| 5635 | |
| 5636 | bool start_block_invalid = snapshot_start_block->nStatus & BLOCK_FAILED_VALID; |
| 5637 | if (start_block_invalid) { |
| 5638 | return util::Error{Untranslated(strprintf("The base block header (%s) is part of an invalid chain", base_blockhash.ToString()))}; |
| 5639 | } |
| 5640 | |
| 5641 | if (!m_best_header || m_best_header->GetAncestor(snapshot_start_block->nHeight) != snapshot_start_block) { |
| 5642 | return util::Error{Untranslated("A forked headers-chain with more work than the chain with the snapshot base block header exists. Please proceed to sync without AssumeUtxo.")}; |
| 5643 | } |
| 5644 | |
| 5645 | auto mempool{CurrentChainstate().GetMempool()}; |
| 5646 | if (mempool && mempool->size() > 0) { |
| 5647 | return util::Error{Untranslated("Can't activate a snapshot when mempool not empty")}; |
| 5648 | } |
| 5649 | } |
| 5650 | |
| 5651 | int64_t current_coinsdb_cache_size{0}; |
| 5652 | int64_t current_coinstip_cache_size{0}; |
| 5653 | |
| 5654 | // Cache percentages to allocate to each chainstate. |
| 5655 | // |
| 5656 | // These particular percentages don't matter so much since they will only be |
| 5657 | // relevant during snapshot activation; caches are rebalanced at the conclusion of |
| 5658 | // this function. We want to give (essentially) all available cache capacity to the |
| 5659 | // snapshot to aid the bulk load later in this function. |
| 5660 | static constexpr double IBD_CACHE_PERC = 0.01; |
| 5661 | static constexpr double SNAPSHOT_CACHE_PERC = 0.99; |
| 5662 | |
| 5663 | { |
| 5664 | LOCK(::cs_main); |