@@ -63,7 +63,6 @@ import {
6363 NodeClientErrorV0 ,
6464 NodeClientErrorV1 ,
6565 NodeCommandServerKeysResponse ,
66- NodeErrorV3 ,
6766 RejectedNodePromises ,
6867 SendNodeCommand ,
6968 SessionSigsMap ,
@@ -113,6 +112,8 @@ export type LitNodeClientConfigWithDefaults = Required<
113112const EPOCH_PROPAGATION_DELAY = 45_000 ;
114113// This interval is responsible for keeping latest block hash up to date
115114const BLOCKHASH_SYNC_INTERVAL = 30_000 ;
115+ // When fetching the blockhash from a provider (not lit), we use a previous block to avoid a nodes not knowing about the new block yet
116+ const BLOCKHASH_COUNT_PROVIDER_DELAY = - 1 ;
116117
117118// Intentionally not including datil-dev here per discussion with Howard
118119const NETWORKS_REQUIRING_SEV : string [ ] = [
@@ -798,6 +799,8 @@ export class LitCore {
798799
799800 /**
800801 * Fetches the latest block hash and log any errors that are returned
802+ * Nodes will accept any blockhash in the last 30 days but use the latest 10 as challenges for webauthn
803+ * Note: last blockhash from providers might not be propagated to the nodes yet, so we need to use a slightly older one
801804 * @returns void
802805 */
803806 private async _syncBlockhash ( ) {
@@ -819,52 +822,68 @@ export class LitCore {
819822 this . latestBlockhash
820823 ) ;
821824
822- return fetch ( this . _blockHashUrl )
823- . then ( async ( resp : Response ) => {
824- const blockHashBody : EthBlockhashInfo = await resp . json ( ) ;
825- this . latestBlockhash = blockHashBody . blockhash ;
826- this . lastBlockHashRetrieved = Date . now ( ) ;
827- log ( 'Done syncing state new blockhash: ' , this . latestBlockhash ) ;
828-
829- // If the blockhash retrieval failed, throw an error to trigger fallback in catch block
830- if ( ! this . latestBlockhash ) {
831- throw new Error (
832- `Error getting latest blockhash. Received: "${ this . latestBlockhash } "`
833- ) ;
834- }
835- } )
836- . catch ( async ( err : BlockHashErrorResponse | Error ) => {
837- logError (
838- 'Error while attempting to fetch new latestBlockhash:' ,
839- err instanceof Error ? err . message : err . messages ,
840- 'Reason: ' ,
841- err instanceof Error ? err : err . reason
842- ) ;
825+ try {
826+ // This fetches from the lit propagation service so nodes will always have it
827+ const resp = await fetch ( this . _blockHashUrl ) ;
828+ // If the blockhash retrieval failed, throw an error to trigger fallback in catch block
829+ if ( ! resp . ok ) {
830+ throwError ( {
831+ message : `Error getting latest blockhash from ${ this . _blockHashUrl } . Received: "${ resp . status } "` ,
832+ errorKind : LIT_ERROR . INVALID_ETH_BLOCKHASH . kind ,
833+ errorCode : LIT_ERROR . INVALID_ETH_BLOCKHASH . code ,
834+ } ) ;
835+ }
843836
844- log (
845- 'Attempting to fetch blockhash manually using ethers with fallback RPC URLs...'
846- ) ;
847- const provider = await this . _getProviderWithFallback ( ) ;
837+ const blockHashBody : EthBlockhashInfo = await resp . json ( ) ;
838+ const { blockhash, timestamp } = blockHashBody ;
848839
849- if ( ! provider ) {
850- logError (
851- 'All fallback RPC URLs failed. Unable to retrieve blockhash.'
852- ) ;
853- return ;
854- }
840+ // If the blockhash retrieval does not have the required fields, throw an error to trigger fallback in catch block
841+ if ( ! blockhash || ! timestamp ) {
842+ throwError ( {
843+ message : `Error getting latest blockhash from block indexer. Received: "${ blockHashBody } "` ,
844+ errorKind : LIT_ERROR . INVALID_ETH_BLOCKHASH . kind ,
845+ errorCode : LIT_ERROR . INVALID_ETH_BLOCKHASH . code ,
846+ } ) ;
847+ }
855848
856- try {
857- const latestBlock = await provider . getBlock ( 'latest' ) ;
858- this . latestBlockhash = latestBlock . hash ;
859- this . lastBlockHashRetrieved = Date . now ( ) ;
860- log (
861- 'Successfully retrieved blockhash manually: ' ,
862- this . latestBlockhash
863- ) ;
864- } catch ( ethersError ) {
865- logError ( 'Failed to manually retrieve blockhash using ethers' ) ;
866- }
867- } ) ;
849+ this . latestBlockhash = blockHashBody . blockhash ;
850+ this . lastBlockHashRetrieved = parseInt ( timestamp ) * 1000 ;
851+ log ( 'Done syncing state new blockhash: ' , this . latestBlockhash ) ;
852+ } catch ( error : unknown ) {
853+ const err = error as BlockHashErrorResponse | Error ;
854+
855+ logError (
856+ 'Error while attempting to fetch new latestBlockhash:' ,
857+ err instanceof Error ? err . message : err . messages ,
858+ 'Reason: ' ,
859+ err instanceof Error ? err : err . reason
860+ ) ;
861+
862+ log (
863+ 'Attempting to fetch blockhash manually using ethers with fallback RPC URLs...'
864+ ) ;
865+ const provider = await this . _getProviderWithFallback ( ) ;
866+
867+ if ( ! provider ) {
868+ logError ( 'All fallback RPC URLs failed. Unable to retrieve blockhash.' ) ;
869+ return ;
870+ }
871+
872+ try {
873+ // We use a previous block to avoid nodes not having received the latest block yet
874+ const priorBlock = await provider . getBlock (
875+ BLOCKHASH_COUNT_PROVIDER_DELAY
876+ ) ;
877+ this . latestBlockhash = priorBlock . hash ;
878+ this . lastBlockHashRetrieved = priorBlock . timestamp ;
879+ log (
880+ 'Successfully retrieved blockhash manually: ' ,
881+ this . latestBlockhash
882+ ) ;
883+ } catch ( ethersError ) {
884+ logError ( 'Failed to manually retrieve blockhash using ethers' ) ;
885+ }
886+ }
868887 }
869888
870889 /** Currently, we perform a full sync every 30s, including handshaking with every node
0 commit comments