@@ -193,11 +193,18 @@ export default class BlockDbRepository implements BlockRepository {
193193 }
194194
195195 /**
196- * Retrieves blocks within a specific height range
196+ * Retrieves blocks within a specific height range using a sliding window approach
197197 *
198198 * This method fetches blocks between the specified start and end heights,
199199 * supporting cursor-based pagination and chain filtering for efficient
200- * navigation through large result sets.
200+ * navigation through large result sets. To prevent large database queries,
201+ * it implements a sliding window approach with a default window size of 50.
202+ *
203+ * Sliding window behavior:
204+ * - If endHeight is not provided or is too far from the current cursor position,
205+ * the query is limited to a window of 50 heights from the current position
206+ * - As pagination progresses (via 'after' cursor), the window slides forward
207+ * - This prevents unnecessary large queries when users request broad ranges
201208 *
202209 * Uses keyset pagination with compound cursors (height:id) for better performance
203210 * when navigating through large datasets.
@@ -228,8 +235,70 @@ export default class BlockDbRepository implements BlockRepository {
228235 last,
229236 } ) ;
230237
238+ const heightQuery = `SELECT max("height") FROM "Blocks"` ;
239+
240+ const { rows : maxHeightRows } = await rootPgPool . query ( heightQuery ) ;
241+
242+ const maxHeight = maxHeightRows [ 0 ] . max ;
243+ // Default window size to prevent large database queries
244+ const DEFAULT_WINDOW_SIZE = 50 ;
245+
246+ // Calculate effective window range
247+ let effectiveStartHeight = startHeight ;
248+ let effectiveEndHeight : number ;
249+
250+ // Determine current position from cursor for window calculation
251+ let currentHeight = startHeight ;
252+ if ( after ) {
253+ const [ height ] = after . split ( ':' ) ;
254+ const afterHeight = parseInt ( height , 10 ) ;
255+ if ( ! isNaN ( afterHeight ) ) {
256+ currentHeight = afterHeight ;
257+ }
258+ } else if ( before ) {
259+ const [ height ] = before . split ( ':' ) ;
260+ const beforeHeight = parseInt ( height , 10 ) ;
261+ if ( ! isNaN ( beforeHeight ) ) {
262+ currentHeight = beforeHeight ;
263+ }
264+ }
265+
266+ // If no endHeight provided or endHeight is too far from current position,
267+ // use sliding window approach
268+ if ( ! endHeight || endHeight - currentHeight > DEFAULT_WINDOW_SIZE ) {
269+ if ( after ) {
270+ // Forward pagination: window starts from cursor position
271+ effectiveStartHeight = currentHeight ;
272+ effectiveEndHeight = effectiveStartHeight + DEFAULT_WINDOW_SIZE ;
273+ } else if ( before ) {
274+ // Backward pagination: window ends at cursor position
275+ effectiveEndHeight = currentHeight ;
276+ effectiveStartHeight = Math . max ( startHeight , effectiveEndHeight - DEFAULT_WINDOW_SIZE ) ;
277+ } else {
278+ // Initial request: check if it's 'last' pagination (backward from end)
279+ if ( last ) {
280+ // For 'last' without cursor, use the maximum height across all chains
281+ const actualEndHeight = endHeight ? Math . min ( endHeight , maxHeight ) : maxHeight ;
282+ effectiveEndHeight = actualEndHeight ;
283+ effectiveStartHeight = Math . max ( startHeight , actualEndHeight - DEFAULT_WINDOW_SIZE ) ;
284+ } else {
285+ // Forward pagination: window starts from startHeight
286+ effectiveStartHeight = startHeight ;
287+ effectiveEndHeight = effectiveStartHeight + DEFAULT_WINDOW_SIZE ;
288+ }
289+ }
290+
291+ // If original endHeight is provided and within window, respect it (except for 'last' mode)
292+ if ( endHeight && endHeight <= effectiveEndHeight && ! last ) {
293+ effectiveEndHeight = endHeight ;
294+ }
295+ } else {
296+ // Use the provided endHeight when it's within reasonable range
297+ effectiveEndHeight = endHeight ;
298+ }
299+
231300 const order = orderParam === 'ASC' ? 'DESC' : 'ASC' ;
232- const queryParams : ( string | number | string [ ] ) [ ] = [ limit , startHeight ] ;
301+ const queryParams : ( string | number | string [ ] ) [ ] = [ limit ] ;
233302 let conditions = '' ;
234303
235304 if ( before ) {
@@ -243,7 +312,7 @@ export default class BlockDbRepository implements BlockRepository {
243312 }
244313
245314 queryParams . push ( beforeHeight , beforeId ) ;
246- conditions += `\nAND (b.height, b.id) > ($${ queryParams . length - 1 } , $${ queryParams . length } )` ;
315+ conditions += `\nAND (b.height, b.id) < ($${ queryParams . length - 1 } , $${ queryParams . length } )` ;
247316 }
248317
249318 if ( after ) {
@@ -256,19 +325,26 @@ export default class BlockDbRepository implements BlockRepository {
256325 throw new Error ( 'Invalid after cursor' ) ;
257326 }
258327 queryParams . push ( afterHeight , afterId ) ;
259- conditions += `\nAND (b.height, b.id) < ($${ queryParams . length - 1 } , $${ queryParams . length } )` ;
328+ conditions += `\nAND (b.height, b.id) > ($${ queryParams . length - 1 } , $${ queryParams . length } )` ;
260329 }
261330
262331 if ( chainIds ?. length ) {
263332 queryParams . push ( chainIds ) ;
264333 conditions += `\nAND b."chainId" = ANY($${ queryParams . length } )` ;
265334 }
266335
267- if ( endHeight ) {
268- queryParams . push ( endHeight ) ;
269- conditions += `\nAND b."height" <= $${ queryParams . length } ` ;
336+ // Apply height range constraints
337+ // Only add start height constraint if we don't have an 'after' cursor
338+ // (cursor condition already handles the lower bound for 'after')
339+ // For 'before' cursor, we still need the lower bound
340+ if ( ! after ) {
341+ queryParams . push ( effectiveStartHeight ) ;
342+ conditions += `\nAND b."height" >= $${ queryParams . length } ` ;
270343 }
271344
345+ queryParams . push ( effectiveEndHeight ) ;
346+ conditions += `\nAND b."height" <= $${ queryParams . length } ` ;
347+
272348 const query = `
273349 SELECT b.id,
274350 b.hash,
@@ -288,7 +364,7 @@ export default class BlockDbRepository implements BlockRepository {
288364 b."transactionsCount" as "transactionsCount",
289365 b."totalGasUsed" as "totalGasUsed"
290366 FROM "Blocks" b
291- WHERE b.height ${ before ? '<=' : '>=' } $2
367+ WHERE 1=1
292368 ${ conditions }
293369 ORDER BY b.height ${ order } , b.id ${ order }
294370 LIMIT $1;
@@ -301,7 +377,7 @@ export default class BlockDbRepository implements BlockRepository {
301377 node : blockValidator . validate ( row ) ,
302378 } ) ) ;
303379
304- const pageInfo = getPageInfo ( { edges, order, limit, after, before } ) ;
380+ const pageInfo = getPageInfo ( { edges, order : orderParam , limit, after, before } ) ;
305381 return pageInfo ;
306382 }
307383
0 commit comments