From 5df8948886d640691a52184bf16d63ca09582e93 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Wed, 19 Oct 2022 22:02:17 -0700 Subject: [PATCH] add assertion on trustedPromise !== null --- src/client/webapp/auto-verifier.ts | 193 ++++++++++++++--------------- 1 file changed, 93 insertions(+), 100 deletions(-) diff --git a/src/client/webapp/auto-verifier.ts b/src/client/webapp/auto-verifier.ts index e18c905..b7b9e54 100644 --- a/src/client/webapp/auto-verifier.ts +++ b/src/client/webapp/auto-verifier.ts @@ -6,6 +6,7 @@ const LOG = Logger.create(__filename, electronConsole); import { Changes, WithEquals } from './data-types'; import * as uuid from 'uuid'; +import assert from 'assert'; export enum AutoVerifierChangesType { NONE, // both primaryFunc and trustedFunc returned null @@ -217,40 +218,23 @@ export class AutoVerifier { } const tryResolveTrustedPromise = async () => { - if (this.trustedPromise) { - // there is a trusted promise that we can check + assert(this.trustedPromise !== null) - if (this.trustedStatus === 'fetching') { - // no one has started verifying the trusted yet + if (this.trustedStatus === 'fetching') { + // no one has started verifying the trusted yet - this.trustedStatus = 'verifying'; + this.trustedStatus = 'verifying'; - // note: Promises that have already resolved will return the same value when awaited again :) - const origTrustedPromise: Promise | null = this.trustedPromise; - let trustedResult = undefined; - try { - trustedResult = await origTrustedPromise; - } catch (e: unknown) { - if (this.trustedPromise === origTrustedPromise) { - throw e; - } else { - console.warn('trusted promise rejected after unverify', e); - if (this.trustedPromise === null) { - this.trustedStatus = 'fetching'; - this.trustedPromise = this.trustedFunc(); - } - await tryResolveTrustedPromise(); - return; - } - } - - if (this.trustedPromise !== origTrustedPromise) { - // we've been invalidated while we were waiting for the trusted result! - // TODO: This happens when a socket fetch is sent before the socket is connected to. - console.warn( - 'RARE ALERT: we got unverified while trying to fetch a trusted promise for verification!', - new Error(), - ); + // note: Promises that have already resolved will return the same value when awaited again :) + const origTrustedPromise: Promise = this.trustedPromise; + let trustedResult = undefined; + try { + trustedResult = await origTrustedPromise; + } catch (e: unknown) { + if (this.trustedPromise === origTrustedPromise) { + throw e; + } else { + console.warn('trusted promise rejected after unverify', e); if (this.trustedPromise === null) { this.trustedStatus = 'fetching'; this.trustedPromise = this.trustedFunc(); @@ -258,87 +242,96 @@ export class AutoVerifier { await tryResolveTrustedPromise(); return; } + } - // make sure to verify BEFORE potentially resolving - // this way the conflicts can be resolved before the result is returned - this.verifyPromise = this.verifyFunc(primaryResult, trustedResult); - const primaryUpToDate = await this.verifyPromise; - - if (this.trustedPromise === origTrustedPromise) { - if (trustedResult !== null && primaryUpToDate) { - // we got a good trusted result and the primary data has been updated - // to reflect the trusted data (or already reflects it). - this.trustedStatus = 'verified'; - } else { - // we have to re-fetch the trusted promise again next fetch - this.trustedStatus = 'none'; - } - } else { - // this actually could be quite common - //console.warn('RARE ALERT: we got unverified during verification!'); - // ** complexity: - // if primaryUpToDate is false or we got unverified during verification, this path will still return - // the trustedResult that was passed to the verify function + if (this.trustedPromise !== origTrustedPromise) { + // we've been invalidated while we were waiting for the trusted result! + // TODO: This happens when a socket fetch is sent before the socket is connected to. + console.warn( + 'RARE ALERT: we got unverified while trying to fetch a trusted promise for verification!', + new Error(), + ); + if (this.trustedPromise === null) { + this.trustedStatus = 'fetching'; + this.trustedPromise = this.trustedFunc(); } + await tryResolveTrustedPromise(); + return; + } - if (!resolved) { - // removed 01/09/2021 pretty sure should not be here... && trustedResult - resolve(trustedResult); - resolved = true; + // make sure to verify BEFORE potentially resolving + // this way the conflicts can be resolved before the result is returned + this.verifyPromise = this.verifyFunc(primaryResult, trustedResult); + const primaryUpToDate = await this.verifyPromise; + + if (this.trustedPromise === origTrustedPromise) { + if (trustedResult !== null && primaryUpToDate) { + // we got a good trusted result and the primary data has been updated + // to reflect the trusted data (or already reflects it). + this.trustedStatus = 'verified'; + } else { + // we have to re-fetch the trusted promise again next fetch + this.trustedStatus = 'none'; } } else { - // some code is already dealing with (or dealt with) verifying the trusted result - // await the same trusted promise and return its result if we didn't get a result - // from the primary source. + // this actually could be quite common + //console.warn('RARE ALERT: we got unverified during verification!'); + // ** complexity: + // if primaryUpToDate is false or we got unverified during verification, this path will still return + // the trustedResult that was passed to the verify function + } - // note: Promises that have already resolved will return the same value when awaited again :) - const origTrustedPromise: Promise | null = this.trustedPromise; - let trustedResult = undefined; - try { - trustedResult = await origTrustedPromise; - } catch (e: unknown) { - if (this.trustedPromise === origTrustedPromise) { - // TODO: decide if can unverify here rather than in the "catch-all" - // maybe this will let us get rid of the catch all? - throw e; - } else { - console.warn('trusted promise from another path rejected after unverify', e); - // TODO: only retry if there is another trusted promise available... - // OR always reject? - await tryResolveTrustedPromise(); - return; - } - } + if (!resolved) { + // removed 01/09/2021 pretty sure should not be here... && trustedResult + resolve(trustedResult); + resolved = true; + } + } else { + // some code is already dealing with (or dealt with) verifying the trusted result + // await the same trusted promise and return its result if we didn't get a result + // from the primary source. - if (this.trustedPromise !== origTrustedPromise) { - // we've been invalidated while we were waiting for the trusted result! - console.warn( - 'ULTRA RARE ALERT: we got unverified while awaiting a trusted promise another path was verifying!', - ); + // note: Promises that have already resolved will return the same value when awaited again :) + const origTrustedPromise: Promise | null = this.trustedPromise; + let trustedResult = undefined; + try { + trustedResult = await origTrustedPromise; + } catch (e: unknown) { + if (this.trustedPromise === origTrustedPromise) { + // TODO: decide if can unverify here rather than in the "catch-all" + // maybe this will let us get rid of the catch all? + throw e; + } else { + console.warn('trusted promise from another path rejected after unverify', e); + // TODO: only retry if there is another trusted promise available... + // OR always reject? await tryResolveTrustedPromise(); return; } - - await this.verifyPromise; // we don't care about the result, just that we wait for the verification to finish - if (this.trustedPromise !== origTrustedPromise) { - // we've been invalidated while we were waiting for the verify! - console.warn( - 'ULTRA RARE ALERT: we got unverified while awaiting a verify promise another path was calling!', - ); - // ** complexity: - // if primaryUpToDate is false or we got unverified during verification, this path will still return - // the trustedResult that was passed to the verify function - } - - if (!resolved) { - resolve(trustedResult); - resolved = true; - } } - } else { - // we are all up to date, make sure to resolve if primaryResult is null + + if (this.trustedPromise !== origTrustedPromise) { + // we've been invalidated while we were waiting for the trusted result! + console.warn( + 'ULTRA RARE ALERT: we got unverified while awaiting a trusted promise another path was verifying!', + ); + await tryResolveTrustedPromise(); + return; + } + + await this.verifyPromise; // we don't care about the result, just that we wait for the verification to finish + if (this.trustedPromise !== origTrustedPromise) { + // we've been invalidated while we were waiting for the verify! + console.warn( + 'ULTRA RARE ALERT: we got unverified while awaiting a verify promise another path was calling!', + ); + // ** complexity: + // if primaryUpToDate is false or we got unverified during verification, this path will still return + // the trustedResult that was passed to the verify function + } + if (!resolved) { - resolve(null); + resolve(trustedResult); resolved = true; } }