fix(spv): align deposit sweep proof length with Bridge accumulated difficulty#3918
fix(spv): align deposit sweep proof length with Bridge accumulated difficulty#3918lionakhnazarov wants to merge 14 commits into
Conversation
- Added function to create block headers with specified difficulty. - Introduced method in to add headers for a range of heights based on dynamic difficulty. - Updated tests in to utilize the new difficulty handling, ensuring accurate proof range calculations across epochs. - Enhanced function to compute required confirmations based on actual header difficulties instead of fixed assumptions.
lrsaturnino
left a comment
There was a problem hiding this comment.
Nice one! Just a couple of nits...
| requestedDiff = currentEpochDifficulty | ||
| case firstHeaderDiff.Cmp(previousEpochDifficulty) == 0: | ||
| requestedDiff = previousEpochDifficulty | ||
| default: |
There was a problem hiding this comment.
The default branch here silently returns false, which makes the caller log "proof goes outside the previous and current difficulty epochs" — but the real issue is the tx block was mined at min-difficulty.
On testnet4 this will cause silent retries with a misleading log. Could you add a logger.Warnf distinguishing this case? Something like "transaction block difficulty %s matches neither current (%s) nor previous (%s) epoch — may be unprovable if mined in a min-difficulty block."
There was a problem hiding this comment.
Missing a test for the scenario that motivated this whole PR — a tx block at min-difficulty where firstHeaderDiff matches neither epoch difficulty. Would be good to add a case with difficultyAtBlock(proofStartBlock) = big.NewInt(1) while epoch difficulties are much higher, expecting isProofWithinRelayRange=false.
Add the missing case for the scenario that motivated the PR: a min-difficulty block whose first-header difficulty matches neither the current nor the previous epoch difficulty. Bridge.evaluateProofDifficulty would revert "Not at current or previous difficulty", so getProofInfo must report the proof as out of range.
The default branch in getProofInfo silently returns false, after which the caller logs "proof goes outside the previous and current difficulty epochs". That message is misleading for the case where the first header's difficulty is simply unknown to the relay (e.g. a testnet4 min-difficulty block). Emit a dedicated Warnf so silent retries are diagnosable.
On chains with min-difficulty blocks (e.g. testnet4) the per-header difficulty walk can need many more blocks than txProofDifficultyFactor to accumulate enough work, issuing one GetBlockHeader RPC per iteration. Log a Warnf once the walk crosses a soft threshold so an operator can notice excessive header fetches per maintainer tick.
getProofInfo fetched the header at proofStartBlock once to resolve requestedDifficulty, then refetched the same header on the first iteration of the per-header difficulty walk. Seed the running sum and block count with firstHeader and start the loop at proofStartBlock + 1 to drop the duplicate RPC.
Updates the SPV maintainer’s getProofInfo logic so the number of Bitcoin headers in the SPV proof matches what Bridge.evaluateProofDifficulty requires: sum of per-header difficulty ≥ requestedDifficulty × txProofDifficultyFactor, with the first header matching relay current or previous epoch difficulty. Adds relay-window checks so the proof range stays in the previous epoch, current epoch, or spans previous→current only.
This fixes failures like Insufficient accumulated difficulty in header chain on chains where per-block work varies (e.g. testnet4 min-difficulty streaks), where a fixed block count × epoch-average math was wrong.
Changes
pkg/maintainer/spv/spv.go: implement proofRangeWithinRelayWindow; rewrite getProofInfo to walk headers from proof start, sum header.Difficulty(), resolve requestedDiff from first header vs relay difficulties.
pkg/maintainer/spv/spv_test.go + bitcoin_chain_test.go: populate mock headers with realistic Bits/difficulty; fix setCurrentAndPrevEpochDifficulty argument order; update expectations.
(if included) .github/workflows/contracts-ecdsa.yml: resolve accidental merge conflict markers in on: triggers.