mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-30 19:46:17 +00:00
fix(ots): never persist the non-terminal Verifying sentinel on the note
verifyOts wrote otsVerification = Verifying before the suspending blockchain verifyState() call and only overwrote it with the real verdict afterwards. That verification runs inside LoadOts's cancellable LaunchedEffect, so a row scrolling off-screen cancels the coroutine at the network suspension point — the verdict write never happens and the note is left stuck at Verifying. cacheVerifyOts treats Verifying as terminal, so earliestOtsVerifiedTime then returns null and the confirmed-timestamp pill silently vanishes for the note's lifetime. The old VerificationStateCache had the same write but its LRU eventually evicted the stuck entry; anchoring the verdict on the long-lived note removed that recovery. Store only terminal verdicts (Verified / Error / NetworkError). A cancelled or in-flight verification leaves the field null and simply retries on the next read; the cost is at worst two concurrent first-time verifications, already benign. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014D5fenZbAhCbDiwv7Rtpvj
This commit is contained in:
+12
-6
@@ -49,22 +49,28 @@ fun Note.justOtsVerification(): VerificationState? = otsVerification
|
||||
suspend fun Note.cacheVerifyOts(resolver: OtsResolver): VerificationState {
|
||||
val event = event as? OtsEvent ?: return VerificationState.Error("Not an OTS event")
|
||||
return when (val current = otsVerification) {
|
||||
is VerificationState.Verifying -> current
|
||||
is VerificationState.Verified -> current
|
||||
is VerificationState.Error -> current
|
||||
is VerificationState.NetworkError ->
|
||||
if (current.time < TimeUtils.fiveMinutesAgo()) verifyOts(event, resolver) else current
|
||||
is VerificationState.Error -> current
|
||||
// null, or a leftover non-terminal state from an interrupted run: (re)verify.
|
||||
else -> verifyOts(event, resolver)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the attestation and stores ONLY the terminal verdict. We deliberately never persist a
|
||||
* `Verifying` sentinel: this runs inside a cancellable `LoadOts` LaunchedEffect, so if the coroutine
|
||||
* were cancelled at the network suspension point after writing `Verifying` but before the verdict,
|
||||
* that sentinel would stick on the (long-lived) note forever — there is no LRU eviction to recover
|
||||
* it, unlike the old VerificationStateCache — and the OTS pill would silently vanish. Leaving the
|
||||
* field untouched until a real verdict lands means a cancelled run simply retries on the next read;
|
||||
* the cost is at worst two concurrent first-time verifications, which is harmless.
|
||||
*/
|
||||
private suspend fun Note.verifyOts(
|
||||
event: OtsEvent,
|
||||
resolver: OtsResolver,
|
||||
): VerificationState {
|
||||
otsVerification = VerificationState.Verifying
|
||||
return event.verifyState(resolver).also { otsVerification = it }
|
||||
}
|
||||
): VerificationState = event.verifyState(resolver).also { otsVerification = it }
|
||||
|
||||
/**
|
||||
* The earliest blockchain-verified time (unix seconds) among this note's non-expired OTS
|
||||
|
||||
Reference in New Issue
Block a user