AICH-recover parts found corrupt during the final completion re-hash - #270
Merged
got3nks merged 2 commits intoJul 2, 2026
Merged
Conversation
…le-project#225) When a completed file is re-hashed and a part fails, PartFileHashFinished re-opens the whole 9.28 MB part (AddGap) but, unlike the mid-download hash path, never requests AICH recovery. So a part that passes its per-part hash during download yet is corrupted afterwards — as happens when endgame source rotation (OP_CANCELTRANSFER) splices a 180 KB block across two sources — is fully re-downloaded even when a trusted AICH hashset could recover just the bad 180 KB blocks. Collect the parts that fail the final re-hash and, once the file is back in PS_READY, call RequestAICHRecovery() for each. It is a no-op unless the file has a trusted/verified AICH master hash, so non-AICH files keep the existing whole-part re-download; files that reached AICH_TRUSTED now recover at block granularity and let the CorruptionBlackBox pinpoint the offending block.
) Also flag parts that fail the final completion re-hash in m_corrupted_list, mirroring the mid-download corruption path. The AICH block recovery added in the previous commit doesn't consult this list, but it primes the ICH fallback when no trusted AICH hashset is available, and — since m_corrupted_list is saved to the .met — it keeps the corrupt state across a restart that happens before recovery finishes.
Cflsft
pushed a commit
to Cflsft/amule
that referenced
this pull request
Jul 6, 2026
… re-hash (amule-org#270) When the final full-file re-hash finds a part corrupt (e.g. a block rewritten after the part completed, as with endgame source-rotation block splicing, amule-org#225), PartFileHashFinished only re-gapped the whole 9.28 MB part and never requested AICH recovery. Collect the failing parts and call RequestAICHRecovery() for each once the file is back in PS_READY. It is self-guarded (no-op without a trusted/verified AICH hashset), so non-AICH files keep the existing whole-part re-download; AICH files now recover at 180 KB block granularity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a completed file is re-hashed and a part fails,
PartFileHashFinishedre-opens the whole 9.28 MB part (AddGap) but — unlike the mid-download hash path — never requests AICH recovery. So a part that passed its per-part hash during download but was corrupted afterwards is fully re-downloaded, even when a trusted AICH hashset could recover just the bad 180 KB blocks.This is what surfaces with endgame source rotation (#225): when a faster source evicts a slower one mid-block (
OP_CANCELTRANSFER), the block ends up spliced across two sources and can fail the final full-file hash. In testing there, a 4.5 GB file atAICH_TRUSTED(10 sources) had 8 parts fail and re-downloaded them whole, because the completion path never asked AICH to narrow it down — the AICH quorum was reached but unused on this path.Fix
Collect the parts that fail the final re-hash and, once the file is back in
PS_READY, callRequestAICHRecovery()for each.RequestAICHRecovery()is self-guarded: it returns immediately unless the file has a valid trusted/verified AICH master hash and a source that can serve the recovery data. So theAddGap()whole-part re-open (unchanged and unconditional) is always the fallback, and this only adds an optional narrowing on top:AICH_TRUSTED/AICH_VERIFIEDnow recover at 180 KB block granularity, re-downloading only the corrupt blocks, and theCorruptionBlackBoxcan pinpoint the offending block.Testing
Debug build clean. The recovery path is best exercised live; this unblocks testing whether AICH recovers endgame split-block corruption on #225 (the motivating scenario), where it previously couldn't because the completion path never requested it.