@@ -236,10 +236,19 @@ func (rpc *Client) GetFullBlocks(ctx context.Context, blockNumbers []*big.Int) [
236236 var receipts []RPCFetchBatchResult [* big.Int , common.RawReceipts ]
237237 wg .Add (2 )
238238
239+ // Check if we need special handling for chain ID 296
240+ needsSpecialHandling := rpc .needsChain296SpecialHandling (blockNumbers )
241+
239242 go func () {
240243 defer wg .Done ()
241- result := RPCFetchSingleBatch [* big.Int , common.RawBlock ](rpc , ctx , blockNumbers , "eth_getBlockByNumber" , GetBlockWithTransactionsParams )
242- blocks = result
244+ if needsSpecialHandling {
245+ // For chain 296 with block <= 5780915, get blocks without transactions first
246+ // then fetch transactions separately in batches
247+ blocks = RPCFetchSingleBatch [* big.Int , common.RawBlock ](rpc , ctx , blockNumbers , "eth_getBlockByNumber" , GetBlockWithoutTransactionsParams )
248+ } else {
249+ // Normal flow - get blocks with transactions
250+ blocks = RPCFetchSingleBatch [* big.Int , common.RawBlock ](rpc , ctx , blockNumbers , "eth_getBlockByNumber" , GetBlockWithTransactionsParams )
251+ }
243252 }()
244253
245254 if rpc .supportsBlockReceipts {
@@ -267,6 +276,11 @@ func (rpc *Client) GetFullBlocks(ctx context.Context, blockNumbers []*big.Int) [
267276
268277 wg .Wait ()
269278
279+ // If we used special handling, we need to fetch transactions separately
280+ if needsSpecialHandling {
281+ blocks = rpc .fetchTransactionsForChain296 (ctx , blocks )
282+ }
283+
270284 return SerializeFullBlocks (rpc .chainID , blocks , logs , traces , receipts )
271285}
272286
@@ -315,3 +329,122 @@ func (rpc *Client) HasCode(ctx context.Context, address string) (bool, error) {
315329 }
316330 return len (code ) > 0 , nil
317331}
332+
333+ // needsChain296SpecialHandling checks if we need special handling for chain ID 296
334+ func (rpc * Client ) needsChain296SpecialHandling (blockNumbers []* big.Int ) bool {
335+ // Check if chain ID is 296
336+ if rpc .chainID == nil || rpc .chainID .Uint64 () != 296 {
337+ return false
338+ }
339+
340+ // Check if any block number is <= 5780915 and >= 3853944
341+ threshold2 := big .NewInt (5780915 )
342+ threshold1 := big .NewInt (3853944 )
343+ for _ , blockNum := range blockNumbers {
344+ if blockNum .Cmp (threshold1 ) > 0 && blockNum .Cmp (threshold2 ) <= 0 {
345+ return true
346+ }
347+ }
348+ return false
349+ }
350+
351+ // fetchTransactionsForChain296 fetches transactions separately for chain 296 blocks
352+ func (rpc * Client ) fetchTransactionsForChain296 (ctx context.Context , blocks []RPCFetchBatchResult [* big.Int , common.RawBlock ]) []RPCFetchBatchResult [* big.Int , common.RawBlock ] {
353+ // Collect all transaction hashes from all blocks
354+ var allTxHashes []string
355+ blockTxMap := make (map [string ][]string ) // maps block number to transaction hashes
356+
357+ for _ , blockResult := range blocks {
358+ if blockResult .Error != nil {
359+ continue
360+ }
361+ blockNum := blockResult .Key .String ()
362+ var txHashes []string
363+
364+ // Extract transaction hashes from the block
365+ if transactions , exists := blockResult .Result ["transactions" ]; exists {
366+ if txList , ok := transactions .([]interface {}); ok {
367+ for _ , tx := range txList {
368+ if txHash , ok := tx .(string ); ok {
369+ txHashes = append (txHashes , txHash )
370+ allTxHashes = append (allTxHashes , txHash )
371+ }
372+ }
373+ }
374+ }
375+ blockTxMap [blockNum ] = txHashes
376+ }
377+
378+ if len (allTxHashes ) == 0 {
379+ return blocks
380+ }
381+
382+ // Fetch transactions in batches of 100 with parallel processing
383+ transactions := rpc .fetchTransactionsInBatches (ctx , allTxHashes , 100 )
384+
385+ // Create a map of transaction hash to transaction data
386+ txMap := make (map [string ]interface {})
387+ for _ , txResult := range transactions {
388+ if txResult .Error == nil {
389+ txMap [txResult .Key ] = txResult .Result
390+ }
391+ }
392+
393+ // Update blocks with transaction data
394+ for i , blockResult := range blocks {
395+ if blockResult .Error != nil {
396+ continue
397+ }
398+ blockNum := blockResult .Key .String ()
399+ txHashes := blockTxMap [blockNum ]
400+
401+ var blockTransactions []interface {}
402+ for _ , txHash := range txHashes {
403+ if txData , exists := txMap [txHash ]; exists {
404+ blockTransactions = append (blockTransactions , txData )
405+ }
406+ }
407+
408+ // Update the block with the fetched transactions
409+ blocks [i ].Result ["transactions" ] = blockTransactions
410+ }
411+
412+ return blocks
413+ }
414+
415+ // fetchTransactionsInBatches fetches transactions in batches with parallel processing
416+ func (rpc * Client ) fetchTransactionsInBatches (ctx context.Context , txHashes []string , batchSize int ) []RPCFetchBatchResult [string , common.RawTransaction ] {
417+ if len (txHashes ) <= batchSize {
418+ return RPCFetchSingleBatch [string , common.RawTransaction ](rpc , ctx , txHashes , "eth_getTransactionByHash" , GetTransactionParams )
419+ }
420+
421+ // Split into chunks
422+ chunks := common .SliceToChunks [string ](txHashes , batchSize )
423+
424+ log .Debug ().Msgf ("Fetching %d transactions in %d chunks of max %d requests" , len (txHashes ), len (chunks ), batchSize )
425+
426+ var wg sync.WaitGroup
427+ resultsCh := make (chan []RPCFetchBatchResult [string , common.RawTransaction ], len (chunks ))
428+
429+ // Process chunks in parallel
430+ for _ , chunk := range chunks {
431+ wg .Add (1 )
432+ go func (chunk []string ) {
433+ defer wg .Done ()
434+ resultsCh <- RPCFetchSingleBatch [string , common.RawTransaction ](rpc , ctx , chunk , "eth_getTransactionByHash" , GetTransactionParams )
435+ }(chunk )
436+ }
437+
438+ go func () {
439+ wg .Wait ()
440+ close (resultsCh )
441+ }()
442+
443+ // Collect results
444+ results := make ([]RPCFetchBatchResult [string , common.RawTransaction ], 0 , len (txHashes ))
445+ for batchResults := range resultsCh {
446+ results = append (results , batchResults ... )
447+ }
448+
449+ return results
450+ }
0 commit comments