github.com/protolambda/zssz@v0.1.5/types/ssz_vector.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 "reflect" 11 "unsafe" 12 ) 13 14 type SSZVector struct { 15 length uint64 16 elemMemSize uintptr 17 elemSSZ SSZ 18 isFixedLen bool 19 fixedLen uint64 20 minLen uint64 21 maxLen uint64 22 fuzzMinLen uint64 23 fuzzMaxLen uint64 24 } 25 26 func NewSSZVector(factory SSZFactoryFn, typ reflect.Type) (*SSZVector, error) { 27 if typ.Kind() != reflect.Array { 28 return nil, fmt.Errorf("typ is not a fixed-length array") 29 } 30 length := uint64(typ.Len()) 31 elemTyp := typ.Elem() 32 33 elemSSZ, err := factory(elemTyp) 34 if err != nil { 35 return nil, err 36 } 37 var fixedElemLen, minElemLen, maxElemLen uint64 38 if elemSSZ.IsFixed() { 39 fixedElemLen = elemSSZ.FixedLen() 40 minElemLen = elemSSZ.MinLen() 41 maxElemLen = elemSSZ.MaxLen() 42 if fixedElemLen != minElemLen || fixedElemLen != maxElemLen { 43 return nil, fmt.Errorf("fixed-size element vector has invalid element min/max length:"+ 44 " fixed: %d min: %d max: %d ", fixedElemLen, minElemLen, maxElemLen) 45 } 46 } else { 47 fixedElemLen = BYTES_PER_LENGTH_OFFSET 48 minElemLen = BYTES_PER_LENGTH_OFFSET + elemSSZ.MinLen() 49 maxElemLen = BYTES_PER_LENGTH_OFFSET + elemSSZ.MaxLen() 50 } 51 res := &SSZVector{ 52 length: length, 53 elemMemSize: elemTyp.Size(), 54 elemSSZ: elemSSZ, 55 isFixedLen: elemSSZ.IsFixed(), 56 fixedLen: fixedElemLen * length, 57 minLen: minElemLen * length, 58 maxLen: maxElemLen * length, 59 fuzzMinLen: elemSSZ.FuzzMinLen() * length, 60 fuzzMaxLen: elemSSZ.FuzzMaxLen() * length, 61 } 62 return res, nil 63 } 64 65 func (v *SSZVector) FuzzMinLen() uint64 { 66 return v.fuzzMinLen 67 } 68 69 func (v *SSZVector) FuzzMaxLen() uint64 { 70 return v.fuzzMaxLen 71 } 72 73 func (v *SSZVector) MinLen() uint64 { 74 return v.minLen 75 } 76 77 func (v *SSZVector) MaxLen() uint64 { 78 return v.maxLen 79 } 80 81 func (v *SSZVector) FixedLen() uint64 { 82 return v.fixedLen 83 } 84 85 func (v *SSZVector) IsFixed() bool { 86 return v.isFixedLen 87 } 88 89 func (v *SSZVector) SizeOf(p unsafe.Pointer) uint64 { 90 if v.IsFixed() { 91 return v.fixedLen 92 } else { 93 out := v.fixedLen 94 memOffset := uintptr(0) 95 for i := uint64(0); i < v.length; i++ { 96 elemPtr := unsafe.Pointer(uintptr(p) + memOffset) 97 memOffset += v.elemMemSize 98 out += v.elemSSZ.SizeOf(elemPtr) 99 } 100 return out 101 } 102 } 103 104 func (v *SSZVector) Encode(eb *EncodingWriter, p unsafe.Pointer) error { 105 if v.IsFixed() { 106 return EncodeFixedSeries(v.elemSSZ.Encode, v.length, v.elemMemSize, eb, p) 107 } else { 108 return EncodeVarSeries(v.elemSSZ.Encode, v.elemSSZ.SizeOf, v.length, v.elemMemSize, eb, p) 109 } 110 } 111 112 func (v *SSZVector) Decode(dr *DecodingReader, p unsafe.Pointer) error { 113 if v.IsFixed() { 114 return DecodeFixedSeries(v.elemSSZ.Decode, v.length, v.elemMemSize, dr, p) 115 } else { 116 if dr.IsFuzzMode() { 117 return DecodeVarSeriesFuzzMode(v.elemSSZ, v.length, v.elemMemSize, dr, p) 118 } else { 119 return DecodeVarSeries(v.elemSSZ.Decode, v.length, v.elemMemSize, dr, p) 120 } 121 } 122 } 123 124 func (v *SSZVector) DryCheck(dr *DecodingReader) error { 125 if v.IsFixed() { 126 return DryCheckFixedSeries(v.elemSSZ.DryCheck, v.length, dr) 127 } else { 128 return DryCheckVarSeries(v.elemSSZ.DryCheck, v.length, dr) 129 } 130 } 131 132 func (v *SSZVector) HashTreeRoot(h MerkleFn, p unsafe.Pointer) [32]byte { 133 elemHtr := v.elemSSZ.HashTreeRoot 134 elemSize := v.elemMemSize 135 leaf := func(i uint64) []byte { 136 v := elemHtr(h, unsafe.Pointer(uintptr(p)+(elemSize*uintptr(i)))) 137 return v[:] 138 } 139 return merkle.Merkleize(h, v.length, v.length, leaf) 140 } 141 142 func (v *SSZVector) Pretty(indent uint32, w *PrettyWriter, p unsafe.Pointer) { 143 w.WriteIndent(indent) 144 w.Write("[\n") 145 CallSeries(func(i uint64, p unsafe.Pointer) { 146 v.elemSSZ.Pretty(indent+1, w, p) 147 if i == v.length-1 { 148 w.Write("\n") 149 } else { 150 w.Write(",\n") 151 } 152 }, v.length, v.elemMemSize, p) 153 w.WriteIndent(indent) 154 w.Write("]") 155 }