@@ -19,21 +19,21 @@ package main
1919import (
2020 "archive/tar"
2121 "bufio"
22- "bytes"
2322 "context"
2423 "database/sql"
2524 "encoding/json"
2625 "fmt"
2726 "io"
28- "io/ioutil"
2927 "os"
3028 "strings"
3129 "time"
3230
3331 "github.com/spf13/cobra"
3432
33+ cmdutil "github.com/algorand/go-algorand/cmd/util"
3534 "github.com/algorand/go-algorand/config"
3635 "github.com/algorand/go-algorand/data/basics"
36+ "github.com/algorand/go-algorand/data/bookkeeping"
3737 "github.com/algorand/go-algorand/ledger"
3838 "github.com/algorand/go-algorand/ledger/ledgercore"
3939 "github.com/algorand/go-algorand/logging"
@@ -43,10 +43,12 @@ import (
4343
4444var tarFile string
4545var outFileName string
46+ var excludedFields * cmdutil.CobraStringSliceValue = cmdutil .MakeCobraStringSliceValue (nil , []string {"version" , "catchpoint" })
4647
4748func init () {
4849 fileCmd .Flags ().StringVarP (& tarFile , "tar" , "t" , "" , "Specify the tar file to process" )
4950 fileCmd .Flags ().StringVarP (& outFileName , "output" , "o" , "" , "Specify an outfile for the dump ( i.e. tracker.dump.txt )" )
51+ fileCmd .Flags ().VarP (excludedFields , "exclude-fields" , "e" , "List of fields to exclude from the dump: [" + excludedFields .AllowedString ()+ "]" )
5052}
5153
5254var fileCmd = & cobra.Command {
@@ -59,11 +61,23 @@ var fileCmd = &cobra.Command{
5961 cmd .HelpFunc ()(cmd , args )
6062 return
6163 }
62- tarFileBytes , err := ioutil .ReadFile (tarFile )
63- if err != nil || len (tarFileBytes ) == 0 {
64- reportErrorf ("Unable to read '%s' : %v" , tarFile , err )
64+ stats , err := os .Stat (tarFile )
65+ if err != nil {
66+ reportErrorf ("Unable to stat '%s' : %v" , tarFile , err )
67+ }
68+ tarSize := stats .Size ()
69+ if tarSize == 0 {
70+ reportErrorf ("Empty file '%s' : %v" , tarFile , err )
71+ }
72+ // TODO: store CurrentProtocol in catchpoint file header.
73+ // As a temporary workaround use a current protocol version.
74+ genesisInitState := ledgercore.InitState {
75+ Block : bookkeeping.Block {BlockHeader : bookkeeping.BlockHeader {
76+ UpgradeState : bookkeeping.UpgradeState {
77+ CurrentProtocol : protocol .ConsensusCurrentVersion ,
78+ },
79+ }},
6580 }
66- genesisInitState := ledgercore.InitState {}
6781 cfg := config .GetDefaultLocal ()
6882 l , err := ledger .OpenLedger (logging .Base (), "./ledger" , false , genesisInitState , cfg )
6983 if err != nil {
@@ -84,7 +98,14 @@ var fileCmd = &cobra.Command{
8498 reportErrorf ("Unable to initialize catchup database : %v" , err )
8599 }
86100 var fileHeader ledger.CatchpointFileHeader
87- fileHeader , err = loadCatchpointIntoDatabase (context .Background (), catchupAccessor , tarFileBytes )
101+
102+ reader , err := os .Open (tarFile )
103+ if err != nil {
104+ reportErrorf ("Unable to read '%s' : %v" , tarFile , err )
105+ }
106+ defer reader .Close ()
107+
108+ fileHeader , err = loadCatchpointIntoDatabase (context .Background (), catchupAccessor , reader , tarSize )
88109 if err != nil {
89110 reportErrorf ("Unable to load catchpoint file into in-memory database : %v" , err )
90111 }
@@ -98,7 +119,7 @@ var fileCmd = &cobra.Command{
98119 defer outFile .Close ()
99120 }
100121
101- err = printAccountsDatabase ("./ledger.tracker.sqlite" , fileHeader , outFile )
122+ err = printAccountsDatabase ("./ledger.tracker.sqlite" , fileHeader , outFile , excludedFields . GetSlice () )
102123 if err != nil {
103124 reportErrorf ("Unable to print account database : %v" , err )
104125 }
@@ -115,15 +136,14 @@ func printLoadCatchpointProgressLine(progress int, barLength int, dld int64) {
115136 fmt .Printf (escapeCursorUp + escapeDeleteLine + outString + " %s\n " , formatSize (dld ))
116137}
117138
118- func loadCatchpointIntoDatabase (ctx context.Context , catchupAccessor ledger.CatchpointCatchupAccessor , fileBytes [] byte ) (fileHeader ledger.CatchpointFileHeader , err error ) {
139+ func loadCatchpointIntoDatabase (ctx context.Context , catchupAccessor ledger.CatchpointCatchupAccessor , tarFile io. Reader , tarSize int64 ) (fileHeader ledger.CatchpointFileHeader , err error ) {
119140 fmt .Printf ("\n " )
120141 printLoadCatchpointProgressLine (0 , 50 , 0 )
121142 lastProgressUpdate := time .Now ()
122143 progress := uint64 (0 )
123144 defer printLoadCatchpointProgressLine (0 , 0 , 0 )
124145
125- reader := bytes .NewReader (fileBytes )
126- tarReader := tar .NewReader (reader )
146+ tarReader := tar .NewReader (tarFile )
127147 var downloadProgress ledger.CatchpointCatchupAccessorProgress
128148 for {
129149 header , err := tarReader .Next ()
@@ -158,9 +178,9 @@ func loadCatchpointIntoDatabase(ctx context.Context, catchupAccessor ledger.Catc
158178 // we already know it's valid, since we validated that above.
159179 protocol .Decode (balancesBlockBytes , & fileHeader )
160180 }
161- if time .Now (). Sub ( lastProgressUpdate ) > 50 * time .Millisecond && len ( fileBytes ) > 0 {
181+ if time .Since ( lastProgressUpdate ) > 50 * time .Millisecond && tarSize > 0 {
162182 lastProgressUpdate = time .Now ()
163- printLoadCatchpointProgressLine (int (float64 (progress )* 50.0 / float64 (len ( fileBytes ) )), 50 , int64 (progress ))
183+ printLoadCatchpointProgressLine (int (float64 (progress )* 50.0 / float64 (tarSize )), 50 , int64 (progress ))
164184 }
165185 }
166186}
@@ -178,7 +198,7 @@ func printDumpingCatchpointProgressLine(progress int, barLength int, dld int64)
178198 fmt .Printf (escapeCursorUp + escapeDeleteLine + outString + "\n " )
179199}
180200
181- func printAccountsDatabase (databaseName string , fileHeader ledger.CatchpointFileHeader , outFile * os.File ) error {
201+ func printAccountsDatabase (databaseName string , fileHeader ledger.CatchpointFileHeader , outFile * os.File , excludeFields [] string ) error {
182202 lastProgressUpdate := time .Now ()
183203 progress := uint64 (0 )
184204 defer printDumpingCatchpointProgressLine (0 , 0 , 0 )
@@ -191,14 +211,54 @@ func printAccountsDatabase(databaseName string, fileHeader ledger.CatchpointFile
191211 return err
192212 }
193213 if fileHeader .Version != 0 {
194- fmt .Fprintf (fileWriter , "Version: %d\n Balances Round: %d\n Block Round: %d\n Block Header Digest: %s\n Catchpoint: %s\n Total Accounts: %d\n Total Chunks: %d\n " ,
214+ var headerFields = []string {
215+ "Version: %d" ,
216+ "Balances Round: %d" ,
217+ "Block Round: %d" ,
218+ "Block Header Digest: %s" ,
219+ "Catchpoint: %s" ,
220+ "Total Accounts: %d" ,
221+ "Total Chunks: %d" ,
222+ }
223+ var headerValues = []interface {}{
195224 fileHeader .Version ,
196225 fileHeader .BalancesRound ,
197226 fileHeader .BlocksRound ,
198227 fileHeader .BlockHeaderDigest .String (),
199228 fileHeader .Catchpoint ,
200229 fileHeader .TotalAccounts ,
201- fileHeader .TotalChunks )
230+ fileHeader .TotalChunks ,
231+ }
232+ // safety check
233+ if len (headerFields ) != len (headerValues ) {
234+ return fmt .Errorf ("printing failed: header formatting mismatch" )
235+ }
236+
237+ var actualFields []string
238+ var actualValues []interface {}
239+ if len (excludeFields ) == 0 {
240+ actualFields = headerFields
241+ actualValues = headerValues
242+ } else {
243+ actualFields = make ([]string , 0 , len (headerFields )- len (excludeFields ))
244+ actualValues = make ([]interface {}, 0 , len (headerFields )- len (excludeFields ))
245+ for i , field := range headerFields {
246+ lower := strings .ToLower (field )
247+ excluded := false
248+ for _ , filter := range excludeFields {
249+ if strings .HasPrefix (lower , filter ) {
250+ excluded = true
251+ break
252+ }
253+ }
254+ if ! excluded {
255+ actualFields = append (actualFields , field )
256+ actualValues = append (actualValues , headerValues [i ])
257+ }
258+ }
259+ }
260+
261+ fmt .Fprintf (fileWriter , strings .Join (actualFields , "\n " )+ "\n " , actualValues ... )
202262
203263 totals := fileHeader .Totals
204264 fmt .Fprintf (fileWriter , "AccountTotals - Online Money: %d\n AccountTotals - Online RewardUnits : %d\n AccountTotals - Offline Money: %d\n AccountTotals - Offline RewardUnits : %d\n AccountTotals - Not Participating Money: %d\n AccountTotals - Not Participating Money RewardUnits: %d\n AccountTotals - Rewards Level: %d\n " ,
0 commit comments