11import { fromHex } from "viem" ;
22import type { Bytes , Cursor } from "../common" ;
3- import type { BlockInfo } from "./config" ;
3+ import type { BlockInfo , FetchCursorRangeArgs } from "./config" ;
44import { blockInfoToCursor } from "./helpers" ;
55
66type UpdateHeadArgs = {
77 newHead : BlockInfo ;
88 fetchCursorByHash : ( hash : Bytes ) => Promise < BlockInfo | null > ;
9+ fetchCursorRange : ( args : FetchCursorRangeArgs ) => Promise < BlockInfo [ ] > ;
910} ;
1011
1112type UpdateHeadResult =
@@ -24,10 +25,21 @@ export class ChainTracker {
2425 #finalized: BlockInfo ;
2526 #head: BlockInfo ;
2627 #canonical: Map < bigint , BlockInfo > ;
28+ #batchSize: bigint ;
2729
28- constructor ( { head, finalized } : { finalized : BlockInfo ; head : BlockInfo } ) {
30+ constructor ( {
31+ head,
32+ finalized,
33+ batchSize,
34+ } : {
35+ finalized : BlockInfo ;
36+ head : BlockInfo ;
37+ batchSize : bigint ;
38+ } ) {
2939 this . #finalized = finalized ;
3040 this . #head = head ;
41+ this . #batchSize = batchSize ;
42+
3143 this . #canonical = new Map ( [
3244 [ finalized . blockNumber , finalized ] ,
3345 [ head . blockNumber , head ] ,
@@ -106,6 +118,7 @@ export class ChainTracker {
106118 async updateHead ( {
107119 newHead,
108120 fetchCursorByHash,
121+ fetchCursorRange,
109122 } : UpdateHeadArgs ) : Promise < UpdateHeadResult > {
110123 // console.debug(
111124 // `updateHead: new=${newHead.blockNumber} old=${this.#head.blockNumber}`,
@@ -192,10 +205,47 @@ export class ChainTracker {
192205 // The new chain is longer and we need the missing blocks.
193206 // This may result in reorgs.
194207
195- let current = newHead ;
196- let reorgDetected = false ;
197- const blocksToApply = [ newHead ] ;
208+ // console.log(
209+ // `Moving from ${this.#head.blockNumber} to ${newHead.blockNumber} (${newHead.blockNumber - this.#head.blockNumber} blocks)`,
210+ // );
211+
212+ let currentBlockNumber = this . #head. blockNumber + 1n ;
213+
214+ while ( true ) {
215+ let endBlockNumber = currentBlockNumber + this . #batchSize;
216+ if ( endBlockNumber > newHead . blockNumber ) {
217+ endBlockNumber = newHead . blockNumber ;
218+ }
219+
220+ const missing = await fetchCursorRange ( {
221+ startBlockNumber : currentBlockNumber ,
222+ endBlockNumber,
223+ } ) ;
224+
225+ for ( const block of missing ) {
226+ const canonicalParent = this . #canonical. get ( block . blockNumber - 1n ) ;
227+ if (
228+ ! canonicalParent ||
229+ canonicalParent . blockHash !== block . parentBlockHash
230+ ) {
231+ throw new Error (
232+ "Chain reorganization detected. Recovery not implemented" ,
233+ ) ;
234+ }
235+
236+ this . #canonical. set ( block . blockNumber , block ) ;
237+
238+ // console.log(`Applied block ${block.blockNumber}`);
239+ }
240+
241+ if ( endBlockNumber === newHead . blockNumber ) {
242+ break ;
243+ }
244+
245+ currentBlockNumber = endBlockNumber + 1n ;
246+ }
198247
248+ /*
199249 while (true) {
200250 const parent = await fetchCursorByHash(current.parentBlockHash);
201251
@@ -226,24 +276,39 @@ export class ChainTracker {
226276 blocksToApply.push(parent);
227277 current = parent;
228278 }
279+ */
280+ // throw new Error("FUCK IT");
229281
230- for ( const block of blocksToApply . reverse ( ) ) {
231- this . #canonical. set ( block . blockNumber , block ) ;
232- }
282+ // for (const block of blocksToApply.reverse()) {
283+ // this.#canonical.set(block.blockNumber, block);
284+ // }
233285
234- const previousHead = this . #head;
286+ // const previousHead = this.#head;
235287 this . #head = newHead ;
236288
237- if ( reorgDetected ) {
238- return {
239- status : "reorg" ,
240- cursor : blockInfoToCursor ( previousHead ) ,
241- } ;
242- }
289+ // if (reorgDetected) {
290+ // return {
291+ // status: "reorg",
292+ // cursor: blockInfoToCursor(previousHead),
293+ // };
294+ // }
243295
244296 return { status : "success" } ;
245297 }
246298
299+ isCanonical ( { orderKey, uniqueKey } : Cursor ) {
300+ if ( ! uniqueKey ) {
301+ return true ;
302+ }
303+
304+ const block = this . #canonical. get ( orderKey ) ;
305+ if ( ! block ) {
306+ return true ;
307+ }
308+
309+ return block . blockHash === uniqueKey ;
310+ }
311+
247312 async initializeStartingCursor ( {
248313 cursor,
249314 fetchCursor,
@@ -319,9 +384,11 @@ export class ChainTracker {
319384export function createChainTracker ( {
320385 head,
321386 finalized,
387+ batchSize,
322388} : {
323389 head : BlockInfo ;
324390 finalized : BlockInfo ;
391+ batchSize : bigint ;
325392} ) : ChainTracker {
326- return new ChainTracker ( { finalized, head } ) ;
393+ return new ChainTracker ( { finalized, head, batchSize } ) ;
327394}
0 commit comments