package main import ( "bufio" "bytes" "context" "encoding/binary" "encoding/json" "errors" "flag" "fmt" "io" "math/big" "net/http" _ "net/http/pprof" //nolint:gosec "os" "os/signal" "path/filepath" "regexp" "runtime" "runtime/pprof" "strconv" "strings" "syscall" "time" "github.com/RoaringBitmap/roaring/roaring64" "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/compress" "github.com/ledgerwatch/erigon-lib/etl" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/ledgerwatch/erigon-lib/recsplit" "golang.org/x/exp/slices" hackdb "github.com/ledgerwatch/erigon/cmd/hack/db" "github.com/ledgerwatch/erigon/cmd/hack/flow" "github.com/ledgerwatch/erigon/cmd/hack/tool" "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/changeset" "github.com/ledgerwatch/erigon/common/dbutils" "github.com/ledgerwatch/erigon/common/paths" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/types/accounts" "github.com/ledgerwatch/erigon/eth/stagedsync" "github.com/ledgerwatch/erigon/eth/stagedsync/stages" "github.com/ledgerwatch/erigon/ethdb" "github.com/ledgerwatch/erigon/ethdb/cbor" "github.com/ledgerwatch/erigon/internal/debug" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rlp" "github.com/ledgerwatch/erigon/turbo/snapshotsync" "github.com/ledgerwatch/erigon/turbo/snapshotsync/parallelcompress" "github.com/ledgerwatch/erigon/turbo/trie" "github.com/ledgerwatch/log/v3" "github.com/wcharczuk/go-chart/v2" ) const ASSERT = false var ( verbosity = flag.Uint("verbosity", 3, "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default 3)") action = flag.String("action", "", "action to execute") cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`") rewind = flag.Int("rewind", 1, "rewind to given number of blocks") block = flag.Int("block", 1, "specifies a block number for operation") blockTotal = flag.Int("blocktotal", 1, "specifies a total amount of blocks to process (will offset from head block if <= 0)") account = flag.String("account", "0x", "specifies account to investigate") name = flag.String("name", "", "name to add to the file names") chaindata = flag.String("chaindata", "chaindata", "path to the chaindata database file") bucket = flag.String("bucket", "", "bucket in the database") hash = flag.String("hash", "0x00", "image for preimage or state root for testBlockHashes action") ) func readData(filename string) (blocks []float64, hours []float64, dbsize []float64, trienodes []float64, heap []float64) { err := chart.ReadLines(filename, func(line string) error { parts := strings.Split(line, ",") blocks = append(blocks, tool.ParseFloat64(strings.Trim(parts[0], " "))) hours = append(hours, tool.ParseFloat64(strings.Trim(parts[1], " "))) dbsize = append(dbsize, tool.ParseFloat64(strings.Trim(parts[2], " "))) trienodes = append(trienodes, tool.ParseFloat64(strings.Trim(parts[3], " "))) heap = append(heap, tool.ParseFloat64(strings.Trim(parts[4], " "))) return nil }) if err != nil { fmt.Println(err.Error()) } return } func notables() []chart.GridLine { return []chart.GridLine{ {Value: 1.0}, {Value: 2.0}, {Value: 3.0}, {Value: 4.0}, {Value: 5.0}, {Value: 6.0}, } } func days() []chart.GridLine { return []chart.GridLine{ {Value: 24.0}, {Value: 48.0}, {Value: 72.0}, {Value: 96.0}, {Value: 120.0}, {Value: 144.0}, {Value: 168.0}, {Value: 192.0}, {Value: 216.0}, {Value: 240.0}, {Value: 264.0}, {Value: 288.0}, } } func mychart() { blocks, hours, dbsize, trienodes, heap := readData("bolt.csv") blocks0, hours0, dbsize0, _, _ := readData("badger.csv") mainSeries := &chart.ContinuousSeries{ Name: "Cumulative sync time (bolt)", Style: chart.Style{ StrokeColor: chart.ColorBlue, FillColor: chart.ColorBlue.WithAlpha(100), }, XValues: blocks, YValues: hours, } badgerSeries := &chart.ContinuousSeries{ Name: "Cumulative sync time (badger)", Style: chart.Style{ StrokeColor: chart.ColorRed, FillColor: chart.ColorRed.WithAlpha(100), }, XValues: blocks0, YValues: hours0, } dbsizeSeries := &chart.ContinuousSeries{ Name: "Database size (bolt)", Style: chart.Style{ StrokeColor: chart.ColorBlack, }, YAxis: chart.YAxisSecondary, XValues: blocks, YValues: dbsize, } dbsizeSeries0 := &chart.ContinuousSeries{ Name: "Database size (badger)", Style: chart.Style{ StrokeColor: chart.ColorOrange, }, YAxis: chart.YAxisSecondary, XValues: blocks, YValues: dbsize0, } graph1 := chart.Chart{ Width: 1280, Height: 720, Background: chart.Style{ Padding: chart.Box{ Top: 50, }, }, YAxis: chart.YAxis{ Name: "Elapsed time", NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%d h", int(v.(float64))) }, GridMajorStyle: chart.Style{ StrokeColor: chart.ColorBlue, StrokeWidth: 1.0, }, GridLines: days(), }, YAxisSecondary: chart.YAxis{ NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%d G", int(v.(float64))) }, }, XAxis: chart.XAxis{ Name: "Blocks, million", Style: chart.Style{}, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.3fm", v.(float64)) }, GridMajorStyle: chart.Style{ StrokeColor: chart.ColorAlternateGray, StrokeWidth: 1.0, }, GridLines: notables(), }, Series: []chart.Series{ mainSeries, badgerSeries, dbsizeSeries, dbsizeSeries0, }, } graph1.Elements = []chart.Renderable{chart.LegendThin(&graph1)} buffer := bytes.NewBuffer([]byte{}) err := graph1.Render(chart.PNG, buffer) tool.Check(err) err = os.WriteFile("chart1.png", buffer.Bytes(), 0644) tool.Check(err) heapSeries := &chart.ContinuousSeries{ Name: "Allocated heap", Style: chart.Style{ StrokeColor: chart.ColorYellow, FillColor: chart.ColorYellow.WithAlpha(100), }, XValues: blocks, YValues: heap, } trienodesSeries := &chart.ContinuousSeries{ Name: "Trie nodes", Style: chart.Style{ StrokeColor: chart.ColorGreen, }, YAxis: chart.YAxisSecondary, XValues: blocks, YValues: trienodes, } graph2 := chart.Chart{ Width: 1280, Height: 720, Background: chart.Style{ Padding: chart.Box{ Top: 50, }, }, YAxis: chart.YAxis{ Name: "Allocated heap", NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.1f G", v.(float64)) }, GridMajorStyle: chart.Style{ StrokeColor: chart.ColorYellow, StrokeWidth: 1.0, }, GridLines: days(), }, YAxisSecondary: chart.YAxis{ NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.1f m", v.(float64)) }, }, XAxis: chart.XAxis{ Name: "Blocks, million", Style: chart.Style{}, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.3fm", v.(float64)) }, GridMajorStyle: chart.Style{ StrokeColor: chart.ColorAlternateGray, StrokeWidth: 1.0, }, GridLines: notables(), }, Series: []chart.Series{ heapSeries, trienodesSeries, }, } graph2.Elements = []chart.Renderable{chart.LegendThin(&graph2)} buffer.Reset() err = graph2.Render(chart.PNG, buffer) tool.Check(err) err = os.WriteFile("chart2.png", buffer.Bytes(), 0644) tool.Check(err) } func bucketStats(chaindata string) error { /* ethDb := mdbx.MustOpen(chaindata) defer ethDb.Close() var bucketList []string if err1 := ethDb.View(context.Background(), func(txa kv.Tx) error { if bl, err := txa.(kv.BucketMigrator).ListBuckets(); err == nil { bucketList = bl } else { return err } return nil }); err1 != nil { ethDb.Close() return err1 } fmt.Printf(",BranchPageN,LeafPageN,OverflowN,Entries\n") switch db := ethDb.(type) { case *mdbx.MdbxKV: type MdbxStat interface { BucketStat(name string) (*mdbx.Stat, error) } if err := db.View(context.Background(), func(tx kv.Tx) error { for _, bucket := range bucketList { bs, statErr := tx.(MdbxStat).BucketStat(bucket) tool.Check(statErr) fmt.Printf("%s,%d,%d,%d,%d\n", bucket, bs.BranchPages, bs.LeafPages, bs.OverflowPages, bs.Entries) } bs, statErr := tx.(MdbxStat).BucketStat("freelist") tool.Check(statErr) fmt.Printf("%s,%d,%d,%d,%d\n", "freelist", bs.BranchPages, bs.LeafPages, bs.OverflowPages, bs.Entries) return nil }); err != nil { panic(err) } } */ return nil } func readTrieLog() ([]float64, map[int][]float64, []float64) { data, err := os.ReadFile("dust/hack.log") tool.Check(err) thresholds := []float64{} counts := map[int][]float64{} for i := 2; i <= 16; i++ { counts[i] = []float64{} } shorts := []float64{} lines := bytes.Split(data, []byte("\n")) for _, line := range lines { if bytes.HasPrefix(line, []byte("Threshold:")) { tokens := bytes.Split(line, []byte(" ")) if len(tokens) == 23 { wei := tool.ParseFloat64(string(tokens[1])) thresholds = append(thresholds, wei) for i := 2; i <= 16; i++ { pair := bytes.Split(tokens[i+3], []byte(":")) counts[i] = append(counts[i], tool.ParseFloat64(string(pair[1]))) } pair := bytes.Split(tokens[21], []byte(":")) shorts = append(shorts, tool.ParseFloat64(string(pair[1]))) } } } return thresholds, counts, shorts } func trieChart() { thresholds, counts, shorts := readTrieLog() fmt.Printf("%d %d %d\n", len(thresholds), len(counts), len(shorts)) shortsSeries := &chart.ContinuousSeries{ Name: "Short nodes", Style: chart.Style{ StrokeColor: chart.ColorBlue, FillColor: chart.ColorBlue.WithAlpha(100), }, XValues: thresholds, YValues: shorts, } countSeries := make(map[int]*chart.ContinuousSeries) for i := 2; i <= 16; i++ { countSeries[i] = &chart.ContinuousSeries{ Name: fmt.Sprintf("%d-nodes", i), Style: chart.Style{ StrokeColor: chart.GetAlternateColor(i), }, XValues: thresholds, YValues: counts[i], } } xaxis := &chart.XAxis{ Name: "Dust theshold", Style: chart.Style{}, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%d wei", int(v.(float64))) }, GridMajorStyle: chart.Style{ StrokeColor: chart.DefaultStrokeColor, StrokeWidth: 1.0, }, Range: &chart.ContinuousRange{ Min: thresholds[0], Max: thresholds[len(thresholds)-1], }, Ticks: []chart.Tick{ {Value: 0.0, Label: "0"}, {Value: 1.0, Label: "wei"}, {Value: 10.0, Label: "10"}, {Value: 100.0, Label: "100"}, {Value: 1e3, Label: "1e3"}, {Value: 1e4, Label: "1e4"}, {Value: 1e5, Label: "1e5"}, {Value: 1e6, Label: "1e6"}, {Value: 1e7, Label: "1e7"}, {Value: 1e8, Label: "1e8"}, {Value: 1e9, Label: "1e9"}, {Value: 1e10, Label: "1e10"}, //{1e15, "finney"}, //{1e18, "ether"}, }, } graph3 := chart.Chart{ Width: 1280, Height: 720, Background: chart.Style{ Padding: chart.Box{ Top: 50, }, }, XAxis: *xaxis, YAxis: chart.YAxis{ Name: "Node count", NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%dm", int(v.(float64)/1e6)) }, GridMajorStyle: chart.Style{ StrokeColor: chart.DefaultStrokeColor, StrokeWidth: 1.0, }, }, Series: []chart.Series{ shortsSeries, }, } graph3.Elements = []chart.Renderable{chart.LegendThin(&graph3)} buffer := bytes.NewBuffer([]byte{}) err := graph3.Render(chart.PNG, buffer) tool.Check(err) err = os.WriteFile("chart3.png", buffer.Bytes(), 0644) tool.Check(err) graph4 := chart.Chart{ Width: 1280, Height: 720, Background: chart.Style{ Padding: chart.Box{ Top: 50, }, }, XAxis: *xaxis, YAxis: chart.YAxis{ Name: "Node count", NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.2fm", v.(float64)/1e6) }, GridMajorStyle: chart.Style{ StrokeColor: chart.DefaultStrokeColor, StrokeWidth: 1.0, }, }, Series: []chart.Series{ countSeries[2], countSeries[3], }, } graph4.Elements = []chart.Renderable{chart.LegendThin(&graph4)} buffer = bytes.NewBuffer([]byte{}) err = graph4.Render(chart.PNG, buffer) tool.Check(err) err = os.WriteFile("chart4.png", buffer.Bytes(), 0644) tool.Check(err) graph5 := chart.Chart{ Width: 1280, Height: 720, Background: chart.Style{ Padding: chart.Box{ Top: 50, }, }, XAxis: *xaxis, YAxis: chart.YAxis{ Name: "Node count", NameStyle: chart.Shown(), Style: chart.Shown(), TickStyle: chart.Style{ TextRotationDegrees: 45.0, }, ValueFormatter: func(v interface{}) string { return fmt.Sprintf("%.2fk", v.(float64)/1e3) }, GridMajorStyle: chart.Style{ StrokeColor: chart.DefaultStrokeColor, StrokeWidth: 1.0, }, }, Series: []chart.Series{ countSeries[4], countSeries[5], countSeries[6], countSeries[7], countSeries[8], countSeries[9], countSeries[10], countSeries[11], countSeries[12], countSeries[13], countSeries[14], countSeries[15], countSeries[16], }, } graph5.Elements = []chart.Renderable{chart.LegendThin(&graph5)} buffer = bytes.NewBuffer([]byte{}) err = graph5.Render(chart.PNG, buffer) tool.Check(err) err = os.WriteFile("chart5.png", buffer.Bytes(), 0644) tool.Check(err) } func dbSlice(chaindata string, bucket string, prefix []byte) { db := mdbx.MustOpen(chaindata) defer db.Close() if err := db.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(bucket) if err != nil { return err } for k, v, err := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v, err = c.Next() { if err != nil { return err } fmt.Printf("db.Put([]byte(\"%s\"), common.FromHex(\"%x\"), common.FromHex(\"%x\"))\n", bucket, k, v) } return nil }); err != nil { panic(err) } } func hashFile() { f, err := os.Open("/Users/alexeyakhunov/mygit/go-ethereum/geth.log") tool.Check(err) defer f.Close() w, err := os.Create("/Users/alexeyakhunov/mygit/go-ethereum/geth_read.log") tool.Check(err) defer w.Close() scanner := bufio.NewScanner(f) count := 0 for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "ResolveWithDb") || strings.HasPrefix(line, "Error") || strings.HasPrefix(line, "0000000000000000000000000000000000000000000000000000000000000000") || strings.HasPrefix(line, "ERROR") || strings.HasPrefix(line, "tc{") { fmt.Printf("%d %s\n", count, line) count++ } else if count == 66 { w.WriteString(line) w.WriteString("\n") } } fmt.Printf("%d lines scanned\n", count) } func rlpIndices() { keybuf := new(bytes.Buffer) for i := 0; i < 512; i++ { keybuf.Reset() rlp.Encode(keybuf, uint(i)) fmt.Printf("Encoding of %d is %x\n", i, keybuf.Bytes()) } } func printFullNodeRLPs() { trie.FullNode1() trie.FullNode2() trie.FullNode3() trie.FullNode4() trie.ShortNode1() trie.ShortNode2() trie.Hash1() trie.Hash2() trie.Hash3() trie.Hash4() trie.Hash5() trie.Hash6() trie.Hash7() } // Searches 1000 blocks from the given one to try to find the one with the given state root hash func testBlockHashes(chaindata string, block int, stateRoot common.Hash) { ethDb := mdbx.MustOpen(chaindata) defer ethDb.Close() tool.Check(ethDb.View(context.Background(), func(tx kv.Tx) error { blocksToSearch := 10000000 for i := uint64(block); i < uint64(block+blocksToSearch); i++ { hash, err := rawdb.ReadCanonicalHash(tx, i) if err != nil { panic(err) } header := rawdb.ReadHeader(tx, hash, i) if header.Root == stateRoot || stateRoot == (common.Hash{}) { fmt.Printf("\n===============\nCanonical hash for %d: %x\n", i, hash) fmt.Printf("Header.Root: %x\n", header.Root) fmt.Printf("Header.TxHash: %x\n", header.TxHash) fmt.Printf("Header.UncleHash: %x\n", header.UncleHash) } } return nil })) } func getCurrentBlockNumber(tx kv.Tx) *uint64 { hash := rawdb.ReadHeadBlockHash(tx) if hash == (common.Hash{}) { return nil } return rawdb.ReadHeaderNumber(tx, hash) } func printCurrentBlockNumber(chaindata string) { ethDb := mdbx.MustOpen(chaindata) defer ethDb.Close() ethDb.View(context.Background(), func(tx kv.Tx) error { if number := getCurrentBlockNumber(tx); number != nil { fmt.Printf("Block number: %d\n", *number) } else { fmt.Println("Block number: ") } return nil }) } func printTxHashes(chaindata string, block uint64) error { db := mdbx.MustOpen(chaindata) defer db.Close() if err := db.View(context.Background(), func(tx kv.Tx) error { for b := block; b < block+1; b++ { hash, e := rawdb.ReadCanonicalHash(tx, b) if e != nil { return e } block := rawdb.ReadBlock(tx, hash, b) if block == nil { break } for i, tx := range block.Transactions() { fmt.Printf("%d: %x\n", i, tx.Hash()) } } return nil }); err != nil { return err } return nil } func readTrie(filename string) *trie.Trie { f, err := os.Open(filename) tool.Check(err) defer f.Close() t, err := trie.Load(f) tool.Check(err) return t } func invTree(wrong, right, diff string, name string) { fmt.Printf("Reading trie...\n") t1 := readTrie(fmt.Sprintf("%s_%s.txt", wrong, name)) fmt.Printf("Root hash: %x\n", t1.Hash()) fmt.Printf("Reading trie 2...\n") t2 := readTrie(fmt.Sprintf("%s_%s.txt", right, name)) fmt.Printf("Root hash: %x\n", t2.Hash()) c, err := os.Create(fmt.Sprintf("%s_%s.txt", diff, name)) tool.Check(err) defer c.Close() t1.PrintDiff(t2, c) } func readAccount(chaindata string, account common.Address) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, txErr := db.BeginRo(context.Background()) if txErr != nil { return txErr } defer tx.Rollback() a, err := state.NewPlainStateReader(tx).ReadAccountData(account) if err != nil { return err } else if a == nil { return fmt.Errorf("acc not found") } fmt.Printf("CodeHash:%x\nIncarnation:%d\n", a.CodeHash, a.Incarnation) c, err := tx.Cursor(kv.PlainState) if err != nil { return err } for k, v, e := c.Seek(account.Bytes()); k != nil && e == nil; k, v, e = c.Next() { if e != nil { return e } if !bytes.HasPrefix(k, account.Bytes()) { break } fmt.Printf("%x => %x\n", k, v) } return nil } func nextIncarnation(chaindata string, addrHash common.Hash) { ethDb := mdbx.MustOpen(chaindata) defer ethDb.Close() var found bool var incarnationBytes [common.IncarnationLength]byte startkey := make([]byte, common.HashLength+common.IncarnationLength+common.HashLength) var fixedbits = 8 * common.HashLength copy(startkey, addrHash[:]) tool.Check(ethDb.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(kv.HashedStorage) if err != nil { return err } defer c.Close() return ethdb.Walk(c, startkey, fixedbits, func(k, v []byte) (bool, error) { fmt.Printf("Incarnation(z): %d\n", 0) copy(incarnationBytes[:], k[common.HashLength:]) found = true return false, nil }) })) if found { fmt.Printf("Incarnation: %d\n", (binary.BigEndian.Uint64(incarnationBytes[:]))+1) return } fmt.Printf("Incarnation(f): %d\n", state.FirstContractIncarnation) } func repairCurrent() { historyDb := mdbx.MustOpen("/Volumes/tb4/erigon/ropsten/geth/chaindata") defer historyDb.Close() currentDb := mdbx.MustOpen("statedb") defer currentDb.Close() tool.Check(historyDb.Update(context.Background(), func(tx kv.RwTx) error { return tx.ClearBucket(kv.HashedStorage) })) tool.Check(historyDb.Update(context.Background(), func(tx kv.RwTx) error { newB, err := tx.RwCursor(kv.HashedStorage) if err != nil { return err } count := 0 if err := currentDb.View(context.Background(), func(ctx kv.Tx) error { c, err := ctx.Cursor(kv.HashedStorage) if err != nil { return err } for k, v, err := c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } tool.Check(newB.Put(k, v)) count++ if count == 10000 { fmt.Printf("Copied %d storage items\n", count) } } return nil }); err != nil { return err } return nil })) } func dumpStorage() { db := mdbx.MustOpen(paths.DefaultDataDir() + "/geth/chaindata") defer db.Close() if err := db.View(context.Background(), func(tx kv.Tx) error { return tx.ForEach(kv.StorageHistory, nil, func(k, v []byte) error { fmt.Printf("%x %x\n", k, v) return nil }) }); err != nil { panic(err) } } func printBucket(chaindata string) { db := mdbx.MustOpen(chaindata) defer db.Close() f, err := os.Create("bucket.txt") tool.Check(err) defer f.Close() fb := bufio.NewWriter(f) defer fb.Flush() if err := db.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(kv.StorageHistory) if err != nil { return err } for k, v, err := c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } fmt.Fprintf(fb, "%x %x\n", k, v) } return nil }); err != nil { panic(err) } } func ValidateTxLookups2(chaindata string) { db := mdbx.MustOpen(chaindata) defer db.Close() startTime := time.Now() sigs := make(chan os.Signal, 1) interruptCh := make(chan bool, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) go func() { <-sigs interruptCh <- true }() var blockNum uint64 = 1 validateTxLookups2(db, blockNum, interruptCh) log.Info("All done", "duration", time.Since(startTime)) } func validateTxLookups2(db kv.RwDB, startBlock uint64, interruptCh chan bool) { tx, err := db.BeginRo(context.Background()) if err != nil { panic(err) } defer tx.Rollback() blockNum := startBlock iterations := 0 var interrupt bool // Validation Process blockBytes := big.NewInt(0) for !interrupt { blockHash, err := rawdb.ReadCanonicalHash(tx, blockNum) tool.Check(err) body := rawdb.ReadCanonicalBodyWithTransactions(tx, blockHash, blockNum) if body == nil { break } select { case interrupt = <-interruptCh: log.Info("interrupted, please wait for cleanup...") default: } blockBytes.SetUint64(blockNum) bn := blockBytes.Bytes() for _, txn := range body.Transactions { val, err := tx.GetOne(kv.TxLookup, txn.Hash().Bytes()) iterations++ if iterations%100000 == 0 { log.Info("Validated", "entries", iterations, "number", blockNum) } if !bytes.Equal(val, bn) { tool.Check(err) panic(fmt.Sprintf("Validation process failed(%d). Expected %b, got %b", iterations, bn, val)) } } blockNum++ } } type Receiver struct { defaultReceiver *trie.RootHashAggregator accountMap map[string]*accounts.Account storageMap map[string][]byte unfurlList []string currentIdx int } func (r *Receiver) Root() common.Hash { panic("don't call me") } func (r *Receiver) Receive( itemType trie.StreamItem, accountKey []byte, storageKey []byte, accountValue *accounts.Account, storageValue []byte, hash []byte, hasTree bool, cutoff int, ) error { for r.currentIdx < len(r.unfurlList) { ks := r.unfurlList[r.currentIdx] k := []byte(ks) var c int switch itemType { case trie.StorageStreamItem, trie.SHashStreamItem: c = bytes.Compare(k, storageKey) case trie.AccountStreamItem, trie.AHashStreamItem: c = bytes.Compare(k, accountKey) case trie.CutoffStreamItem: c = -1 } if c > 0 { return r.defaultReceiver.Receive(itemType, accountKey, storageKey, accountValue, storageValue, hash, hasTree, cutoff) } if len(k) > common.HashLength { v := r.storageMap[ks] if len(v) > 0 { if err := r.defaultReceiver.Receive(trie.StorageStreamItem, nil, k, nil, v, nil, hasTree, 0); err != nil { return err } } } else { v := r.accountMap[ks] if v != nil { if err := r.defaultReceiver.Receive(trie.AccountStreamItem, k, nil, v, nil, nil, hasTree, 0); err != nil { return err } } } r.currentIdx++ if c == 0 { return nil } } // We ran out of modifications, simply pass through return r.defaultReceiver.Receive(itemType, accountKey, storageKey, accountValue, storageValue, hash, hasTree, cutoff) } func (r *Receiver) Result() trie.SubTries { return r.defaultReceiver.Result() } func regenerate(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() tool.Check(stagedsync.ResetIH(tx)) to, err := stages.GetStageProgress(tx, stages.HashState) if err != nil { return err } hash, err := rawdb.ReadCanonicalHash(tx, to) if err != nil { return err } syncHeadHeader := rawdb.ReadHeader(tx, hash, to) expectedRootHash := syncHeadHeader.Root blockReader := snapshotsync.NewBlockReader() _, err = stagedsync.RegenerateIntermediateHashes("", tx, stagedsync.StageTrieCfg(db, true, true, "", blockReader), expectedRootHash, nil) tool.Check(err) log.Info("Regeneration ended") return tx.Commit() } func testGetProof(chaindata string, address common.Address, rewind int, regen bool) error { if regen { if err := regenerate(chaindata); err != nil { return err } } storageKeys := []string{} var m runtime.MemStats runtime.ReadMemStats(&m) db := mdbx.MustOpen(chaindata) defer db.Close() tx, err1 := db.BeginRo(context.Background()) if err1 != nil { return err1 } defer tx.Rollback() headHash := rawdb.ReadHeadBlockHash(tx) headNumber := rawdb.ReadHeaderNumber(tx, headHash) block := *headNumber - uint64(rewind) log.Info("GetProof", "address", address, "storage keys", len(storageKeys), "head", *headNumber, "block", block, "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) accountMap := make(map[string]*accounts.Account) if err := changeset.ForRange(tx, kv.AccountChangeSet, block+1, *headNumber+1, func(blockN uint64, address, v []byte) error { var addrHash, err = common.HashData(address) if err != nil { return err } k := addrHash[:] if _, ok := accountMap[string(k)]; !ok { if len(v) > 0 { var a accounts.Account if innerErr := a.DecodeForStorage(v); innerErr != nil { return innerErr } accountMap[string(k)] = &a } else { accountMap[string(k)] = nil } } return nil }); err != nil { return err } runtime.ReadMemStats(&m) log.Info("Constructed account map", "size", len(accountMap), "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) storageMap := make(map[string][]byte) if err := changeset.ForRange(tx, kv.StorageChangeSet, block+1, *headNumber+1, func(blockN uint64, address, v []byte) error { var addrHash, err = common.HashData(address) if err != nil { return err } k := addrHash[:] if _, ok := storageMap[string(k)]; !ok { storageMap[string(k)] = v } return nil }); err != nil { return err } runtime.ReadMemStats(&m) log.Info("Constructed storage map", "size", len(storageMap), "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) var unfurlList = make([]string, len(accountMap)+len(storageMap)) unfurl := trie.NewRetainList(0) i := 0 for ks, acc := range accountMap { unfurlList[i] = ks i++ unfurl.AddKey([]byte(ks)) if acc != nil { // Fill the code hashes if acc.Incarnation > 0 && acc.IsEmptyCodeHash() { if codeHash, err1 := tx.GetOne(kv.ContractCode, dbutils.GenerateStoragePrefix([]byte(ks), acc.Incarnation)); err1 == nil { copy(acc.CodeHash[:], codeHash) } else { return err1 } } } } for ks := range storageMap { unfurlList[i] = ks i++ unfurl.AddKey([]byte(ks)) } rl := trie.NewRetainList(0) addrHash, err := common.HashData(address[:]) if err != nil { return err } rl.AddKey(addrHash[:]) unfurl.AddKey(addrHash[:]) for _, key := range storageKeys { keyAsHash := common.HexToHash(key) if keyHash, err1 := common.HashData(keyAsHash[:]); err1 == nil { //TODO Add incarnation in the middle of this trieKey := append(addrHash[:], keyHash[:]...) rl.AddKey(trieKey) unfurl.AddKey(trieKey) } else { return err1 } } slices.Sort(unfurlList) runtime.ReadMemStats(&m) log.Info("Constructed account unfurl lists", "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) loader := trie.NewFlatDBTrieLoader("checkRoots") if err = loader.Reset(unfurl, nil, nil, false); err != nil { panic(err) } _, err = loader.CalcTrieRoot(tx, nil, nil) if err != nil { return err } r := &Receiver{defaultReceiver: trie.NewRootHashAggregator(), unfurlList: unfurlList, accountMap: accountMap, storageMap: storageMap} r.defaultReceiver.Reset(nil, nil /* HashCollector */, false) loader.SetStreamReceiver(r) root, err := loader.CalcTrieRoot(tx, nil, nil) if err != nil { return err } runtime.ReadMemStats(&m) log.Info("Loaded subtries", "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) hash, err := rawdb.ReadCanonicalHash(tx, block) tool.Check(err) header := rawdb.ReadHeader(tx, hash, block) runtime.ReadMemStats(&m) log.Info("Constructed trie", "alloc", libcommon.ByteCount(m.Alloc), "sys", libcommon.ByteCount(m.Sys)) fmt.Printf("Resulting root: %x, expected root: %x\n", root, header.Root) return nil } // dumpState writes the content of current state into a file with given name func dumpState(chaindata string, block int, name string) error { db := mdbx.MustOpen(chaindata) defer db.Close() fa, err := os.Create(name + ".accounts.dat") if err != nil { return err } defer fa.Close() wa := bufio.NewWriterSize(fa, etl.BufIOSize) // Write out number of key/value pairs first var countBytes [8]byte binary.BigEndian.PutUint64(countBytes[:], 0) // TODO: Write correct number or remove if _, err = wa.Write(countBytes[:]); err != nil { return err } defer wa.Flush() var fs, fc *os.File if fs, err = os.Create(name + ".storage.dat"); err != nil { return err } defer fs.Close() ws := bufio.NewWriterSize(fs, etl.BufIOSize) binary.BigEndian.PutUint64(countBytes[:], 0) // TODO: Write correct number or remove if _, err = ws.Write(countBytes[:]); err != nil { return err } defer ws.Flush() if fc, err = os.Create(name + ".code.dat"); err != nil { return err } defer fc.Close() wc := bufio.NewWriterSize(fc, etl.BufIOSize) binary.BigEndian.PutUint64(countBytes[:], 0) // TODO: Write correct number or remove if _, err = wc.Write(countBytes[:]); err != nil { return err } defer wc.Flush() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() var sc kv.Cursor if sc, err = tx.Cursor(kv.PlainState); err != nil { return err } defer sc.Close() var cc kv.Cursor if cc, err = tx.Cursor(kv.PlainContractCode); err != nil { return err } defer cc.Close() i := 0 numBuf := make([]byte, binary.MaxVarintLen64) k, v, e := sc.First() var a accounts.Account var addr common.Address var ks [20 + 32]byte for ; k != nil && e == nil; k, v, e = sc.Next() { if len(k) == 20 { n := binary.PutUvarint(numBuf, uint64(len(k))) if _, err = wa.Write(numBuf[:n]); err != nil { return err } if _, err = wa.Write(k); err != nil { return err } n = binary.PutUvarint(numBuf, uint64(len(v))) if _, err = wa.Write(numBuf[:n]); err != nil { return err } if len(v) > 0 { if _, err = wa.Write(v); err != nil { return err } } if err = a.DecodeForStorage(v); err != nil { return err } if a.CodeHash != trie.EmptyCodeHash { code, err := tx.GetOne(kv.Code, a.CodeHash[:]) if err != nil { return err } if len(code) != 0 { n = binary.PutUvarint(numBuf, uint64(len(k))) if _, err = wc.Write(numBuf[:n]); err != nil { return err } if _, err = wc.Write(k); err != nil { return err } n = binary.PutUvarint(numBuf, uint64(len(code))) if _, err = wc.Write(numBuf[:n]); err != nil { return err } if len(code) > 0 { if _, err = wc.Write(code); err != nil { return err } } i += 2 if i%10_000_000 == 0 { log.Info("Written into file", "millions", i/1_000_000) } } } copy(addr[:], k) i += 2 if i%10_000_000 == 0 { log.Info("Written into file", "millions", i/1_000_000) } } if len(k) == 60 { inc := binary.BigEndian.Uint64(k[20:]) if bytes.Equal(k[:20], addr[:]) && inc == a.Incarnation { copy(ks[:], k[:20]) copy(ks[20:], k[20+8:]) n := binary.PutUvarint(numBuf, uint64(len(ks))) if _, err = ws.Write(numBuf[:n]); err != nil { return err } if _, err = ws.Write(ks[:]); err != nil { return err } n = binary.PutUvarint(numBuf, uint64(len(v))) if _, err = ws.Write(numBuf[:n]); err != nil { return err } if len(v) > 0 { if _, err = ws.Write(v); err != nil { return err } } i += 2 if i%10_000_000 == 0 { log.Info("Written into file", "millions", i/1_000_000) } } } } if e != nil { return e } return nil } func mphf(chaindata string, block int) error { // Create a file to compress if it does not exist already statefile := "statedump.dat" if _, err := os.Stat(statefile); err != nil { if !os.IsNotExist(err) { return fmt.Errorf("not sure if statedump.dat exists: %w", err) } if err = dumpState(chaindata, int(block), "statefile"); err != nil { return err } } var rs *recsplit.RecSplit f, err := os.Open(statefile) if err != nil { return err } r := bufio.NewReaderSize(f, etl.BufIOSize) defer f.Close() var countBuf [8]byte if _, err = io.ReadFull(r, countBuf[:]); err != nil { return err } count := binary.BigEndian.Uint64(countBuf[:]) if rs, err = recsplit.NewRecSplit(recsplit.RecSplitArgs{ KeyCount: int(count), BucketSize: 2000, Salt: 1, LeafSize: 8, TmpDir: "", StartSeed: []uint64{0x106393c187cae21a, 0x6453cec3f7376937, 0x643e521ddbd2be98, 0x3740c6412f6572cb, 0x717d47562f1ce470, 0x4cd6eb4c63befb7c, 0x9bfd8c5e18c8da73, 0x082f20e10092a9a3, 0x2ada2ce68d21defc, 0xe33cb4f3e7c6466b, 0x3980be458c509c59, 0xc466fd9584828e8c, 0x45f0aabe1a61ede6, 0xf6e7b8b33ad9b98d, 0x4ef95e25f4b4983d, 0x81175195173b92d3, 0x4e50927d8dd15978, 0x1ea2099d1fafae7f, 0x425c8a06fbaaa815, 0xcd4216006c74052a}, IndexFile: "state.idx", }); err != nil { return err } var buf [256]byte l, e := r.ReadByte() i := 0 for ; e == nil; l, e = r.ReadByte() { if _, e = io.ReadFull(r, buf[:l]); e != nil { return e } if i%2 == 0 { // It is key, we skip the values here if err := rs.AddKey(buf[:l], uint64(i/2)); err != nil { return err } } i++ if i == int(count*2) { break } } if e != nil && !errors.Is(e, io.EOF) { return e } start := time.Now() log.Info("Building recsplit...") if err = rs.Build(); err != nil { return err } s1, s2 := rs.Stats() log.Info("Done", "time", time.Since(start), "s1", s1, "s2", s2) idx := recsplit.MustOpen("state.idx") defer idx.Close() log.Info("Testing bijection") bitCount := (count + 63) / 64 bits := make([]uint64, bitCount) if _, err = f.Seek(8, 0); err != nil { return err } r = bufio.NewReaderSize(f, etl.BufIOSize) l, e = r.ReadByte() i = 0 var lookupTime time.Duration idxReader := recsplit.NewIndexReader(idx) for ; e == nil; l, e = r.ReadByte() { if _, e = io.ReadFull(r, buf[:l]); e != nil { return e } if i%2 == 0 { // It is key, we skip the values here start := time.Now() offset := idxReader.Lookup(buf[:l]) lookupTime += time.Since(start) if offset >= count { return fmt.Errorf("idx %d >= count %d", offset, count) } mask := uint64(1) << (offset & 63) if bits[offset>>6]&mask != 0 { return fmt.Errorf("no bijection key idx=%d, lookup up idx = %d", i, offset) } bits[offset>>6] |= mask } i++ if i == int(count*2) { break } } if e != nil && !errors.Is(e, io.EOF) { return e } log.Info("Average lookup time", "per key", time.Duration(uint64(lookupTime)/count)) return nil } // genstate generates statedump.dat file for testing func genstate() error { f, err := os.Create("statedump.dat") if err != nil { return err } defer f.Close() w := bufio.NewWriterSize(f, etl.BufIOSize) defer w.Flush() var count uint64 = 25 var countBuf [8]byte binary.BigEndian.PutUint64(countBuf[:], count) if _, err = w.Write(countBuf[:]); err != nil { return err } for i := 0; i < 5; i++ { for j := 0; j < 5; j++ { key := fmt.Sprintf("addr%dxlocation%d", i, j) val := "value" if err = w.WriteByte(byte(len(key))); err != nil { return err } if _, err = w.Write([]byte(key)); err != nil { return err } if err = w.WriteByte(byte(len(val))); err != nil { return err } if _, err = w.Write([]byte(val)); err != nil { return err } } } return nil } func compress1(fileName, segmentFileName string) error { compressor, err := compress.NewCompressor(context.Background(), "", segmentFileName, "", compress.MinPatternScore, runtime.GOMAXPROCS(-1), log.LvlDebug) if err != nil { return err } defer compressor.Close() if err := compress.ReadSimpleFile(fileName, func(v []byte) error { return compressor.AddWord(v) }); err != nil { return err } return compressor.Compress() } func decompress(name string) error { return parallelcompress.Decompress("hack", name+".seg", name+".decompressed.dat") } func changeSetStats(chaindata string, block1, block2 uint64) error { db := mdbx.MustOpen(chaindata) defer db.Close() fmt.Printf("State stats\n") stAccounts := 0 stStorage := 0 if err := db.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(kv.PlainState) if err != nil { return err } k, _, e := c.First() for ; k != nil && e == nil; k, _, e = c.Next() { if len(k) > 28 { stStorage++ } else { stAccounts++ } if (stStorage+stAccounts)%100000 == 0 { fmt.Printf("State records: %d\n", stStorage+stAccounts) } } return e }); err != nil { return err } fmt.Printf("stAccounts = %d, stStorage = %d\n", stAccounts, stStorage) fmt.Printf("Changeset stats from %d to %d\n", block1, block2) accounts := make(map[string]struct{}) tx, err1 := db.BeginRw(context.Background()) if err1 != nil { return err1 } defer tx.Rollback() if err := changeset.ForRange(tx, kv.AccountChangeSet, block1, block2, func(blockN uint64, k, v []byte) error { if (blockN-block1)%100000 == 0 { fmt.Printf("at the block %d for accounts, booster size: %d\n", blockN, len(accounts)) } accounts[string(common.CopyBytes(k))] = struct{}{} return nil }); err != nil { return err } storage := make(map[string]struct{}) if err := changeset.ForRange(tx, kv.StorageChangeSet, block1, block2, func(blockN uint64, k, v []byte) error { if (blockN-block1)%100000 == 0 { fmt.Printf("at the block %d for accounts, booster size: %d\n", blockN, len(accounts)) } storage[string(common.CopyBytes(k))] = struct{}{} return nil }); err != nil { return err } fmt.Printf("accounts changed: %d, storage changed: %d\n", len(accounts), len(storage)) return nil } func searchChangeSet(chaindata string, key []byte, block uint64) error { fmt.Printf("Searching changesets\n") db := mdbx.MustOpen(chaindata) defer db.Close() tx, err1 := db.BeginRw(context.Background()) if err1 != nil { return err1 } defer tx.Rollback() if err := changeset.ForEach(tx, kv.AccountChangeSet, dbutils.EncodeBlockNumber(block), func(blockN uint64, k, v []byte) error { if bytes.Equal(k, key) { fmt.Printf("Found in block %d with value %x\n", blockN, v) } return nil }); err != nil { return err } return nil } func searchStorageChangeSet(chaindata string, key []byte, block uint64) error { fmt.Printf("Searching storage changesets\n") db := mdbx.MustOpen(chaindata) defer db.Close() tx, err1 := db.BeginRw(context.Background()) if err1 != nil { return err1 } defer tx.Rollback() if err := changeset.ForEach(tx, kv.StorageChangeSet, dbutils.EncodeBlockNumber(block), func(blockN uint64, k, v []byte) error { if bytes.Equal(k, key) { fmt.Printf("Found in block %d with value %x\n", blockN, v) } return nil }); err != nil { return err } return nil } func supply(chaindata string) error { startTime := time.Now() db := mdbx.MustOpen(chaindata) defer db.Close() count := 0 supply := uint256.NewInt(0) var a accounts.Account if err := db.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(kv.PlainState) if err != nil { return err } for k, v, err := c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } if len(k) != 20 { continue } if err1 := a.DecodeForStorage(v); err1 != nil { return err1 } count++ supply.Add(supply, &a.Balance) if count%100000 == 0 { fmt.Printf("Processed %dK account records\n", count/1000) } } return nil }); err != nil { return err } fmt.Printf("Total accounts: %d, supply: %d, took: %s\n", count, supply, time.Since(startTime)) return nil } func extractCode(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() var contractCount int if err1 := db.View(context.Background(), func(tx kv.Tx) error { c, err := tx.Cursor(kv.Code) if err != nil { return err } // This is a mapping of CodeHash => Byte code for k, v, err := c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } fmt.Printf("%x,%x", k, v) contractCount++ } return nil }); err1 != nil { return err1 } fmt.Fprintf(os.Stderr, "contractCount: %d\n", contractCount) return nil } func iterateOverCode(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() hashes := make(map[common.Hash][]byte) if err1 := db.View(context.Background(), func(tx kv.Tx) error { // This is a mapping of CodeHash => Byte code if err := tx.ForEach(kv.Code, nil, func(k, v []byte) error { if len(v) > 0 && v[0] == 0xef { fmt.Printf("Found code with hash %x: %x\n", k, v) hashes[common.BytesToHash(k)] = common.CopyBytes(v) } return nil }); err != nil { return err } // This is a mapping of contractAddress + incarnation => CodeHash if err := tx.ForEach(kv.PlainContractCode, nil, func(k, v []byte) error { hash := common.BytesToHash(v) if code, ok := hashes[hash]; ok { fmt.Printf("address: %x: %x\n", k[:20], code) } return nil }); err != nil { return err } return nil }); err1 != nil { return err1 } return nil } func mint(chaindata string, block uint64) error { f, err := os.Create("mint.csv") if err != nil { return err } defer f.Close() w := bufio.NewWriter(f) defer w.Flush() db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() //chiTokenAddr = common.HexToAddress("0x0000000000004946c0e9F43F4Dee607b0eF1fA1c") //mintFuncPrefix = common.FromHex("0xa0712d68") var gwei uint256.Int gwei.SetUint64(1000000000) blockEncoded := dbutils.EncodeBlockNumber(block) canonical := make(map[common.Hash]struct{}) c, err := tx.Cursor(kv.HeaderCanonical) if err != nil { return err } // This is a mapping of contractAddress + incarnation => CodeHash for k, v, err := c.Seek(blockEncoded); k != nil; k, v, err = c.Next() { if err != nil { return err } // Skip non relevant records canonical[common.BytesToHash(v)] = struct{}{} if len(canonical)%100_000 == 0 { log.Info("Read canonical hashes", "count", len(canonical)) } } log.Info("Read canonical hashes", "count", len(canonical)) c, err = tx.Cursor(kv.BlockBody) if err != nil { return err } var prevBlock uint64 var burntGas uint64 for k, _, err := c.Seek(blockEncoded); k != nil; k, _, err = c.Next() { if err != nil { return err } blockNumber := binary.BigEndian.Uint64(k[:8]) blockHash := common.BytesToHash(k[8:]) if _, isCanonical := canonical[blockHash]; !isCanonical { continue } if blockNumber != prevBlock && blockNumber != prevBlock+1 { fmt.Printf("Gap [%d-%d]\n", prevBlock, blockNumber-1) } prevBlock = blockNumber body := rawdb.ReadCanonicalBodyWithTransactions(tx, blockHash, blockNumber) header := rawdb.ReadHeader(tx, blockHash, blockNumber) senders, errSenders := rawdb.ReadSenders(tx, blockHash, blockNumber) if errSenders != nil { return errSenders } var ethSpent uint256.Int var ethSpentTotal uint256.Int var totalGas uint256.Int count := 0 for i, tx := range body.Transactions { ethSpent.SetUint64(tx.GetGas()) totalGas.Add(&totalGas, ðSpent) if senders[i] == header.Coinbase { continue // Mining pool sending payout potentially with abnormally low fee, skip } ethSpent.Mul(ðSpent, tx.GetPrice()) ethSpentTotal.Add(ðSpentTotal, ðSpent) count++ } if count > 0 { ethSpentTotal.Div(ðSpentTotal, &totalGas) ethSpentTotal.Div(ðSpentTotal, &gwei) gasPrice := ethSpentTotal.Uint64() burntGas += header.GasUsed fmt.Fprintf(w, "%d, %d\n", burntGas, gasPrice) } if blockNumber%100_000 == 0 { log.Info("Processed", "blocks", blockNumber) } } return tx.Commit() } func getBlockTotal(tx kv.Tx, blockFrom uint64, blockTotalOrOffset int64) uint64 { if blockTotalOrOffset > 0 { return uint64(blockTotalOrOffset) } if head := getCurrentBlockNumber(tx); head != nil { if blockSub := uint64(-blockTotalOrOffset); blockSub <= *head { if blockEnd := *head - blockSub; blockEnd > blockFrom { return blockEnd - blockFrom + 1 } } } return 1 } func extractHashes(chaindata string, blockStep uint64, blockTotalOrOffset int64, name string) error { db := mdbx.MustOpen(chaindata) defer db.Close() f, err := os.Create(fmt.Sprintf("preverified_hashes_%s.go", name)) if err != nil { return err } defer f.Close() w := bufio.NewWriter(f) defer w.Flush() fmt.Fprintf(w, "package headerdownload\n\n") fmt.Fprintf(w, "var %sPreverifiedHashes = []string{\n", name) b := uint64(0) tool.Check(db.View(context.Background(), func(tx kv.Tx) error { blockTotal := getBlockTotal(tx, b, blockTotalOrOffset) // Note: blockTotal used here as block number rather than block count for b <= blockTotal { hash, err := rawdb.ReadCanonicalHash(tx, b) if err != nil { return err } if hash == (common.Hash{}) { break } fmt.Fprintf(w, " \"%x\",\n", hash) b += blockStep } return nil })) b -= blockStep fmt.Fprintf(w, "}\n\n") fmt.Fprintf(w, "const %sPreverifiedHeight uint64 = %d\n", name, b) fmt.Printf("Last block is %d\n", b) return nil } func extractHeaders(chaindata string, block uint64, blockTotalOrOffset int64) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() c, err := tx.Cursor(kv.Headers) if err != nil { return err } defer c.Close() blockEncoded := dbutils.EncodeBlockNumber(block) blockTotal := getBlockTotal(tx, block, blockTotalOrOffset) for k, v, err := c.Seek(blockEncoded); k != nil && blockTotal > 0; k, v, err = c.Next() { if err != nil { return err } blockNumber := binary.BigEndian.Uint64(k[:8]) blockHash := common.BytesToHash(k[8:]) var header types.Header if err = rlp.DecodeBytes(v, &header); err != nil { return fmt.Errorf("decoding header from %x: %w", v, err) } fmt.Printf("Header %d %x: stateRoot %x, parentHash %x, diff %d\n", blockNumber, blockHash, header.Root, header.ParentHash, header.Difficulty) blockTotal-- } return nil } func extractBodies(chaindata string, block uint64) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() c, err := tx.Cursor(kv.BlockBody) if err != nil { return err } defer c.Close() blockEncoded := dbutils.EncodeBlockNumber(block) i := 0 for k, _, err := c.Seek(blockEncoded); k != nil; k, _, err = c.Next() { if err != nil { return err } blockNumber := binary.BigEndian.Uint64(k[:8]) blockHash := common.BytesToHash(k[8:]) _, baseTxId, txAmount := rawdb.ReadBody(tx, blockHash, blockNumber) fmt.Printf("Body %d %x: baseTxId %d, txAmount %d\n", blockNumber, blockHash, baseTxId, txAmount) i++ if i == 1 { break } } return nil } func fixUnwind(chaindata string) error { contractAddr := common.HexToAddress("0x577a32aa9c40cf4266e49fc1e44c749c356309bd") db := mdbx.MustOpen(chaindata) defer db.Close() tool.Check(db.Update(context.Background(), func(tx kv.RwTx) error { i, err := tx.GetOne(kv.IncarnationMap, contractAddr[:]) if err != nil { return err } else if i == nil { fmt.Print("Not found\n") var b [8]byte binary.BigEndian.PutUint64(b[:], 1) if err = tx.Put(kv.IncarnationMap, contractAddr[:], b[:]); err != nil { return err } } else { fmt.Printf("Inc: %x\n", i) } return nil })) return nil } func snapSizes(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() c, _ := tx.Cursor(kv.CliqueSeparate) defer c.Close() sizes := make(map[int]int) differentValues := make(map[string]struct{}) var ( total uint64 k, v []byte ) for k, v, err = c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } sizes[len(v)]++ differentValues[string(v)] = struct{}{} total += uint64(len(v) + len(k)) } var lens = make([]int, len(sizes)) i := 0 for l := range sizes { lens[i] = l i++ } slices.Sort(lens) for _, l := range lens { fmt.Printf("%6d - %d\n", l, sizes[l]) } fmt.Printf("Different keys %d\n", len(differentValues)) fmt.Printf("Total size: %d bytes\n", total) return nil } func readCallTraces(chaindata string, block uint64) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() traceCursor, err1 := tx.RwCursorDupSort(kv.CallTraceSet) if err1 != nil { return err1 } defer traceCursor.Close() var k []byte var v []byte count := 0 for k, v, err = traceCursor.First(); k != nil; k, v, err = traceCursor.Next() { if err != nil { return err } blockNum := binary.BigEndian.Uint64(k) if blockNum == block { fmt.Printf("%x\n", v) } count++ } fmt.Printf("Found %d records\n", count) idxCursor, err2 := tx.Cursor(kv.CallToIndex) if err2 != nil { return err2 } var acc = common.HexToAddress("0x511bc4556d823ae99630ae8de28b9b80df90ea2e") for k, v, err = idxCursor.Seek(acc[:]); k != nil && err == nil && bytes.HasPrefix(k, acc[:]); k, v, err = idxCursor.Next() { bm := roaring64.New() _, err = bm.ReadFrom(bytes.NewReader(v)) if err != nil { return err } //fmt.Printf("%x: %d\n", k, bm.ToArray()) } if err != nil { return err } return nil } func fixTd(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() c, err1 := tx.RwCursor(kv.Headers) if err1 != nil { return err1 } defer c.Close() var k, v []byte for k, v, err = c.First(); err == nil && k != nil; k, v, err = c.Next() { hv, herr := tx.GetOne(kv.HeaderTD, k) if herr != nil { return herr } if hv == nil { fmt.Printf("Missing TD record for %x, fixing\n", k) var header types.Header if err = rlp.DecodeBytes(v, &header); err != nil { return fmt.Errorf("decoding header from %x: %w", v, err) } if header.Number.Uint64() == 0 { continue } var parentK [40]byte binary.BigEndian.PutUint64(parentK[:], header.Number.Uint64()-1) copy(parentK[8:], header.ParentHash[:]) var parentTdRec []byte if parentTdRec, err = tx.GetOne(kv.HeaderTD, parentK[:]); err != nil { return fmt.Errorf("reading parentTd Rec for %d: %w", header.Number.Uint64(), err) } var parentTd big.Int if err = rlp.DecodeBytes(parentTdRec, &parentTd); err != nil { return fmt.Errorf("decoding parent Td record for block %d, from %x: %w", header.Number.Uint64(), parentTdRec, err) } var td big.Int td.Add(&parentTd, header.Difficulty) var newHv []byte if newHv, err = rlp.EncodeToBytes(&td); err != nil { return fmt.Errorf("encoding td record for block %d: %w", header.Number.Uint64(), err) } if err = tx.Put(kv.HeaderTD, k, newHv); err != nil { return err } } } if err != nil { return err } return tx.Commit() } func advanceExec(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() stageExec, err := stages.GetStageProgress(tx, stages.Execution) if err != nil { return err } log.Info("ID exec", "progress", stageExec) if err = stages.SaveStageProgress(tx, stages.Execution, stageExec+1); err != nil { return err } stageExec, err = stages.GetStageProgress(tx, stages.Execution) if err != nil { return err } log.Info("ID exec", "changed to", stageExec) if err = tx.Commit(); err != nil { return err } return nil } func backExec(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() stageExec, err := stages.GetStageProgress(tx, stages.Execution) if err != nil { return err } log.Info("ID exec", "progress", stageExec) if err = stages.SaveStageProgress(tx, stages.Execution, stageExec-1); err != nil { return err } stageExec, err = stages.GetStageProgress(tx, stages.Execution) if err != nil { return err } log.Info("ID exec", "changed to", stageExec) if err = tx.Commit(); err != nil { return err } return nil } func fixState(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() c, err1 := tx.RwCursor(kv.HeaderCanonical) if err1 != nil { return err1 } defer c.Close() var prevHeaderKey [40]byte var k, v []byte for k, v, err = c.First(); err == nil && k != nil; k, v, err = c.Next() { var headerKey [40]byte copy(headerKey[:], k) copy(headerKey[8:], v) hv, herr := tx.GetOne(kv.Headers, headerKey[:]) if herr != nil { return herr } if hv == nil { return fmt.Errorf("missing header record for %x", headerKey) } var header types.Header if err = rlp.DecodeBytes(hv, &header); err != nil { return fmt.Errorf("decoding header from %x: %w", v, err) } if header.Number.Uint64() > 1 { var parentK [40]byte binary.BigEndian.PutUint64(parentK[:], header.Number.Uint64()-1) copy(parentK[8:], header.ParentHash[:]) if !bytes.Equal(parentK[:], prevHeaderKey[:]) { fmt.Printf("broken ancestry from %d %x (parent hash %x): prevKey %x\n", header.Number.Uint64(), v, header.ParentHash, prevHeaderKey) } } copy(prevHeaderKey[:], headerKey[:]) } if err != nil { return err } return tx.Commit() } func trimTxs(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() lastTxId, err := tx.ReadSequence(kv.EthTx) if err != nil { return err } txs, err1 := tx.RwCursor(kv.EthTx) if err1 != nil { return err1 } defer txs.Close() bodies, err2 := tx.Cursor(kv.BlockBody) if err2 != nil { return err } defer bodies.Close() toDelete := roaring64.New() toDelete.AddRange(0, lastTxId) // Exclude transaction that are used, from the range for k, v, err := bodies.First(); k != nil; k, v, err = bodies.Next() { if err != nil { return err } var body types.BodyForStorage if err = rlp.DecodeBytes(v, &body); err != nil { return err } // Remove from the map toDelete.RemoveRange(body.BaseTxId, body.BaseTxId+uint64(body.TxAmount)) } fmt.Printf("Number of tx records to delete: %d\n", toDelete.GetCardinality()) // Takes 20min to iterate 1.4b toDelete2 := roaring64.New() var iterated int for k, _, err := txs.First(); k != nil; k, _, err = txs.Next() { if err != nil { return err } toDelete2.Add(binary.BigEndian.Uint64(k)) iterated++ if iterated%100_000_000 == 0 { fmt.Printf("Iterated %d\n", iterated) } } fmt.Printf("Number of tx records: %d\n", toDelete2.GetCardinality()) toDelete.And(toDelete2) fmt.Printf("Number of tx records to delete: %d\n", toDelete.GetCardinality()) fmt.Printf("Roaring size: %d\n", toDelete.GetSizeInBytes()) iter := toDelete.Iterator() for { var deleted int for iter.HasNext() { txId := iter.Next() var key [8]byte binary.BigEndian.PutUint64(key[:], txId) if err = txs.Delete(key[:], nil); err != nil { return err } deleted++ if deleted >= 10_000_000 { break } } if deleted == 0 { fmt.Printf("Nothing more to delete\n") break } fmt.Printf("Committing after deleting %d records\n", deleted) if err = tx.Commit(); err != nil { return err } txs.Close() tx, err = db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() txs, err = tx.RwCursor(kv.EthTx) if err != nil { return err } defer txs.Close() } return nil } func scanTxs(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() c, err := tx.Cursor(kv.EthTx) if err != nil { return err } defer c.Close() trTypes := make(map[byte]int) trTypesAl := make(map[byte]int) for k, v, err := c.First(); k != nil; k, v, err = c.Next() { if err != nil { return err } var tr types.Transaction if tr, err = types.DecodeTransaction(rlp.NewStream(bytes.NewReader(v), 0)); err != nil { return err } if _, ok := trTypes[tr.Type()]; !ok { fmt.Printf("Example for type %d:\n%x\n", tr.Type(), v) } trTypes[tr.Type()]++ if tr.GetAccessList().StorageKeys() > 0 { if _, ok := trTypesAl[tr.Type()]; !ok { fmt.Printf("Example for type %d with AL:\n%x\n", tr.Type(), v) } trTypesAl[tr.Type()]++ } } fmt.Printf("Transaction types: %v\n", trTypes) return nil } func scanReceipts3(chaindata string, block uint64) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() var key [8]byte var v []byte binary.BigEndian.PutUint64(key[:], block) if v, err = tx.GetOne(kv.Receipts, key[:]); err != nil { return err } fmt.Printf("%x\n", v) return nil } func scanReceipts2(chaindata string) error { f, err := os.Create("receipts.txt") if err != nil { return err } defer f.Close() w := bufio.NewWriter(f) defer w.Flush() dbdb := mdbx.MustOpen(chaindata) defer dbdb.Close() tx, err := dbdb.BeginRw(context.Background()) if err != nil { return err } defer tx.Rollback() blockNum, err := changeset.AvailableFrom(tx) if err != nil { return err } fixedCount := 0 logEvery := time.NewTicker(20 * time.Second) defer logEvery.Stop() var key [8]byte var v []byte for ; true; blockNum++ { select { default: case <-logEvery.C: log.Info("Scanned", "block", blockNum, "fixed", fixedCount) } var hash common.Hash if hash, err = rawdb.ReadCanonicalHash(tx, blockNum); err != nil { return err } if hash == (common.Hash{}) { break } binary.BigEndian.PutUint64(key[:], blockNum) if v, err = tx.GetOne(kv.Receipts, key[:]); err != nil { return err } var receipts types.Receipts if err = cbor.Unmarshal(&receipts, bytes.NewReader(v)); err == nil { broken := false for _, receipt := range receipts { if receipt.CumulativeGasUsed < 10000 { broken = true break } } if !broken { continue } } fmt.Fprintf(w, "%d %x\n", blockNum, v) fixedCount++ if fixedCount > 100 { break } } tx.Rollback() return nil } func devTx(chaindata string) error { db := mdbx.MustOpen(chaindata) defer db.Close() tx, err := db.BeginRo(context.Background()) if err != nil { return err } defer tx.Rollback() cc := tool.ChainConfig(tx) txn := types.NewTransaction(2, common.Address{}, uint256.NewInt(100), 100_000, uint256.NewInt(1), []byte{1}) signedTx, err := types.SignTx(txn, *types.LatestSigner(cc), core.DevnetSignPrivateKey) tool.Check(err) buf := bytes.NewBuffer(nil) err = signedTx.MarshalBinary(buf) tool.Check(err) fmt.Printf("%x\n", buf.Bytes()) return nil } func mainnetGenesis() error { g := core.DefaultGenesisBlock() _, _, err := g.ToBlock() if err != nil { return err } return nil } func junkdb() error { dir, err := os.MkdirTemp(".", "junk") if err != nil { return fmt.Errorf("creating temp dir for db size test: %w", err) } //defer os.RemoveAll(dir) oneBucketCfg := make(kv.TableCfg) oneBucketCfg["t"] = kv.TableCfgItem{} var db kv.RwDB db, err = mdbx.NewMDBX(log.New()).Path(dir).WithTablessCfg(func(kv.TableCfg) kv.TableCfg { return oneBucketCfg }).Open() if err != nil { return fmt.Errorf("opening database: %w", err) } defer db.Close() for i := 0; i < 1_000_000; i++ { if err = db.Update(context.Background(), func(tx kv.RwTx) error { c, e := tx.RwCursor("t") if e != nil { return e } defer c.Close() for j := 0; j < 1_000_000_000; j++ { var b [8]byte binary.BigEndian.PutUint64(b[:], uint64(i*1_000_000_000+j)) if e = c.Append(b[:], b[:]); e != nil { return e } } return nil }); err != nil { return err } log.Info("Appended records", "bln", i+1) } return nil } func histStats() error { files, err := os.ReadDir(".") if err != nil { return err } endBlockMap := map[uint64]struct{}{} pageMap := map[string]map[uint64]uint64{} keys := []string{"ahistory", "shistory", "abitmap", "sbitmap"} for _, k := range keys { pageMap[k] = map[uint64]uint64{} } re := regexp.MustCompile(`(ahistory|shistory|abitmap|sbitmap).([0-9]+).txt`) for _, f := range files { name := f.Name() subs := re.FindStringSubmatch(name) if len(subs) != 3 { if len(subs) != 0 { log.Warn("File ignored by changes scan, more than 3 submatches", "name", name, "submatches", len(subs)) } continue } var endBlock uint64 if endBlock, err = strconv.ParseUint(subs[2], 10, 64); err != nil { return err } endBlockMap[endBlock] = struct{}{} var ff *os.File if ff, err = os.Open(name); err != nil { return err } scanner := bufio.NewScanner(ff) // Skip 5 lines for i := 0; i < 5; i++ { scanner.Scan() } var totalPages uint64 for i := 0; i < 3; i++ { scanner.Scan() line := scanner.Text() p := strings.Index(line, ": ") var pages uint64 if pages, err = strconv.ParseUint(line[p+2:], 10, 64); err != nil { return err } totalPages += pages } pageMap[subs[1]][endBlock] = totalPages ff.Close() } var endBlocks []uint64 for endBlock := range endBlockMap { endBlocks = append(endBlocks, endBlock) } slices.Sort(endBlocks) var lastEndBlock uint64 fmt.Printf("endBlock,%s\n", strings.Join(keys, ",")) for _, endBlock := range endBlocks { fmt.Printf("%d", endBlock) for _, k := range keys { if lastEndBlock == 0 { fmt.Printf(",%.3f", float64(pageMap[k][endBlock])/256.0/1024.0) } else { fmt.Printf(",%.3f", float64(pageMap[k][endBlock]-pageMap[k][lastEndBlock])/256.0/1024.0) } } fmt.Printf("\n") lastEndBlock = endBlock } return nil } func histStat1(chaindata string) error { files, err := os.ReadDir(chaindata) if err != nil { return err } endBlockMap := map[uint64]struct{}{} sizeMap := map[string]map[uint64]uint64{} keys := []string{"ahistory", "shistory", "chistory", "abitmap", "sbitmap", "cbitmap"} for _, k := range keys { sizeMap[k] = map[uint64]uint64{} } re := regexp.MustCompile(fmt.Sprintf("(%s).([0-9]+)-([0-9]+).(dat|idx)", strings.Join(keys, "|"))) for _, f := range files { name := f.Name() subs := re.FindStringSubmatch(name) if len(subs) != 5 { if len(subs) != 0 { log.Warn("File ignored by changes scan, more than 5 submatches", "name", name, "submatches", len(subs)) } continue } var startBlock uint64 if startBlock, err = strconv.ParseUint(subs[2], 10, 64); err != nil { return err } var endBlock uint64 if endBlock, err = strconv.ParseUint(subs[3], 10, 64); err != nil { return err } if endBlock-startBlock < 499_999 { continue } endBlockMap[endBlock] = struct{}{} if fileInfo, err1 := os.Stat(filepath.Join(chaindata, name)); err1 == nil { sizeMap[subs[1]][endBlock] += uint64(fileInfo.Size()) } else { return err1 } } var endBlocks []uint64 for endBlock := range endBlockMap { endBlocks = append(endBlocks, endBlock) } slices.Sort(endBlocks) fmt.Printf("endBlock,%s\n", strings.Join(keys, ",")) for _, endBlock := range endBlocks { fmt.Printf("%d", endBlock) for _, k := range keys { fmt.Printf(",%.3f", float64(sizeMap[k][endBlock])/1024.0/1024.0/1024.0) } fmt.Printf("\n") } return nil } func chainConfig(name string) error { var chainConfig *params.ChainConfig switch name { case "mainnet": chainConfig = params.MainnetChainConfig case "ropsten": chainConfig = params.RopstenChainConfig case "sepolia": chainConfig = params.SepoliaChainConfig case "rinkeby": chainConfig = params.RinkebyChainConfig case "goerli": chainConfig = params.GoerliChainConfig case "kiln-devnet": chainConfig = params.KilnDevnetChainConfig case "bsc": chainConfig = params.BSCChainConfig case "sokol": chainConfig = params.SokolChainConfig case "chapel": chainConfig = params.ChapelChainConfig case "rialto": chainConfig = params.RialtoChainConfig case "fermion": chainConfig = params.FermionChainConfig case "mumbai": chainConfig = params.MumbaiChainConfig case "bor-mainnet": chainConfig = params.BorMainnetChainConfig default: return fmt.Errorf("unknown name: %s", name) } f, err := os.Create(filepath.Join("params", "chainspecs", fmt.Sprintf("%s.json", name))) if err != nil { return err } w := bufio.NewWriter(f) encoder := json.NewEncoder(w) encoder.SetIndent("", " ") if err = encoder.Encode(chainConfig); err != nil { return err } if err = w.Flush(); err != nil { return err } if err = f.Close(); err != nil { return err } return nil } func main() { debug.RaiseFdLimit() flag.Parse() log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*verbosity), log.StderrHandler)) if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Error("could not create CPU profile", "err", err) return } if err := pprof.StartCPUProfile(f); err != nil { log.Error("could not start CPU profile", "err", err) return } defer pprof.StopCPUProfile() } go func() { if err := http.ListenAndServe("localhost:6060", nil); err != nil { log.Error("Failure in running pprof server", "err", err) } }() var err error switch *action { case "cfg": flow.TestGenCfg() case "bucketStats": err = bucketStats(*chaindata) case "syncChart": mychart() case "testBlockHashes": testBlockHashes(*chaindata, *block, common.HexToHash(*hash)) case "invTree": invTree("root", "right", "diff", *name) case "readAccount": if err := readAccount(*chaindata, common.HexToAddress(*account)); err != nil { fmt.Printf("Error: %v\n", err) } case "nextIncarnation": nextIncarnation(*chaindata, common.HexToHash(*account)) case "dumpStorage": dumpStorage() case "current": printCurrentBlockNumber(*chaindata) case "bucket": printBucket(*chaindata) case "val-tx-lookup-2": ValidateTxLookups2(*chaindata) case "slice": dbSlice(*chaindata, *bucket, common.FromHex(*hash)) case "getProof": err = testGetProof(*chaindata, common.HexToAddress(*account), *rewind, false) case "regenerateIH": err = regenerate(*chaindata) case "searchChangeSet": err = searchChangeSet(*chaindata, common.FromHex(*hash), uint64(*block)) case "searchStorageChangeSet": err = searchStorageChangeSet(*chaindata, common.FromHex(*hash), uint64(*block)) case "changeSetStats": err = changeSetStats(*chaindata, uint64(*block), uint64(*block)+uint64(*rewind)) case "supply": err = supply(*chaindata) case "extractCode": err = extractCode(*chaindata) case "iterateOverCode": err = iterateOverCode(*chaindata) case "mint": err = mint(*chaindata, uint64(*block)) case "extractHeaders": err = extractHeaders(*chaindata, uint64(*block), int64(*blockTotal)) case "extractHashes": err = extractHashes(*chaindata, uint64(*block), int64(*blockTotal), *name) case "defrag": err = hackdb.Defrag() case "textInfo": err = hackdb.TextInfo(*chaindata, &strings.Builder{}) case "extractBodies": err = extractBodies(*chaindata, uint64(*block)) case "fixUnwind": err = fixUnwind(*chaindata) case "repairCurrent": repairCurrent() case "printFullNodeRLPs": printFullNodeRLPs() case "rlpIndices": rlpIndices() case "hashFile": hashFile() case "trieChart": trieChart() case "printTxHashes": printTxHashes(*chaindata, uint64(*block)) case "snapSizes": err = snapSizes(*chaindata) case "mphf": err = mphf(*chaindata, *block) case "readCallTraces": err = readCallTraces(*chaindata, uint64(*block)) case "fixTd": err = fixTd(*chaindata) case "advanceExec": err = advanceExec(*chaindata) case "backExec": err = backExec(*chaindata) case "fixState": err = fixState(*chaindata) case "trimTxs": err = trimTxs(*chaindata) case "scanTxs": err = scanTxs(*chaindata) case "scanReceipts2": err = scanReceipts2(*chaindata) case "scanReceipts3": err = scanReceipts3(*chaindata, uint64(*block)) case "devTx": err = devTx(*chaindata) case "dumpState": err = dumpState(*chaindata, int(*block), *name) case "compress": err = compress1(*name, *name) case "decompress": err = decompress(*name) case "genstate": err = genstate() case "mainnetGenesis": err = mainnetGenesis() case "junkdb": err = junkdb() case "histStats": err = histStats() case "histStat1": err = histStat1(*chaindata) case "chainConfig": err = chainConfig(*name) } if err != nil { fmt.Printf("Error: %v\n", err) } }