github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/u2u/genesisstore/disk.go (about) 1 package genesisstore 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "errors" 7 "fmt" 8 "io" 9 "strings" 10 "time" 11 12 "github.com/status-im/keycard-go/hexutils" 13 "github.com/syndtr/goleveldb/leveldb/opt" 14 "github.com/unicornultrafoundation/go-helios/common/bigendian" 15 "github.com/unicornultrafoundation/go-helios/hash" 16 "github.com/unicornultrafoundation/go-u2u/rlp" 17 18 "github.com/unicornultrafoundation/go-u2u/u2u/genesis" 19 "github.com/unicornultrafoundation/go-u2u/u2u/genesisstore/filelog" 20 "github.com/unicornultrafoundation/go-u2u/u2u/genesisstore/fileshash" 21 "github.com/unicornultrafoundation/go-u2u/u2u/genesisstore/readersmap" 22 "github.com/unicornultrafoundation/go-u2u/utils/ioread" 23 ) 24 25 var ( 26 FileHeader = hexutils.HexToBytes("641b00ac") 27 FileVersion = hexutils.HexToBytes("00020001") 28 ) 29 30 const ( 31 FilesHashMaxMemUsage = 256 * opt.MiB 32 FilesHashPieceSize = 64 * opt.MiB 33 ) 34 35 type dummyByteReader struct { 36 io.Reader 37 } 38 39 func (r dummyByteReader) ReadByte() (byte, error) { 40 b := make([]byte, 1) 41 err := ioread.ReadAll(r.Reader, b) 42 return b[0], err 43 } 44 45 func checkFileHeader(reader io.Reader) error { 46 headerAndVersion := make([]byte, len(FileHeader)+len(FileVersion)) 47 err := ioread.ReadAll(reader, headerAndVersion) 48 if err != nil { 49 return err 50 } 51 if bytes.Compare(headerAndVersion[:len(FileHeader)], FileHeader) != 0 { 52 return errors.New("expected a genesis file, mismatched file header") 53 } 54 if bytes.Compare(headerAndVersion[len(FileHeader):], FileVersion) != 0 { 55 got := hexutils.BytesToHex(headerAndVersion[len(FileHeader):]) 56 expected := hexutils.BytesToHex(FileVersion) 57 return errors.New(fmt.Sprintf("wrong version of genesis file, got=%s, expected=%s", got, expected)) 58 } 59 return nil 60 } 61 62 type ReadAtSeekerCloser interface { 63 io.ReaderAt 64 io.Seeker 65 io.Closer 66 } 67 68 type Unit struct { 69 UnitName string 70 Header genesis.Header 71 } 72 73 func OpenGenesisStore(rawReader ReadAtSeekerCloser) (*Store, genesis.Hashes, error) { 74 header := genesis.Header{} 75 hashes := genesis.Hashes{} 76 units := make([]readersmap.Unit, 0, 3) 77 offset := int64(0) 78 for i := 0; ; i++ { 79 // header cannot be long, cap it with 100000 bytes 80 headerReader := io.NewSectionReader(rawReader, offset, offset+100000) 81 err := checkFileHeader(headerReader) 82 if err == io.EOF { 83 break 84 } 85 if err != nil { 86 return nil, hashes, err 87 } 88 unit := Unit{} 89 err = rlp.Decode(dummyByteReader{headerReader}, &unit) 90 if err != nil { 91 return nil, hashes, err 92 } 93 if i == 0 { 94 header = unit.Header 95 } else { 96 if !header.Equal(unit.Header) { 97 return nil, hashes, errors.New("subsequent genesis header doesn't match the first header") 98 } 99 } 100 101 var h hash.Hash 102 err = ioread.ReadAll(headerReader, h[:]) 103 if err != nil { 104 return nil, hashes, err 105 } 106 hashes[unit.UnitName] = h 107 108 var numB [8]byte 109 err = ioread.ReadAll(headerReader, numB[:]) 110 if err != nil { 111 return nil, hashes, err 112 } 113 dataCompressedSize := bigendian.BytesToUint64(numB[:]) 114 115 err = ioread.ReadAll(headerReader, numB[:]) 116 if err != nil { 117 return nil, hashes, err 118 } 119 uncompressedSize := bigendian.BytesToUint64(numB[:]) 120 121 headerSize, err := headerReader.Seek(0, io.SeekCurrent) 122 if err != nil { 123 return nil, hashes, err 124 } 125 126 unitReader := io.NewSectionReader(rawReader, offset+headerSize, offset+headerSize+int64(dataCompressedSize)) 127 offset += headerSize + int64(dataCompressedSize) 128 129 gzipReader, err := gzip.NewReader(unitReader) 130 if err != nil { 131 return nil, hashes, err 132 } 133 134 // wrap with a logger 135 // human-readable name 136 name := unit.UnitName 137 scanfName := strings.ReplaceAll(name, "-", "") 138 if scanfName[len(scanfName)-1] < '0' || scanfName[len(scanfName)-1] > '9' { 139 scanfName += "0" 140 } 141 var part int 142 if _, err := fmt.Sscanf(scanfName, "brs%d", &part); err == nil { 143 name = fmt.Sprintf("blocks unit %d", part) 144 } 145 if _, err := fmt.Sscanf(scanfName, "ers%d", &part); err == nil { 146 name = fmt.Sprintf("epochs unit %d", part) 147 } 148 if _, err := fmt.Sscanf(scanfName, "evm%d", &part); err == nil { 149 name = fmt.Sprintf("EVM unit %d", part) 150 } 151 loggedReader := filelog.Wrap(gzipReader, name, uncompressedSize, time.Minute) 152 153 units = append(units, readersmap.Unit{ 154 Name: unit.UnitName, 155 Reader: loggedReader, 156 }) 157 } 158 159 unitsMap, err := readersmap.Wrap(units) 160 if err != nil { 161 return nil, hashes, err 162 } 163 164 hashedMap := fileshash.Wrap(unitsMap.Open, FilesHashMaxMemUsage, hashes) 165 166 return NewStore(hashedMap, header, rawReader.Close), hashes, nil 167 }