Repository: ferranbt/fastssz (go)

Issue:
`ssz.ExtendUint32` and `hh.AppendUint32` undefined error in the generated code
Hi,

I have the following struct and use `sszgen` to generate ssz code for it:
```
type Container struct {
	List []uint32 `ssz-max:"100"`
}
```
However, the generated code has two errors: 
- In `UnmarshalSSZ`: `undefined: ssz.ExtendUint32`
- In `HashTreeRootWith`: `hh.AppendUint32 undefined (type ssz.HashWalker has no field or method AppendUint32)`

Why does `fastssz` not support uint32 list?

Pull request:
Add support for uint32 lists
Closes #148 

Patch:
diff --git a/encode.go b/encode.go
index 5848023..9fe8d28 100644
--- a/encode.go
+++ b/encode.go
@@ -161,6 +161,18 @@ func ExtendUint64(b []uint64, needLen int) []uint64 {
 	return b[:needLen]
 }
 
+// ExtendUint32 extends a uint32 buffer to a given size
+func ExtendUint32(b []uint32, needLen int) []uint32 {
+	if b == nil {
+		b = []uint32{}
+	}
+	b = b[:cap(b)]
+	if n := needLen - cap(b); n > 0 {
+		b = append(b, make([]uint32, n)...)
+	}
+	return b[:needLen]
+}
+
 // ExtendUint16 extends a uint16 buffer to a given size
 func ExtendUint16(b []uint16, needLen int) []uint16 {
 	if b == nil {
diff --git a/hasher.go b/hasher.go
index ec3975d..ee5cdfb 100755
--- a/hasher.go
+++ b/hasher.go
@@ -150,6 +150,10 @@ func (h *Hasher) AppendUint8(i uint8) {
 	h.buf = MarshalUint8(h.buf, i)
 }
 
+func (h *Hasher) AppendUint32(i uint32) {
+	h.buf = MarshalUint32(h.buf, i)
+}
+
 func (h *Hasher) AppendUint64(i uint64) {
 	h.buf = MarshalUint64(h.buf, i)
 }
diff --git a/interface.go b/interface.go
index c35dea5..ad5eb11 100644
--- a/interface.go
+++ b/interface.go
@@ -22,6 +22,7 @@ type HashWalker interface {
 	// Intended for testing purposes to know the latest hash generated during merkleize
 	Hash() []byte
 	AppendUint8(i uint8)
+	AppendUint32(i uint32)
 	AppendUint64(i uint64)
 	AppendBytes32(b []byte)
 	PutUint64Array(b []uint64, maxCapacity ...uint64)
diff --git a/wrapper.go b/wrapper.go
index af9bff5..4c585c3 100644
--- a/wrapper.go
+++ b/wrapper.go
@@ -31,6 +31,10 @@ func (w *Wrapper) AppendUint64(i uint64) {
 	w.buf = MarshalUint64(w.buf, i)
 }
 
+func (w *Wrapper) AppendUint32(i uint32) {
+	w.buf = MarshalUint32(w.buf, i)
+}
+
 func (w *Wrapper) AppendUint8(i uint8) {
 	w.buf = MarshalUint8(w.buf, i)
 }


Test patch:
diff --git a/sszgen/testcases/container.go b/sszgen/testcases/container.go
index 4285c00..ef66361 100644
--- a/sszgen/testcases/container.go
+++ b/sszgen/testcases/container.go
@@ -5,3 +5,7 @@ package testcases
 type Vec struct {
 	Values []uint64 `ssz-size:"6"`
 }
+
+type Vec2 struct {
+	Values2 []uint32 `ssz-max:"100"`
+}
diff --git a/sszgen/testcases/container_encoding.go b/sszgen/testcases/container_encoding.go
index 166bb37..bf78da9 100644
--- a/sszgen/testcases/container_encoding.go
+++ b/sszgen/testcases/container_encoding.go
@@ -1,5 +1,5 @@
 // Code generated by fastssz. DO NOT EDIT.
-// Hash: acb511949371bd93802219589c0d97145e86ad6f3573e53f612cf206ac868df4
+// Hash: b05b1d4bd1edc06c10690d812bb9c15ef308ef91a59c5c38b2a8215f12440e48
 // Version: 0.1.3
 package testcases
 
@@ -81,3 +81,107 @@ func (v *Vec) HashTreeRootWith(hh ssz.HashWalker) (err error) {
 func (v *Vec) GetTree() (*ssz.Node, error) {
 	return ssz.ProofTree(v)
 }
+
+// MarshalSSZ ssz marshals the Vec2 object
+func (v *Vec2) MarshalSSZ() ([]byte, error) {
+	return ssz.MarshalSSZ(v)
+}
+
+// MarshalSSZTo ssz marshals the Vec2 object to a target array
+func (v *Vec2) MarshalSSZTo(buf []byte) (dst []byte, err error) {
+	dst = buf
+	offset := int(4)
+
+	// Offset (0) 'Values2'
+	dst = ssz.WriteOffset(dst, offset)
+	offset += len(v.Values2) * 4
+
+	// Field (0) 'Values2'
+	if size := len(v.Values2); size > 100 {
+		err = ssz.ErrListTooBigFn("Vec2.Values2", size, 100)
+		return
+	}
+	for ii := 0; ii < len(v.Values2); ii++ {
+		dst = ssz.MarshalUint32(dst, v.Values2[ii])
+	}
+
+	return
+}
+
+// UnmarshalSSZ ssz unmarshals the Vec2 object
+func (v *Vec2) UnmarshalSSZ(buf []byte) error {
+	var err error
+	size := uint64(len(buf))
+	if size < 4 {
+		return ssz.ErrSize
+	}
+
+	tail := buf
+	var o0 uint64
+
+	// Offset (0) 'Values2'
+	if o0 = ssz.ReadOffset(buf[0:4]); o0 > size {
+		return ssz.ErrOffset
+	}
+
+	if o0 < 4 {
+		return ssz.ErrInvalidVariableOffset
+	}
+
+	// Field (0) 'Values2'
+	{
+		buf = tail[o0:]
+		num, err := ssz.DivideInt2(len(buf), 4, 100)
+		if err != nil {
+			return err
+		}
+		v.Values2 = ssz.ExtendUint32(v.Values2, num)
+		for ii := 0; ii < num; ii++ {
+			v.Values2[ii] = ssz.UnmarshallUint32(buf[ii*4 : (ii+1)*4])
+		}
+	}
+	return err
+}
+
+// SizeSSZ returns the ssz encoded size in bytes for the Vec2 object
+func (v *Vec2) SizeSSZ() (size int) {
+	size = 4
+
+	// Field (0) 'Values2'
+	size += len(v.Values2) * 4
+
+	return
+}
+
+// HashTreeRoot ssz hashes the Vec2 object
+func (v *Vec2) HashTreeRoot() ([32]byte, error) {
+	return ssz.HashWithDefaultHasher(v)
+}
+
+// HashTreeRootWith ssz hashes the Vec2 object with a hasher
+func (v *Vec2) HashTreeRootWith(hh ssz.HashWalker) (err error) {
+	indx := hh.Index()
+
+	// Field (0) 'Values2'
+	{
+		if size := len(v.Values2); size > 100 {
+			err = ssz.ErrListTooBigFn("Vec2.Values2", size, 100)
+			return
+		}
+		subIndx := hh.Index()
+		for _, i := range v.Values2 {
+			hh.AppendUint32(i)
+		}
+		hh.FillUpTo32()
+		numItems := uint64(len(v.Values2))
+		hh.MerkleizeWithMixin(subIndx, numItems, ssz.CalculateLimit(100, numItems, 4))
+	}
+
+	hh.Merkleize(indx)
+	return
+}
+
+// GetTree ssz hashes the Vec2 object
+func (v *Vec2) GetTree() (*ssz.Node, error) {
+	return ssz.ProofTree(v)
+}