Wait on the ripening schedule, not a clock, so an exit lands as one UTXO - #192
Closed
CypherBoxLLC wants to merge 1 commit into
Closed
CypherBoxLLC wants to merge 1 commit into
CypherBoxLLC wants to merge 1 commit into
Conversation
…s as one UTXO drainExits sweeps every claimable capsule into ONE transaction, so a whole exit can arrive as a single UTXO. It did not: the last mainnet exit delivered 2,961 sats as five separate UTXOs. Batching held on a 6-hour wall-clock ceiling. The three capsules still in flight on that exit reported claimableHeight 963101, 963142 and 963145, a 44-block spread of about 7.3 hours, so the window expired roughly 80 minutes BEFORE the last one ripened, with one of three claimable. The sweep fired early and split the exit in two. No ceiling tuned in hours fixes this in general: block intervals are stochastic and the spread is a property of when each branch confirmed. The schedule is knowable in advance. AwaitingDelta carries the exact block each straggler becomes claimable at, fixed from the moment its leaf confirmed. So hold until the tip reaches the last of them. That wait provably terminates, because the heights do not move and the chain only goes forward. The wall-clock backstop stays for the case it is good for: a straggler with no known ripening height, still broadcasting, or an unreadable chain tip. There is no schedule to wait on there and something has to bound it. The wait also stops if the tip passes every scheduled height and the stragglers still are not claimable, which means wedged rather than slow. The decision now also reports blocks remaining, so the wait can be shown as "2 blocks to go" rather than a seconds countdown that stalls and jumps. 21 unit tests over the measured heights. Mutation-checked: restoring the blind ceiling fails 3, taking min instead of max fails 2, waiting on a partial schedule fails 1, holding forever past the schedule fails 1.
Owner
Author
|
Landed in This PR did not auto-close because its base was another feature branch rather than Closing as merged. |
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.
Stacked on #181.
One exit should arrive as one UTXO. It does not.
drainExitssweeps every claimable capsule into a single transaction, so the whole exit can land as one UTXO at the destination. The last mainnet exit delivered 2,961 sats as five separate UTXOs.#181 fixed the obvious half of that by holding the sweep instead of claiming the moment the first capsule ripens. The ceiling it holds against is wall-clock, and that is where it still breaks.
The three capsules still in flight on that exit reported:
44 blocks, about 7.3 hours. Against
EXIT_CLAIM_BATCH_MAX_WAIT_MS = 6h:So it fires
window-expired, sweeps one capsule, and the exit splits into two UTXOs. No ceiling tuned in hours fixes this in general: block intervals are stochastic, and the spread is a property of when each branch happened to confirm, not of how long anyone waited.Blocks are the truth, time is the estimate
ExitState.AwaitingDelta.inner.claimableHeightis populated the moment a leaf confirms, and it does not move. The full schedule is known long before it matters, so "has everything ripened" is a question about the chain tip, not about elapsed time.decideExitClaimBatchnow holds until the tip reaches the last knownclaimableHeight. That wait provably terminates: the heights are fixed and the chain only goes forward.The wall-clock backstop stays for the case it is actually good for, and only that case:
Processing, no leaf confirmed yet)A partial schedule does not count. Knowing two heights of three proves nothing about the third, so that falls back to the clock too.
The decision also returns
blocksUntilAllReady, which feeds an honest "2 blocks to go" rather than a seconds countdown that visibly stalls and jumps, per spec 7.2.Testing
21 unit tests, built on the three measured heights above. Mutation-checked:
mininstead ofmaxof the ripening heightsFull unit suite 37 suites / 272 tests.
tscunchanged at the 405 baseline.Relationship to #191
Independent, and they compound. #191 keeps capsules out of the exit set that would never have become claimable, so there are fewer stragglers to wait on and no dust exit that could hold the batch to its backstop. This one makes the remaining set arrive together.