github.com/gochain-io/gochain@v2.2.26+incompatible/cmd/gochain-ethdb/check.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"flag"
     8  	"fmt"
     9  	"path/filepath"
    10  
    11  	"github.com/gochain-io/gochain/ethdb"
    12  )
    13  
    14  var (
    15  	ErrUnsupportedCheckType = errors.New("unsupported check type")
    16  )
    17  
    18  type CheckCommand struct{}
    19  
    20  func NewCheckCommand() *CheckCommand {
    21  	return &CheckCommand{}
    22  }
    23  
    24  func (cmd *CheckCommand) Run(args []string) error {
    25  	// Parse flags.
    26  	fs := flag.NewFlagSet("gochain-ethdb-check", flag.ContinueOnError)
    27  	if err := fs.Parse(args); err != nil {
    28  		return err
    29  	}
    30  
    31  	if fs.NArg() == 0 {
    32  		return errors.New("path required")
    33  	}
    34  
    35  	// Iterate over each path passed in.
    36  	for _, path := range fs.Args() {
    37  		if err := cmd.check(path); err == ErrUnsupportedCheckType {
    38  			fmt.Printf("%s: not currently supported, skipping\n", path)
    39  			continue
    40  		} else if err != nil {
    41  			return fmt.Errorf("%s: %s", path, err)
    42  		}
    43  	}
    44  	return nil
    45  }
    46  
    47  func (cmd *CheckCommand) check(path string) error {
    48  	typ, err := ethdb.SegmentFileType(path)
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	switch typ {
    54  	case ethdb.SegmentLDB1:
    55  		return cmd.checkLDBSegment(path)
    56  	case ethdb.SegmentETH1:
    57  		return cmd.checkETHSegment(path)
    58  	default:
    59  		return fmt.Errorf("unknown segment type: %q", typ)
    60  	}
    61  }
    62  
    63  func (cmd *CheckCommand) checkLDBSegment(path string) error {
    64  	return ErrUnsupportedCheckType
    65  }
    66  
    67  func (cmd *CheckCommand) checkETHSegment(path string) error {
    68  	s := ethdb.NewFileSegment(filepath.Base(path), path)
    69  	if err := s.Open(); err != nil {
    70  		return err
    71  	}
    72  	defer s.Close()
    73  
    74  	// Print stats.
    75  	fmt.Printf("[eth1] %s\n", path)
    76  	fmt.Printf("SIZE: %d bytes\n", s.Size())
    77  	fmt.Printf("IDX: %d bytes\n", len(s.Index()))
    78  	fmt.Printf("LEN: %d items\n", s.Len())
    79  	fmt.Printf("CAP: %d items\n", s.Cap())
    80  	fmt.Printf("CHKSUM: %x\n", s.Checksum())
    81  
    82  	// Verify checksum integrity.
    83  	if chksum, err := ethdb.ChecksumFileSegment(path); err != nil {
    84  		return err
    85  	} else if !bytes.Equal(chksum, s.Checksum()) {
    86  		return fmt.Errorf("checksum mismatch: %x != %x", chksum, s.Checksum())
    87  	}
    88  
    89  	// Verify index is the correct size.
    90  	if len(s.Index()) != s.Cap()*8 {
    91  		return fmt.Errorf("unexpected index size: %d != %d", len(s.Index()), s.Cap()*8)
    92  	}
    93  
    94  	// Verify every index in bounds.
    95  	data, idx := s.Data(), s.Index()
    96  	for i := 0; i < s.Cap(); i++ {
    97  		offset := int64(binary.BigEndian.Uint64(idx[i*8:]))
    98  		if offset == 0 {
    99  			continue
   100  		} else if offset > int64(len(data)) {
   101  			return fmt.Errorf("offset out of bound: i=%d offset=%d", i, offset)
   102  		}
   103  	}
   104  
   105  	fmt.Println("")
   106  
   107  	return nil
   108  }