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  }