diff --git a/rollup/missing_header_fields/export-headers-toolkit/.gitignore b/rollup/missing_header_fields/export-headers-toolkit/.gitignore new file mode 100644 index 000000000000..adbb97d2d313 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/.gitignore @@ -0,0 +1 @@ +data/ \ No newline at end of file diff --git a/rollup/missing_header_fields/export-headers-toolkit/Dockerfile b/rollup/missing_header_fields/export-headers-toolkit/Dockerfile new file mode 100644 index 000000000000..04f729a05ef7 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.22 + +WORKDIR /app + +COPY go.mod go.sum ./ + +RUN go mod download + +COPY . . + +RUN go build -o main . + +ENTRYPOINT ["./main"] \ No newline at end of file diff --git a/rollup/missing_header_fields/export-headers-toolkit/README.md b/rollup/missing_header_fields/export-headers-toolkit/README.md new file mode 100644 index 000000000000..339bcada3d59 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/README.md @@ -0,0 +1,63 @@ +# Export missing block header fields toolkit + +A toolkit for exporting and transforming missing block header fields of Scroll before {{upgrade_name}} TODO: replace when upgrade is clear. + +## Context +We are using the [Clique consensus](https://eips.ethereum.org/EIPS/eip-225) in Scroll L2. Amongst others, it requires the following header fields: +- `extraData` +- `difficulty` + +However, before {{upgrade_name}}, these fields were not stored on L1/DA. +In order for nodes to be able to reconstruct the correct block hashes when only reading data from L1, +we need to provide the historical values of these fields to these nodes through a separate file. + +This toolkit provides commands to export the missing fields, deduplicate the data and create a file +with the missing fields that can be used to reconstruct the correct block hashes when only reading data from L1. + +The toolkit provides the following commands: +- `fetch` - Fetch missing block header fields from a running Scroll L2 node and store in a file +- `dedup` - Deduplicate the headers file, print unique values and create a new file with the deduplicated headers + +## Binary layout deduplicated missing header fields file +The deduplicated header file binary layout is as follows: + +```plaintext +...... + +Where: +- unique_vanity_count: number of unique vanities n +- unique_vanity_i: unique vanity i +- header_i: block header i +- header: + + - flags: bitmask, lsb first + - bit 0-5: index of the vanity in the sorted vanities list + - bit 6: 0 if difficulty is 2, 1 if difficulty is 1 + - bit 7: 0 if seal length is 65, 1 if seal length is 85 +``` + +## How to run +Each of the commands has its own set of flags and options. To display the help message run with `--help` flag. + +1. Fetch the missing block header fields from a running Scroll L2 node via RPC and store in a file (approx 40min for 5.5M blocks). +2. Deduplicate the headers file, print unique values and create a new file with the deduplicated headers + +```bash +go run main.go fetch --rpc=http://localhost:8545 --start=0 --end=100 --batch=10 --parallelism=10 --output=headers.bin --humanOutput=true +go run main.go dedup --input=headers.bin --output=headers-dedup.bin +``` + + +### With Docker +To run the toolkit with Docker, build the Docker image and run the commands inside the container. + +```bash +docker build -t export-headers-toolkit . + +# depending on the Docker config maybe finding the RPC container's IP with docker inspect is necessary. Potentially host IP works: http://172.17.0.1:8545 +docker run --rm -v "$(pwd)":/app/result export-headers-toolkit fetch --rpc=
--start=0 --end=5422047 --batch=10000 --parallelism=10 --output=/app/result/headers.bin --humanOutput=/app/result/headers.csv +docker run --rm -v "$(pwd)":/app/result export-headers-toolkit dedup --input=/app/result/headers.bin --output=/app/result/headers-dedup.bin +``` + + + diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/dedup.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/dedup.go new file mode 100644 index 000000000000..e2bbd7ee4ddd --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/dedup.go @@ -0,0 +1,296 @@ +package cmd + +import ( + "bufio" + "bytes" + "crypto/sha256" + "encoding/binary" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + + "github.com/spf13/cobra" + + "github.com/scroll-tech/go-ethereum/common" + + "github.com/scroll-tech/go-ethereum/export-headers-toolkit/types" +) + +// dedupCmd represents the dedup command +var dedupCmd = &cobra.Command{ + Use: "dedup", + Short: "Deduplicate the headers file, print unique values and create a new file with the deduplicated headers", + Long: `Deduplicate the headers file, print unique values and create a new file with the deduplicated headers. + +The binary layout of the deduplicated file is as follows: +- 1 byte for the count of unique vanity +- 32 bytes for each unique vanity +- for each header: + - 1 byte (bitmask, lsb first): + - bit 0-5: index of the vanity in the sorted vanities list + - bit 6: 0 if difficulty is 2, 1 if difficulty is 1 + - bit 7: 0 if seal length is 65, 1 if seal length is 85 + - 65 or 85 bytes for the seal`, + Run: func(cmd *cobra.Command, args []string) { + inputFile, err := cmd.Flags().GetString("input") + if err != nil { + log.Fatalf("Error reading output flag: %v", err) + } + outputFile, err := cmd.Flags().GetString("output") + if err != nil { + log.Fatalf("Error reading output flag: %v", err) + } + verifyFile, err := cmd.Flags().GetString("verify") + if err != nil { + log.Fatalf("Error reading verify flag: %v", err) + } + + if verifyFile != "" { + verifyInputFile(verifyFile, inputFile) + } + + _, seenVanity, _ := runAnalysis(inputFile) + runDedup(inputFile, outputFile, seenVanity) + + if verifyFile != "" { + verifyOutputFile(verifyFile, outputFile) + } + + runSHA256(outputFile) + }, +} + +func init() { + rootCmd.AddCommand(dedupCmd) + + dedupCmd.Flags().String("input", "headers.bin", "headers file") + dedupCmd.Flags().String("output", "headers-dedup.bin", "deduplicated, binary formatted file") + dedupCmd.Flags().String("verify", "", "verify the input and output files with the given .csv file") +} + +func runAnalysis(inputFile string) (seenDifficulty map[uint64]int, seenVanity map[[32]byte]bool, seenSealLen map[int]int) { + reader := newHeaderReader(inputFile) + defer reader.close() + + // track header fields we've seen + seenDifficulty = make(map[uint64]int) + seenVanity = make(map[[32]byte]bool) + seenSealLen = make(map[int]int) + + reader.read(func(header *types.Header) { + seenDifficulty[header.Difficulty]++ + seenVanity[header.Vanity()] = true + seenSealLen[header.SealLen()]++ + }) + + // Print distinct values and report + fmt.Println("--------------------------------------------------") + for diff, count := range seenDifficulty { + fmt.Printf("Difficulty %d: %d\n", diff, count) + } + + for vanity := range seenVanity { + fmt.Printf("Vanity: %x\n", vanity) + } + + for sealLen, count := range seenSealLen { + fmt.Printf("SealLen %d bytes: %d\n", sealLen, count) + } + + fmt.Println("--------------------------------------------------") + fmt.Printf("Unique values seen in the headers file (last seen block: %d):\n", reader.lastHeader.Number) + fmt.Printf("Distinct count: Difficulty:%d, Vanity:%d, SealLen:%d\n", len(seenDifficulty), len(seenVanity), len(seenSealLen)) + fmt.Printf("--------------------------------------------------\n\n") + + return seenDifficulty, seenVanity, seenSealLen +} + +func runDedup(inputFile, outputFile string, seenVanity map[[32]byte]bool) { + reader := newHeaderReader(inputFile) + defer reader.close() + + writer := newMissingHeaderFileWriter(outputFile, seenVanity) + defer writer.close() + + writer.missingHeaderWriter.writeVanities() + + reader.read(func(header *types.Header) { + writer.missingHeaderWriter.write(header) + }) +} + +func runSHA256(outputFile string) { + f, err := os.Open(outputFile) + defer f.Close() + if err != nil { + log.Fatalf("Error opening file: %v", err) + } + + h := sha256.New() + if _, err = io.Copy(h, f); err != nil { + log.Fatalf("Error hashing file: %v", err) + } + + fmt.Printf("Deduplicated headers written to %s with sha256 checksum: %x\n", outputFile, h.Sum(nil)) +} + +type headerReader struct { + file *os.File + reader *bufio.Reader + lastHeader *types.Header +} + +func newHeaderReader(inputFile string) *headerReader { + f, err := os.Open(inputFile) + if err != nil { + log.Fatalf("Error opening input file: %v", err) + } + + h := &headerReader{ + file: f, + reader: bufio.NewReader(f), + } + + return h +} + +func (h *headerReader) read(callback func(header *types.Header)) { + headerSizeBytes := make([]byte, types.HeaderSizeSerialized) + + for { + _, err := io.ReadFull(h.reader, headerSizeBytes) + if err != nil { + if err == io.EOF { + break + } + log.Fatalf("Error reading headerSizeBytes: %v", err) + } + headerSize := binary.BigEndian.Uint16(headerSizeBytes) + + headerBytes := make([]byte, headerSize) + _, err = io.ReadFull(h.reader, headerBytes) + if err != nil { + if err == io.EOF { + break + } + log.Fatalf("Error reading headerBytes: %v", err) + } + header := new(types.Header).FromBytes(headerBytes) + + // sanity check: make sure headers are in order + if h.lastHeader != nil && header.Number != h.lastHeader.Number+1 { + fmt.Println("lastHeader:", h.lastHeader.String()) + log.Fatalf("Missing block: %d, got %d instead", h.lastHeader.Number+1, header.Number) + } + h.lastHeader = header + + callback(header) + } +} + +func (h *headerReader) close() { + h.file.Close() +} + +type csvHeaderReader struct { + file *os.File + reader *bufio.Reader +} + +func newCSVHeaderReader(verifyFile string) *csvHeaderReader { + f, err := os.Open(verifyFile) + if err != nil { + log.Fatalf("Error opening verify file: %v", err) + } + + h := &csvHeaderReader{ + file: f, + reader: bufio.NewReader(f), + } + + return h +} + +func (h *csvHeaderReader) readNext() *types.Header { + line, err := h.reader.ReadString('\n') + if err != nil { + if err == io.EOF { + return nil + } + log.Fatalf("Error reading line: %v", err) + } + + s := strings.Split(line, ",") + extraString := strings.Split(s[2], "\n") + + num, err := strconv.ParseUint(s[0], 10, 64) + if err != nil { + log.Fatalf("Error parsing block number: %v", err) + } + difficulty, err := strconv.ParseUint(s[1], 10, 64) + if err != nil { + log.Fatalf("Error parsing difficulty: %v", err) + } + extra := common.FromHex(extraString[0]) + + header := types.NewHeader(num, difficulty, extra) + return header +} + +func (h *csvHeaderReader) close() { + h.file.Close() +} + +func verifyInputFile(verifyFile, inputFile string) { + csvReader := newCSVHeaderReader(verifyFile) + defer csvReader.close() + + binaryReader := newHeaderReader(inputFile) + defer binaryReader.close() + + binaryReader.read(func(header *types.Header) { + csvHeader := csvReader.readNext() + + if !csvHeader.Equal(header) { + log.Fatalf("Header mismatch: %v != %v", csvHeader, header) + } + }) + + log.Printf("All headers match in %s and %s\n", verifyFile, inputFile) +} + +func verifyOutputFile(verifyFile, outputFile string) { + csvReader := newCSVHeaderReader(verifyFile) + defer csvReader.close() + + dedupReader, err := NewReader(outputFile) + if err != nil { + log.Fatalf("Error opening dedup file: %v", err) + } + defer dedupReader.Close() + + for { + header := csvReader.readNext() + if header == nil { + if _, _, err = dedupReader.ReadNext(); err == nil { + log.Fatalf("Expected EOF, got more headers") + } + break + } + + difficulty, extraData, err := dedupReader.Read(header.Number) + if err != nil { + log.Fatalf("Error reading header: %v", err) + } + + if header.Difficulty != difficulty { + log.Fatalf("Difficulty mismatch: headerNum %d: %d != %d", header.Number, header.Difficulty, difficulty) + } + if !bytes.Equal(header.ExtraData, extraData) { + log.Fatalf("ExtraData mismatch: headerNum %d: %x != %x", header.Number, header.ExtraData, extraData) + } + } +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/fetch.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/fetch.go new file mode 100644 index 000000000000..b9799d12ba29 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/fetch.go @@ -0,0 +1,247 @@ +package cmd + +import ( + "bufio" + "container/heap" + "context" + "fmt" + "log" + "math/big" + "os" + "sync" + "time" + + "github.com/spf13/cobra" + + "github.com/scroll-tech/go-ethereum/ethclient" + + "github.com/scroll-tech/go-ethereum/export-headers-toolkit/types" +) + +var fetchCmd = &cobra.Command{ + Use: "fetch", + Short: "Fetch missing block header fields from a running Scroll L2 node via RPC and store in a file", + Long: `Fetch allows to retrieve the missing block header fields from a running Scroll L2 node via RPC. +It produces a binary file and optionally a human readable csv file with the missing fields.`, + Run: func(cmd *cobra.Command, args []string) { + rpc, err := cmd.Flags().GetString("rpc") + if err != nil { + log.Fatalf("Error reading rpc flag: %v", err) + } + client, err := ethclient.Dial(rpc) + if err != nil { + log.Fatalf("Error connecting to RPC: %v", err) + } + startBlockNum, err := cmd.Flags().GetUint64("start") + if err != nil { + log.Fatalf("Error reading start flag: %v", err) + } + endBlockNum, err := cmd.Flags().GetUint64("end") + if err != nil { + log.Fatalf("Error reading end flag: %v", err) + } + batchSize, err := cmd.Flags().GetUint64("batch") + if err != nil { + log.Fatalf("Error reading batch flag: %v", err) + } + maxParallelGoroutines, err := cmd.Flags().GetInt("parallelism") + if err != nil { + log.Fatalf("Error reading parallelism flag: %v", err) + } + outputFile, err := cmd.Flags().GetString("output") + if err != nil { + log.Fatalf("Error reading output flag: %v", err) + } + humanReadableOutputFile, err := cmd.Flags().GetString("humanOutput") + if err != nil { + log.Fatalf("Error reading humanReadable flag: %v", err) + } + + runFetch(client, startBlockNum, endBlockNum, batchSize, maxParallelGoroutines, outputFile, humanReadableOutputFile) + }, +} + +func init() { + rootCmd.AddCommand(fetchCmd) + + fetchCmd.Flags().String("rpc", "http://localhost:8545", "RPC URL") + fetchCmd.Flags().Uint64("start", 0, "start block number") + fetchCmd.Flags().Uint64("end", 1000, "end block number") + fetchCmd.Flags().Uint64("batch", 100, "batch size") + fetchCmd.Flags().Int("parallelism", 10, "max parallel goroutines each working on batch size blocks") + fetchCmd.Flags().String("output", "headers.bin", "output file") + fetchCmd.Flags().String("humanOutput", "", "additionally produce human readable csv file") +} + +func headerByNumberWithRetry(client *ethclient.Client, blockNum uint64, maxRetries int) (*types.Header, error) { + var innerErr error + for i := 0; i < maxRetries; i++ { + header, err := client.HeaderByNumber(context.Background(), big.NewInt(int64(blockNum))) + if err == nil { + return &types.Header{ + Number: header.Number.Uint64(), + Difficulty: header.Difficulty.Uint64(), + ExtraData: header.Extra, + }, nil + } + + innerErr = err // save the last error to return it if all retries fail + + // Wait before retrying + time.Sleep(time.Duration(i*200) * time.Millisecond) + log.Printf("Retrying header fetch for block %d, retry %d, error %v", blockNum, i+1, err) + } + + return nil, fmt.Errorf("error fetching header for block %d: %v", blockNum, innerErr) +} + +func fetchHeaders(client *ethclient.Client, start, end uint64, headersChan chan<- *types.Header) { + for i := start; i <= end; i++ { + header, err := headerByNumberWithRetry(client, i, 15) + if err != nil { + log.Fatalf("Error fetching header %d: %v", i, err) + } + + headersChan <- header + } +} + +func writeHeadersToFile(outputFile string, humanReadableOutputFile string, startBlockNum uint64, headersChan <-chan *types.Header) { + writer := newFilesWriter(outputFile, humanReadableOutputFile) + defer writer.close() + + headerHeap := &types.HeaderHeap{} + heap.Init(headerHeap) + + nextHeaderNum := startBlockNum + + // receive all headers and write them in order by using a sorted heap + for header := range headersChan { + heap.Push(headerHeap, header) + + // write all headers that are in order + for headerHeap.Len() > 0 && (*headerHeap)[0].Number == nextHeaderNum { + nextHeaderNum++ + sortedHeader := heap.Pop(headerHeap).(*types.Header) + writer.write(sortedHeader) + } + } + + fmt.Println("Finished writing headers to file, last block number:", nextHeaderNum-1) +} + +func runFetch(client *ethclient.Client, startBlockNum uint64, endBlockNum uint64, batchSize uint64, maxGoroutines int, outputFile string, humanReadableOutputFile string) { + headersChan := make(chan *types.Header, maxGoroutines*int(batchSize)) + tasks := make(chan task, maxGoroutines) + + var wgConsumer sync.WaitGroup + // start consumer goroutine to sort and write headers to file + go func() { + wgConsumer.Add(1) + writeHeadersToFile(outputFile, humanReadableOutputFile, startBlockNum, headersChan) + wgConsumer.Done() + }() + + var wgProducers sync.WaitGroup + // start producer goroutines to fetch headers + for i := 0; i < maxGoroutines; i++ { + wgProducers.Add(1) + go func() { + for { + t, ok := <-tasks + if !ok { + break + } + fetchHeaders(client, t.start, t.end, headersChan) + } + wgProducers.Done() + }() + } + + // create tasks/work packages for producer goroutines + for start := startBlockNum; start <= endBlockNum; start += batchSize { + end := start + batchSize - 1 + if end > endBlockNum { + end = endBlockNum + } + fmt.Println("Fetching headers for blocks", start, "to", end) + + tasks <- task{start, end} + } + + close(tasks) + wgProducers.Wait() + close(headersChan) + wgConsumer.Wait() +} + +type task struct { + start uint64 + end uint64 +} + +// filesWriter is a helper struct to write headers to binary and human-readable csv files at the same time. +type filesWriter struct { + binaryFile *os.File + binaryWriter *bufio.Writer + + humanReadable bool + csvFile *os.File + csvWriter *bufio.Writer +} + +func newFilesWriter(outputFile string, humanReadableOutputFile string) *filesWriter { + binaryFile, err := os.Create(outputFile) + if err != nil { + log.Fatalf("Error creating binary file: %v", err) + } + + f := &filesWriter{ + binaryFile: binaryFile, + binaryWriter: bufio.NewWriter(binaryFile), + humanReadable: humanReadableOutputFile != "", + } + + if humanReadableOutputFile != "" { + csvFile, err := os.Create(humanReadableOutputFile) + if err != nil { + log.Fatalf("Error creating human readable file: %v", err) + } + f.csvFile = csvFile + f.csvWriter = bufio.NewWriter(csvFile) + } + + return f +} + +func (f *filesWriter) close() { + if err := f.binaryWriter.Flush(); err != nil { + log.Fatalf("Error flushing binary buffer: %v", err) + } + if f.humanReadable { + if err := f.csvWriter.Flush(); err != nil { + log.Fatalf("Error flushing csv buffer: %v", err) + } + } + + f.binaryFile.Close() + if f.humanReadable { + f.csvFile.Close() + } +} +func (f *filesWriter) write(header *types.Header) { + bytes, err := header.Bytes() + if err != nil { + log.Fatalf("Error converting header to bytes: %v", err) + } + + if _, err = f.binaryWriter.Write(bytes); err != nil { + log.Fatalf("Error writing to binary file: %v", err) + } + + if f.humanReadable { + if _, err = f.csvWriter.WriteString(header.String()); err != nil { + log.Fatalf("Error writing to human readable file: %v", err) + } + } +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_reader.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_reader.go new file mode 100644 index 000000000000..773b4e06451c --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_reader.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" +) + +// TODO: instead of duplicating this file, missing_header_fields.Reader should be used in toolkit + +type missingHeader struct { + headerNum uint64 + difficulty uint64 + extraData []byte +} + +type Reader struct { + file *os.File + reader *bufio.Reader + sortedVanities map[int][32]byte + lastReadHeader *missingHeader +} + +func NewReader(filePath string) (*Reader, error) { + f, err := os.Open(filePath) + if err != nil { + return nil, fmt.Errorf("failed to open file: %v", err) + } + + r := &Reader{ + file: f, + reader: bufio.NewReader(f), + } + + // read the count of unique vanities + vanityCount, err := r.reader.ReadByte() + if err != nil { + return nil, err + } + + // read the unique vanities + r.sortedVanities = make(map[int][32]byte) + for i := uint8(0); i < vanityCount; i++ { + var vanity [32]byte + if _, err = r.reader.Read(vanity[:]); err != nil { + return nil, err + } + r.sortedVanities[int(i)] = vanity + } + + return r, nil +} + +func (r *Reader) Read(headerNum uint64) (difficulty uint64, extraData []byte, err error) { + if r.lastReadHeader == nil { + if _, _, err = r.ReadNext(); err != nil { + return 0, nil, err + } + } + + if headerNum > r.lastReadHeader.headerNum { + // skip the headers until the requested header number + for i := r.lastReadHeader.headerNum; i < headerNum; i++ { + if _, _, err = r.ReadNext(); err != nil { + return 0, nil, err + } + } + } + + if headerNum == r.lastReadHeader.headerNum { + return r.lastReadHeader.difficulty, r.lastReadHeader.extraData, nil + } + + // headerNum < r.lastReadHeader.headerNum is not supported + return 0, nil, fmt.Errorf("requested header %d below last read header number %d", headerNum, r.lastReadHeader.headerNum) +} + +func (r *Reader) ReadNext() (difficulty uint64, extraData []byte, err error) { + // read the bitmask + bitmaskByte, err := r.reader.ReadByte() + if err != nil { + return 0, nil, fmt.Errorf("failed to read bitmask: %v", err) + } + + bits := newBitMaskFromByte(bitmaskByte) + + seal := make([]byte, bits.sealLen()) + + if _, err = io.ReadFull(r.reader, seal); err != nil { + return 0, nil, fmt.Errorf("failed to read seal: %v", err) + } + + // construct the extraData field + vanity := r.sortedVanities[bits.vanityIndex()] + var b bytes.Buffer + b.Write(vanity[:]) + b.Write(seal) + + // we don't have the header number, so we'll just increment the last read header number + // we assume that the headers are written in order, starting from 0 + if r.lastReadHeader == nil { + r.lastReadHeader = &missingHeader{ + headerNum: 0, + difficulty: uint64(bits.difficulty()), + extraData: b.Bytes(), + } + } else { + r.lastReadHeader.headerNum++ + r.lastReadHeader.difficulty = uint64(bits.difficulty()) + r.lastReadHeader.extraData = b.Bytes() + } + + return difficulty, b.Bytes(), nil +} + +func (r *Reader) Close() error { + return r.file.Close() +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer.go new file mode 100644 index 000000000000..5b3eed1c2cbd --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer.go @@ -0,0 +1,169 @@ +package cmd + +import ( + "bufio" + "bytes" + "io" + "log" + "os" + "sort" + + "github.com/scroll-tech/go-ethereum/export-headers-toolkit/types" +) + +// maxVanityCount is the maximum number of unique vanities that can be represented with 6 bits in the bitmask +const maxVanityCount = 1 << 6 + +type missingHeaderFileWriter struct { + file *os.File + writer *bufio.Writer + + missingHeaderWriter *missingHeaderWriter +} + +func newMissingHeaderFileWriter(filename string, seenVanity map[[32]byte]bool) *missingHeaderFileWriter { + if len(seenVanity) > maxVanityCount { + log.Fatalf("Number of unique vanities exceeds maximum: %d > %d", len(seenVanity), maxVanityCount) + } + + file, err := os.Create(filename) + if err != nil { + log.Fatalf("Error creating file: %v", err) + } + + writer := bufio.NewWriter(file) + return &missingHeaderFileWriter{ + file: file, + writer: writer, + missingHeaderWriter: newMissingHeaderWriter(writer, seenVanity), + } +} + +func (m *missingHeaderFileWriter) close() { + if err := m.writer.Flush(); err != nil { + log.Fatalf("Error flushing writer: %v", err) + } + if err := m.file.Close(); err != nil { + log.Fatalf("Error closing file: %v", err) + } +} + +type missingHeaderWriter struct { + writer io.Writer + + sortedVanities [][32]byte + sortedVanitiesMap map[[32]byte]int + seenDifficulty map[uint64]int + seenSealLen map[int]int +} + +func newMissingHeaderWriter(writer io.Writer, seenVanity map[[32]byte]bool) *missingHeaderWriter { + // sort the vanities and assign an index to each so that we can write the index of the vanity in the header + sortedVanities := make([][32]byte, 0, len(seenVanity)) + for vanity := range seenVanity { + sortedVanities = append(sortedVanities, vanity) + } + sort.Slice(sortedVanities, func(i, j int) bool { + return bytes.Compare(sortedVanities[i][:], sortedVanities[j][:]) < 0 + }) + sortedVanitiesMap := make(map[[32]byte]int) + for i, vanity := range sortedVanities { + sortedVanitiesMap[vanity] = i + } + + return &missingHeaderWriter{ + writer: writer, + sortedVanities: sortedVanities, + sortedVanitiesMap: sortedVanitiesMap, + } +} + +func (m *missingHeaderWriter) writeVanities() { + // write the count of unique vanities + if _, err := m.writer.Write([]byte{uint8(len(m.sortedVanitiesMap))}); err != nil { + log.Fatalf("Error writing unique vanity count: %v", err) + } + + // write the unique vanities + for _, vanity := range m.sortedVanities { + if _, err := m.writer.Write(vanity[:]); err != nil { + log.Fatalf("Error writing vanity: %v", err) + } + } +} + +func (m *missingHeaderWriter) write(header *types.Header) { + // 1. prepare the bitmask + bits := newBitMask(m.sortedVanitiesMap[header.Vanity()], int(header.Difficulty), header.SealLen()) + + // 2. write the header: bitmask and seal + if _, err := m.writer.Write(bits.Bytes()); err != nil { + log.Fatalf("Error writing bitmask: %v", err) + } + + if _, err := m.writer.Write(header.Seal()); err != nil { + log.Fatalf("Error writing seal: %v", err) + } +} + +// bitMask is a bitmask that encodes the following information: +// +// bit 0-5: index of the vanity in the sorted vanities list +// bit 6: 0 if difficulty is 2, 1 if difficulty is 1 +// bit 7: 0 if seal length is 65, 1 if seal length is 85 +type bitMask struct { + b uint8 +} + +func newBitMaskFromByte(b uint8) bitMask { + return bitMask{b} +} + +func newBitMask(vanityIndex int, difficulty int, sealLen int) bitMask { + b := uint8(0) + + if vanityIndex >= maxVanityCount { + log.Fatalf("Vanity index exceeds maximum: %d >= %d", vanityIndex, maxVanityCount) + } + b |= uint8(vanityIndex) & 0b00111111 + + if difficulty == 1 { + b |= 1 << 6 + } else if difficulty != 2 { + log.Fatalf("Invalid difficulty: %d", difficulty) + } + + if sealLen == 85 { + b |= 1 << 7 + } else if sealLen != 65 { + log.Fatalf("Invalid seal length: %d", sealLen) + } + + return bitMask{b} +} + +func (b bitMask) vanityIndex() int { + return int(b.b & 0b00111111) +} + +func (b bitMask) difficulty() int { + val := (b.b >> 6) & 0x01 + if val == 0 { + return 2 + } else { + return 1 + } +} + +func (b bitMask) sealLen() int { + val := (b.b >> 7) & 0x01 + if val == 0 { + return 65 + } else { + return 85 + } +} + +func (b bitMask) Bytes() []byte { + return []byte{b.b} +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer_test.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer_test.go new file mode 100644 index 000000000000..25c5d039dd93 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/missing_header_writer_test.go @@ -0,0 +1,101 @@ +package cmd + +import ( + "bytes" + "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/scroll-tech/go-ethereum/export-headers-toolkit/types" +) + +func TestMissingHeaderWriter(t *testing.T) { + vanity1 := [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} + vanity2 := [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02} + vanity8 := [32]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08} + + var expectedBytes []byte + expectedBytes = append(expectedBytes, 0x03) + expectedBytes = append(expectedBytes, vanity1[:]...) + expectedBytes = append(expectedBytes, vanity2[:]...) + expectedBytes = append(expectedBytes, vanity8[:]...) + + seenVanity := map[[32]byte]bool{ + vanity8: true, + vanity1: true, + vanity2: true, + } + var buf []byte + bytesBuffer := bytes.NewBuffer(buf) + mhw := newMissingHeaderWriter(bytesBuffer, seenVanity) + + mhw.writeVanities() + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + + // Header0 + { + seal := randomSeal(65) + header := types.NewHeader(0, 2, append(vanity1[:], seal...)) + mhw.write(header) + + // bit 0-5:0x0 index0, bit 6=0: difficulty 2, bit 7=0: seal length 65 + expectedBytes = append(expectedBytes, 0b00000000) + expectedBytes = append(expectedBytes, seal...) + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + } + + // Header1 + { + seal := randomSeal(65) + header := types.NewHeader(1, 1, append(vanity2[:], seal...)) + mhw.write(header) + + // bit 0-5:0x1 index1, bit 6=1: difficulty 1, bit 7=0: seal length 65 + expectedBytes = append(expectedBytes, 0b01000001) + expectedBytes = append(expectedBytes, seal...) + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + } + + // Header2 + { + seal := randomSeal(85) + header := types.NewHeader(2, 2, append(vanity2[:], seal...)) + mhw.write(header) + + // bit 0-5:0x1 index1, bit 6=0: difficulty 2, bit 7=1: seal length 85 + expectedBytes = append(expectedBytes, 0b10000001) + expectedBytes = append(expectedBytes, seal...) + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + } + + // Header3 + { + seal := randomSeal(85) + header := types.NewHeader(3, 1, append(vanity8[:], seal...)) + mhw.write(header) + + // bit 0-5:0x2 index2, bit 6=1: difficulty 1, bit 7=1: seal length 85 + expectedBytes = append(expectedBytes, 0b11000010) + expectedBytes = append(expectedBytes, seal...) + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + } + + // Header4 + { + seal := randomSeal(65) + header := types.NewHeader(4, 2, append(vanity1[:], seal...)) + mhw.write(header) + + // bit 0-5:0x0 index0, bit 6=0: difficulty 2, bit 7=0: seal length 65 + expectedBytes = append(expectedBytes, 0b00000000) + expectedBytes = append(expectedBytes, seal...) + assert.Equal(t, expectedBytes, bytesBuffer.Bytes()) + } +} + +func randomSeal(length int) []byte { + buf := make([]byte, length) + _, _ = rand.Read(buf) + return buf +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/cmd/root.go b/rollup/missing_header_fields/export-headers-toolkit/cmd/root.go new file mode 100644 index 000000000000..9b485e96dd62 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/cmd/root.go @@ -0,0 +1,32 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "export-headers-toolkit", + Short: "A toolkit for exporting and transforming missing block header fields of Scroll", + Long: `A toolkit for exporting and transforming missing block header fields of Scroll. + +The fields difficulty and extraData are missing from header data stored on L1 before {{upgrade_name}}. +This toolkit provides commands to export the missing fields, deduplicate the data and create a +file with the missing fields that can be used to reconstruct the correct block hashes when only reading +data from L1.`, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + rootCmd.CompletionOptions.DisableDefaultCmd = true +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/go.mod b/rollup/missing_header_fields/export-headers-toolkit/go.mod new file mode 100644 index 000000000000..97806cc8252f --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/go.mod @@ -0,0 +1,71 @@ +module github.com/scroll-tech/go-ethereum/export-headers-toolkit + +go 1.22 + +require ( + github.com/scroll-tech/go-ethereum v1.10.14-0.20240624092647-7da0bd5480e9 + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.9.0 +) + +require ( + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect + github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/btcsuite/btcd v0.20.1-beta // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea // indirect + github.com/edsrzf/mmap-go v1.0.0 // indirect + github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 // indirect + github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/uuid v1.1.5 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect + github.com/holiman/uint256 v1.3.0 // indirect + github.com/huin/goupnp v1.0.2 // indirect + github.com/iden3/go-iden3-crypto v0.0.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/tsdb v0.7.1 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/rjeczalik/notify v0.9.1 // indirect + github.com/rs/cors v1.7.0 // indirect + github.com/scroll-tech/da-codec v0.0.0-20240605080813-32bfc9fccde7 // indirect + github.com/scroll-tech/zktrie v0.8.4 // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect + github.com/supranational/blst v0.3.12 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.8.0 // indirect + github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/urfave/cli.v1 v1.20.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect +) diff --git a/rollup/missing_header_fields/export-headers-toolkit/go.sum b/rollup/missing_header_fields/export-headers-toolkit/go.sum new file mode 100644 index 000000000000..c0fc07b58407 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/go.sum @@ -0,0 +1,262 @@ +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI= +github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 h1:B2mpK+MNqgPqk2/KNi1LbqwtZDy5F7iy0mynQiBr8VA= +github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4/go.mod h1:y4GA2JbAUama1S4QwYjC2hefgGLU8Ul0GMtL/ADMF1c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= +github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= +github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= +github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk= +github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/scroll-tech/da-codec v0.0.0-20240605080813-32bfc9fccde7 h1:CDrPMqifvAVyYqu0x1J5qickVV0b51tApPnOwDYLESI= +github.com/scroll-tech/da-codec v0.0.0-20240605080813-32bfc9fccde7/go.mod h1:1wWYii0OPwd5kw+xrz0PFgS420xNadrNF1x/ELJT+TM= +github.com/scroll-tech/go-ethereum v1.10.14-0.20240624092647-7da0bd5480e9 h1:Jq4TTYcHVAIVPUHNYbOzNxEsWf+9Q3b30YQaMyl0TDI= +github.com/scroll-tech/go-ethereum v1.10.14-0.20240624092647-7da0bd5480e9/go.mod h1:byf/mZ8jLYUCnUePTicjJWn+RvKdxDn7buS6glTnMwQ= +github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= +github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/supranational/blst v0.3.12 h1:Vfas2U2CFHhniv2QkUm2OVa1+pGTdqtpqm9NnhUUbZ8= +github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/rollup/missing_header_fields/export-headers-toolkit/main.go b/rollup/missing_header_fields/export-headers-toolkit/main.go new file mode 100644 index 000000000000..1d8e22abe8cb --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/scroll-tech/go-ethereum/export-headers-toolkit/cmd" +) + +func main() { + cmd.Execute() +} diff --git a/rollup/missing_header_fields/export-headers-toolkit/types/header.go b/rollup/missing_header_fields/export-headers-toolkit/types/header.go new file mode 100644 index 000000000000..ffd76c8a8bb5 --- /dev/null +++ b/rollup/missing_header_fields/export-headers-toolkit/types/header.go @@ -0,0 +1,94 @@ +package types + +import ( + "encoding/binary" + "fmt" + + "github.com/scroll-tech/go-ethereum/common" +) + +const HeaderSizeSerialized = 2 +const VanitySize = 32 + +type Header struct { + Number uint64 + Difficulty uint64 + ExtraData []byte +} + +func NewHeader(number, difficulty uint64, extraData []byte) *Header { + return &Header{ + Number: number, + Difficulty: difficulty, + ExtraData: extraData, + } +} + +func (h *Header) String() string { + return fmt.Sprintf("%d,%d,%s\n", h.Number, h.Difficulty, common.Bytes2Hex(h.ExtraData)) +} + +func (h *Header) Equal(other *Header) bool { + if h.Number != other.Number { + return false + } + if h.Difficulty != other.Difficulty { + return false + } + if len(h.ExtraData) != len(other.ExtraData) { + return false + } + for i, b := range h.ExtraData { + if b != other.ExtraData[i] { + return false + } + } + return true +} + +// Bytes returns the byte representation of the header including the initial 2 bytes for the size. +func (h *Header) Bytes() ([]byte, error) { + size := 8 + 8 + len(h.ExtraData) + + buf := make([]byte, HeaderSizeSerialized+size) + binary.BigEndian.PutUint16(buf[:2], uint16(size)) + binary.BigEndian.PutUint64(buf[2:10], h.Number) + binary.BigEndian.PutUint64(buf[10:18], h.Difficulty) + copy(buf[18:], h.ExtraData) + return buf, nil +} + +func (h *Header) Vanity() [VanitySize]byte { + return [VanitySize]byte(h.ExtraData[:VanitySize]) +} + +func (h *Header) Seal() []byte { + return h.ExtraData[VanitySize:] +} + +func (h *Header) SealLen() int { + return len(h.Seal()) +} + +// FromBytes reads the header from the byte representation excluding the initial 2 bytes for the size. +func (h *Header) FromBytes(buf []byte) *Header { + h.Number = binary.BigEndian.Uint64(buf[:8]) + h.Difficulty = binary.BigEndian.Uint64(buf[8:16]) + h.ExtraData = buf[16:] + + return h +} + +type HeaderHeap []*Header + +func (h HeaderHeap) Len() int { return len(h) } +func (h HeaderHeap) Less(i, j int) bool { return h[i].Number < h[j].Number } +func (h HeaderHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *HeaderHeap) Push(x interface{}) { *h = append(*h, x.(*Header)) } +func (h *HeaderHeap) Pop() interface{} { + old := *h + n := len(old) + item := old[n-1] + *h = old[0 : n-1] + return item +}