* Scan the block chain (starting in start_block) for transactions * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. * * @param[in] start_block Scan starting block. If block is not on the active * chain, the scan will return SUCCESS immediately. * @param[in] start_height Height of start_block * @param[in] max_he
| 1621 | * transactions for. |
| 1622 | */ |
| 1623 | CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate) |
| 1624 | { |
| 1625 | int64_t nNow = GetTime(); |
| 1626 | int64_t start_time = GetTimeMillis(); |
| 1627 | |
| 1628 | assert(reserver.isReserved()); |
| 1629 | |
| 1630 | uint256 block_hash = start_block; |
| 1631 | ScanResult result; |
| 1632 | |
| 1633 | WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString()); |
| 1634 | |
| 1635 | fAbortRescan = false; |
| 1636 | ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption) |
| 1637 | uint256 tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash()); |
| 1638 | uint256 end_hash = tip_hash; |
| 1639 | if (max_height) chain().findAncestorByHeight(tip_hash, *max_height, FoundBlock().hash(end_hash)); |
| 1640 | double progress_begin = chain().guessVerificationProgress(block_hash); |
| 1641 | double progress_end = chain().guessVerificationProgress(end_hash); |
| 1642 | double progress_current = progress_begin; |
| 1643 | int block_height = start_height; |
| 1644 | while (!fAbortRescan && !chain().shutdownRequested()) { |
| 1645 | if (progress_end - progress_begin > 0.0) { |
| 1646 | m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin); |
| 1647 | } else { // avoid divide-by-zero for single block scan range (i.e. start and stop hashes are equal) |
| 1648 | m_scanning_progress = 0; |
| 1649 | } |
| 1650 | if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) { |
| 1651 | ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100)))); |
| 1652 | } |
| 1653 | if (GetTime() >= nNow + 60) { |
| 1654 | nNow = GetTime(); |
| 1655 | WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current); |
| 1656 | } |
| 1657 | |
| 1658 | // Read block data |
| 1659 | CBlock block; |
| 1660 | chain().findBlock(block_hash, FoundBlock().data(block)); |
| 1661 | |
| 1662 | // Find next block separately from reading data above, because reading |
| 1663 | // is slow and there might be a reorg while it is read. |
| 1664 | bool block_still_active = false; |
| 1665 | bool next_block = false; |
| 1666 | uint256 next_block_hash; |
| 1667 | chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash))); |
| 1668 | |
| 1669 | if (!block.IsNull()) { |
| 1670 | LOCK(cs_wallet); |
| 1671 | if (!block_still_active) { |
| 1672 | // Abort scan if current block is no longer active, to prevent |
| 1673 | // marking transactions as coming from the wrong block. |
| 1674 | result.last_failed_block = block_hash; |
| 1675 | result.status = ScanResult::FAILURE; |
| 1676 | break; |
| 1677 | } |
| 1678 | for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) { |
| 1679 | SyncTransaction(block.vtx[posInBlock], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true); |
| 1680 | } |