mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-04 01:54:28 +00:00
e1dec529d4
* save * save * save * save * save
2777 lines
70 KiB
Go
2777 lines
70 KiB
Go
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: <nil>")
|
|
}
|
|
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)
|
|
}
|
|
}
|