github.com/protolambda/zssz@v0.1.5/types/ssz_bytes.go (about) 1 package types 2 3 import ( 4 "fmt" 5 . "github.com/protolambda/zssz/dec" 6 . "github.com/protolambda/zssz/enc" 7 . "github.com/protolambda/zssz/htr" 8 "github.com/protolambda/zssz/merkle" 9 . "github.com/protolambda/zssz/pretty" 10 "github.com/protolambda/zssz/util/ptrutil" 11 "reflect" 12 "unsafe" 13 ) 14 15 type SSZBytes struct { 16 limit uint64 17 } 18 19 func NewSSZBytes(typ reflect.Type) (*SSZBytes, error) { 20 if typ.Kind() != reflect.Slice { 21 return nil, fmt.Errorf("typ is not a dynamic-length bytes slice") 22 } 23 if typ.Elem().Kind() != reflect.Uint8 { 24 return nil, fmt.Errorf("typ is not a bytes slice") 25 } 26 limit, err := ReadListLimit(typ) 27 if err != nil { 28 return nil, err 29 } 30 return &SSZBytes{limit: limit}, nil 31 } 32 33 func (v *SSZBytes) FuzzMinLen() uint64 { 34 return 8 35 } 36 37 func (v *SSZBytes) FuzzMaxLen() uint64 { 38 return 8 + v.limit 39 } 40 41 func (v *SSZBytes) MinLen() uint64 { 42 return 0 43 } 44 45 func (v *SSZBytes) MaxLen() uint64 { 46 return v.limit 47 } 48 49 func (v *SSZBytes) FixedLen() uint64 { 50 return 0 51 } 52 53 func (v *SSZBytes) IsFixed() bool { 54 return false 55 } 56 57 func (v *SSZBytes) SizeOf(p unsafe.Pointer) uint64 { 58 sh := ptrutil.ReadSliceHeader(p) 59 return uint64(sh.Len) 60 } 61 62 func (v *SSZBytes) Encode(eb *EncodingWriter, p unsafe.Pointer) error { 63 sh := ptrutil.ReadSliceHeader(p) 64 data := *(*[]byte)(unsafe.Pointer(sh)) 65 return eb.Write(data) 66 } 67 68 func (v *SSZBytes) Decode(dr *DecodingReader, p unsafe.Pointer) error { 69 var length uint64 70 if dr.IsFuzzMode() { 71 x, err := dr.ReadUint64() 72 if err != nil { 73 return err 74 } 75 span := dr.GetBytesSpan() 76 if span > v.limit { 77 span = v.limit 78 } 79 if span != 0 { 80 length = x % span 81 } 82 } else { 83 length = dr.GetBytesSpan() 84 } 85 if length > v.limit { 86 return fmt.Errorf("got %d bytes, expected no more than %d bytes", length, v.limit) 87 } 88 ptrutil.BytesAllocFn(p, length) 89 data := *(*[]byte)(p) 90 _, err := dr.Read(data) 91 return err 92 } 93 94 func (v *SSZBytes) DryCheck(dr *DecodingReader) error { 95 _, err := dr.Skip(dr.GetBytesSpan()) 96 return err 97 } 98 99 func (v *SSZBytes) HashTreeRoot(h MerkleFn, p unsafe.Pointer) [32]byte { 100 sh := ptrutil.ReadSliceHeader(p) 101 data := *(*[]byte)(unsafe.Pointer(sh)) 102 dataLen := uint64(len(data)) 103 leafCount := (dataLen + 31) >> 5 104 leafLimit := (v.limit + 31) >> 5 105 leaf := func(i uint64) []byte { 106 s := i << 5 107 e := (i + 1) << 5 108 // pad the data 109 if e > dataLen { 110 x := [32]byte{} 111 copy(x[:], data[s:dataLen]) 112 return x[:] 113 } 114 return data[s:e] 115 } 116 return h.MixIn(merkle.Merkleize(h, leafCount, leafLimit, leaf), dataLen) 117 } 118 119 func (v *SSZBytes) Pretty(indent uint32, w *PrettyWriter, p unsafe.Pointer) { 120 w.WriteIndent(indent) 121 sh := ptrutil.ReadSliceHeader(p) 122 data := *(*[]byte)(unsafe.Pointer(sh)) 123 w.Write(fmt.Sprintf("0x%x", data)) 124 }