From 391a4f968a6709db5d7fc11f8e9b14e2604a5eed Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Thu, 13 Jul 2023 04:00:42 -0400 Subject: [PATCH] refactor: if we have a _latestOptimisticUpdate, check the estimated current block against the block we have, and return it as cached data if we don't need to fetch again. Also use a mutex to prevent race conditions --- src/baseClient.ts | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/baseClient.ts b/src/baseClient.ts index 395f171..208ae5f 100644 --- a/src/baseClient.ts +++ b/src/baseClient.ts @@ -13,7 +13,11 @@ import { getDefaultClientConfig, optimisticUpdateVerify, } from "#util.js"; -import { LightClientUpdate, OptimisticUpdateCallback } from "#types.js"; +import { + LightClientUpdate, + OptimisticUpdate, + OptimisticUpdateCallback, +} from "#types.js"; import { assertValidLightClientUpdate } from "@lodestar/light-client/validation"; import * as capella from "@lodestar/types/capella"; @@ -35,6 +39,7 @@ export default abstract class BaseClient { protected options: BaseClientOptions; private genesisTime = this.config.genesis.time; private syncMutex = new Mutex(); + private optimisticMutex = new Mutex(); constructor(options: BaseClientOptions) { this.options = options; @@ -168,14 +173,39 @@ export default abstract class BaseClient { protected async getLatestExecution(): Promise { await this._sync(); + + const getExecInfo = (u: OptimisticUpdate) => { + return { + blockHash: toHexString(u.attestedHeader.execution.blockHash), + blockNumber: u.attestedHeader.execution.blockNumber, + }; + }; + + if (this._latestOptimisticUpdate) { + const update = capella.ssz.LightClientOptimisticUpdate.deserialize( + this._latestOptimisticUpdate, + ); + const diffInSeconds = Date.now() / 1000 - this.genesisTime; + const currentSlot = Math.floor( + diffInSeconds / this.config.chainConfig.SECONDS_PER_SLOT, + ); + if (currentSlot <= update.attestedHeader.beacon.slot) { + this.optimisticMutex.release(); + return getExecInfo(update); + } + } + + await this.optimisticMutex.acquire(); const update = await this.options.optimisticUpdateCallback(); const verify = await optimisticUpdateVerify( this.latestCommittee as Uint8Array[], update, ); + // TODO: check the update against the latest sync committee if (!verify.correct) { + this.optimisticMutex.release(); console.error(`Invalid Optimistic Update: ${verify.reason}`); return null; } @@ -187,10 +217,9 @@ export default abstract class BaseClient { `Optimistic update verified for slot ${update.attestedHeader.beacon.slot}`, ); - return { - blockHash: toHexString(update.attestedHeader.execution.blockHash), - blockNumber: update.attestedHeader.execution.blockNumber, - }; + this.optimisticMutex.release(); + + return getExecInfo(update); } protected async syncUpdateVerifyGetCommittee(