@@ -14,6 +14,8 @@ import (
1414 "time"
1515
1616 "github.com/spf13/cobra"
17+ "gorm.io/driver/postgres"
18+ "gorm.io/gorm"
1719
1820 "github.com/scroll-tech/go-ethereum/ethclient"
1921
@@ -70,6 +72,18 @@ It produces a binary file and optionally a human readable csv file with the miss
7072 if err != nil {
7173 log .Fatalf ("Error reading continue flag: %v" , err )
7274 }
75+ dbDSN , err := cmd .Flags ().GetString ("db" )
76+ if err != nil {
77+ log .Fatalf ("Error reading db flag: %v" , err )
78+ }
79+
80+ var db * gorm.DB
81+ if dbDSN != "" {
82+ db , err = gorm .Open (postgres .Open (dbDSN ), & gorm.Config {})
83+ if err != nil {
84+ log .Fatalf ("Error connecting to database: %v" , err )
85+ }
86+ }
7387
7488 if continueFile != "" {
7589 fmt .Println ("Continue fetching block header fields from" , continueFile )
@@ -92,7 +106,7 @@ It produces a binary file and optionally a human readable csv file with the miss
92106 }
93107 }
94108
95- runFetch (clients , startBlockNum , endBlockNum , batchSize , maxParallelGoroutines , outputFile , humanReadableOutputFile , continueFile )
109+ runFetch (clients , db , startBlockNum , endBlockNum , batchSize , maxParallelGoroutines , outputFile , humanReadableOutputFile , continueFile )
96110 },
97111}
98112
@@ -107,6 +121,7 @@ func init() {
107121 fetchCmd .Flags ().String ("output" , "headers.bin" , "output file" )
108122 fetchCmd .Flags ().String ("humanOutput" , "" , "additionally produce human readable csv file" )
109123 fetchCmd .Flags ().String ("continue" , "" , "continue fetching block header fields from the last seen block number in the specified continue file" )
124+ fetchCmd .Flags ().String ("db" , "" , "database to use instead of fetching from RPC" )
110125}
111126
112127func headerByNumberWithRetry (client * ethclient.Client , blockNum uint64 , maxRetries int ) (* types.Header , error ) {
@@ -118,6 +133,8 @@ func headerByNumberWithRetry(client *ethclient.Client, blockNum uint64, maxRetri
118133 header .Number .Uint64 (),
119134 header .Difficulty .Uint64 (),
120135 header .Root ,
136+ header .Coinbase ,
137+ header .Nonce ,
121138 header .Extra ,
122139 ), nil
123140 }
@@ -132,7 +149,26 @@ func headerByNumberWithRetry(client *ethclient.Client, blockNum uint64, maxRetri
132149 return nil , fmt .Errorf ("error fetching header for block %d: %v" , blockNum , innerErr )
133150}
134151
135- func fetchHeaders (clients []* ethclient.Client , start , end uint64 , headersChan chan <- * types.Header ) {
152+ func fetchHeadersFromDB (db * gorm.DB , start , end uint64 , headersChan chan <- * types.Header ) {
153+ blockORM := types .NewL2Block (db )
154+ blocks , err := blockORM .GetL2BlocksInRange (context .Background (), start , end )
155+ if err != nil {
156+ log .Fatalf ("Error fetching blocks from database: %v" , err )
157+ }
158+
159+ for _ , block := range blocks {
160+ headersChan <- types .NewHeader (
161+ block .Header .Number .Uint64 (),
162+ block .Header .Difficulty .Uint64 (),
163+ block .Header .Root ,
164+ block .Header .Coinbase ,
165+ block .Header .Nonce ,
166+ block .Header .Extra ,
167+ )
168+ }
169+ }
170+
171+ func fetchHeadersFromRPC (clients []* ethclient.Client , start , end uint64 , headersChan chan <- * types.Header ) {
136172 // randomize client selection to distribute load
137173 r := uint64 (rand .Int ())
138174
@@ -199,7 +235,7 @@ func writeHeadersToFile(outputFile string, humanReadableOutputFile string, conti
199235 fmt .Println ("Finished writing headers to file, last block number:" , nextHeaderNum - 1 )
200236}
201237
202- func runFetch (clients []* ethclient.Client , startBlockNum uint64 , endBlockNum uint64 , batchSize uint64 , maxGoroutines int , outputFile string , humanReadableOutputFile string , continueFile string ) {
238+ func runFetch (clients []* ethclient.Client , db * gorm. DB , startBlockNum uint64 , endBlockNum uint64 , batchSize uint64 , maxGoroutines int , outputFile string , humanReadableOutputFile string , continueFile string ) {
203239 headersChan := make (chan * types.Header , maxGoroutines * int (batchSize ))
204240 tasks := make (chan task )
205241
@@ -222,12 +258,25 @@ func runFetch(clients []*ethclient.Client, startBlockNum uint64, endBlockNum uin
222258 break
223259 }
224260 log .Println ("Received task" , t .start , "to" , t .end )
225- fetchHeaders (clients , t .start , t .end , headersChan )
261+
262+ // use DB if dbDSN is provided, otherwise fetch from RPC
263+ if db != nil {
264+ fetchHeadersFromDB (db , t .start , t .end , headersChan )
265+ } else {
266+ fetchHeadersFromRPC (clients , t .start , t .end , headersChan )
267+ }
226268 }
227269 wgProducers .Done ()
228270 }()
229271 }
230272
273+ // need to fetch block 0 from RPC
274+ if startBlockNum == 0 && db != nil {
275+ fmt .Println ("Fetching headers from database... and header 0 from RPC" )
276+ fetchHeadersFromRPC (clients , 0 , 0 , headersChan )
277+ startBlockNum = 1
278+ }
279+
231280 // create tasks/work packages for producer goroutines
232281 for start := startBlockNum ; start <= endBlockNum ; start += batchSize {
233282 end := start + batchSize - 1
0 commit comments