github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/eds/ods.go (about) 1 package eds 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "io" 10 11 cbor "github.com/ipfs/go-ipld-cbor" 12 "github.com/ipld/go-car" 13 "github.com/ipld/go-car/util" 14 ) 15 16 // bufferedODSReader will read odsSquareSize amount of leaves from reader into the buffer. 17 // It exposes the buffer to be read by io.Reader interface implementation 18 type bufferedODSReader struct { 19 carReader *bufio.Reader 20 // current is the amount of CARv1 encoded leaves that have been read from reader. When current 21 // reaches odsSquareSize, bufferedODSReader will prevent further reads by returning io.EOF 22 current, odsSquareSize int 23 buf *bytes.Buffer 24 } 25 26 // ODSReader reads CARv1 encoded data from io.ReadCloser and limits the reader to the CAR header 27 // and first quadrant (ODS) 28 func ODSReader(carReader io.Reader) (io.Reader, error) { 29 if carReader == nil { 30 return nil, errors.New("eds: can't create ODSReader over nil reader") 31 } 32 33 odsR := &bufferedODSReader{ 34 carReader: bufio.NewReader(carReader), 35 buf: new(bytes.Buffer), 36 } 37 38 // first LdRead reads the full CAR header to determine amount of shares in the ODS 39 data, err := util.LdRead(odsR.carReader) 40 if err != nil { 41 return nil, fmt.Errorf("reading header: %v", err) 42 } 43 44 var header car.CarHeader 45 err = cbor.DecodeInto(data, &header) 46 if err != nil { 47 return nil, fmt.Errorf("invalid header: %w", err) 48 } 49 50 // car header contains both row roots and col roots which is why 51 // we divide by 4 to get the ODSWidth 52 odsWidth := len(header.Roots) / 4 53 odsR.odsSquareSize = odsWidth * odsWidth 54 55 // NewCarReader will expect to read the header first, so write it first 56 return odsR, util.LdWrite(odsR.buf, data) 57 } 58 59 func (r *bufferedODSReader) Read(p []byte) (n int, err error) { 60 // read leafs to the buffer until it has sufficient data to fill provided container or full ods is 61 // read 62 for r.current < r.odsSquareSize && r.buf.Len() < len(p) { 63 if err := r.readLeaf(); err != nil { 64 return 0, err 65 } 66 67 r.current++ 68 } 69 70 // read buffer to slice 71 return r.buf.Read(p) 72 } 73 74 // readLeaf reads one leaf from reader into bufferedODSReader buffer 75 func (r *bufferedODSReader) readLeaf() error { 76 if _, err := r.carReader.Peek(1); err != nil { // no more blocks, likely clean io.EOF 77 return err 78 } 79 80 l, err := binary.ReadUvarint(r.carReader) 81 if err != nil { 82 if err == io.EOF { 83 return io.ErrUnexpectedEOF // don't silently pretend this is a clean EOF 84 } 85 return err 86 } 87 88 if l > uint64(util.MaxAllowedSectionSize) { // Don't OOM 89 return fmt.Errorf("malformed car; header `length`: %v is bigger than %v", l, util.MaxAllowedSectionSize) 90 } 91 92 buf := make([]byte, 8) 93 n := binary.PutUvarint(buf, l) 94 r.buf.Write(buf[:n]) 95 96 _, err = r.buf.ReadFrom(io.LimitReader(r.carReader, int64(l))) 97 return err 98 }