Skip to content

fix(spv): align deposit sweep proof length with Bridge accumulated difficulty#3918

Open
lionakhnazarov wants to merge 10 commits intothreshold-network:mainfrom
lionakhnazarov:feat/spv-proof-adjustment
Open

fix(spv): align deposit sweep proof length with Bridge accumulated difficulty#3918
lionakhnazarov wants to merge 10 commits intothreshold-network:mainfrom
lionakhnazarov:feat/spv-proof-adjustment

Conversation

@lionakhnazarov
Copy link
Copy Markdown
Collaborator

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.

lionakhnazarov and others added 9 commits December 12, 2025 14:16
- 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.
Copy link
Copy Markdown
Member

@lrsaturnino lrsaturnino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one! Just a couple of nits...

requestedDiff = currentEpochDifficulty
case firstHeaderDiff.Cmp(previousEpochDifficulty) == 0:
requestedDiff = previousEpochDifficulty
default:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants