| 5771 | } |
| 5772 | |
| 5773 | util::Result<void> ChainstateManager::PopulateAndValidateSnapshot( |
| 5774 | Chainstate& snapshot_chainstate, |
| 5775 | AutoFile& coins_file, |
| 5776 | const SnapshotMetadata& metadata) |
| 5777 | { |
| 5778 | // It's okay to release cs_main before we're done using `coins_cache` because we know |
| 5779 | // that nothing else will be referencing the newly created snapshot_chainstate yet. |
| 5780 | CCoinsViewCache& coins_cache = *WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsTip()); |
| 5781 | |
| 5782 | uint256 base_blockhash = metadata.m_base_blockhash; |
| 5783 | |
| 5784 | CBlockIndex* snapshot_start_block = WITH_LOCK(::cs_main, return m_blockman.LookupBlockIndex(base_blockhash)); |
| 5785 | |
| 5786 | if (!snapshot_start_block) { |
| 5787 | // Needed for ComputeUTXOStats to determine the |
| 5788 | // height and to avoid a crash when base_blockhash.IsNull() |
| 5789 | return util::Error{Untranslated(strprintf("Did not find snapshot start blockheader %s", |
| 5790 | base_blockhash.ToString()))}; |
| 5791 | } |
| 5792 | |
| 5793 | int base_height = snapshot_start_block->nHeight; |
| 5794 | const auto& maybe_au_data = GetParams().AssumeutxoForHeight(base_height); |
| 5795 | |
| 5796 | if (!maybe_au_data) { |
| 5797 | return util::Error{Untranslated(strprintf("Assumeutxo height in snapshot metadata not recognized " |
| 5798 | "(%d) - refusing to load snapshot", base_height))}; |
| 5799 | } |
| 5800 | |
| 5801 | const AssumeutxoData& au_data = *maybe_au_data; |
| 5802 | |
| 5803 | // This work comparison is a duplicate check with the one performed later in |
| 5804 | // ActivateSnapshot(), but is done so that we avoid doing the long work of staging |
| 5805 | // a snapshot that isn't actually usable. |
| 5806 | if (WITH_LOCK(::cs_main, return !CBlockIndexWorkComparator()(ActiveTip(), snapshot_start_block))) { |
| 5807 | return util::Error{Untranslated("Work does not exceed active chainstate")}; |
| 5808 | } |
| 5809 | |
| 5810 | const uint64_t coins_count = metadata.m_coins_count; |
| 5811 | uint64_t coins_left = metadata.m_coins_count; |
| 5812 | |
| 5813 | LogInfo("[snapshot] loading %d coins from snapshot %s", coins_left, base_blockhash.ToString()); |
| 5814 | int64_t coins_processed{0}; |
| 5815 | |
| 5816 | while (coins_left > 0) { |
| 5817 | try { |
| 5818 | Txid txid; |
| 5819 | coins_file >> txid; |
| 5820 | size_t coins_per_txid{0}; |
| 5821 | coins_per_txid = ReadCompactSize(coins_file); |
| 5822 | |
| 5823 | if (coins_per_txid > coins_left) { |
| 5824 | return util::Error{Untranslated("Mismatch in coins count in snapshot metadata and actual snapshot data")}; |
| 5825 | } |
| 5826 | |
| 5827 | for (size_t i = 0; i < coins_per_txid; i++) { |
| 5828 | COutPoint outpoint; |
| 5829 | Coin coin; |
| 5830 | outpoint.n = static_cast<uint32_t>(ReadCompactSize(coins_file)); |
no test coverage detected