# EPF6 - Week 16 & 17 Updates
## tl;dr
- Trying to use `Marshaler` interface in `fastssz`, so that we can remove several logics for `Size()` function. (draft [PR](https://github.com/syjn99/prysm/pull/6))
- Not related to this cohort, but I've been busy for a couple of weeks participating [PQ Workshop](https://x.com/corcoranwill/status/1974417509773353230) at Cambridge, UK.
## Details
```go!
func (info *sszInfo) Size() uint64 {
if info == nil {
return 0
}
// Easy case: if the type is not variable, we can return the fixed size.
if !info.isVariable {
return info.fixedSize
}
switch info.sszType {
case List:
return info.listInfo.Size()
case Bitlist:
return info.bitlistInfo.Size()
case Container:
panic("PLACEHOLDER PANIC IF THIS IS CALLED OR NOT")
size := info.fixedSize
for _, fieldInfo := range info.containerInfo.fields {
if !fieldInfo.sszInfo.isVariable {
continue
}
// Include offset bytes inside nested lists.
if fieldInfo.sszInfo.sszType == List {
size += fieldInfo.sszInfo.listInfo.OffsetBytes()
}
size += fieldInfo.sszInfo.Size()
}
return size
default:
return 0
}
}
```
Current version has `Size` method that calculates the actual size of SSZ object in bytes. But my mentor suggested to leverage existing `fastssz` APIs like `SizeSSZ()`:
```go!
// Marshaler is the interface implemented by types that can marshal themselves into valid SZZ.
type Marshaler interface {
MarshalSSZTo(dst []byte) ([]byte, error)
MarshalSSZ() ([]byte, error)
SizeSSZ() int
}
```
`SizeSSZ()` is *automatically* generated with `sszgen` tool like:
```go!
// SizeSSZ returns the ssz encoded size in bytes for the VariableNestedContainer object
func (v *VariableNestedContainer) SizeSSZ() (size int) {
size = 16
// Field (1) 'FieldListUint64'
size += len(v.FieldListUint64) * 8
// Field (2) 'NestedListField'
for ii := 0; ii < len(v.NestedListField); ii++ {
size += 4
size += len(v.NestedListField[ii])
}
return
}
```
So it would be best if we can replace the whole `Size()` function like:
```go!
func (info *sszInfo) Size() uint64 {
if info == nil {
return 0
}
return uint64(info.source.SizeSSZ())
}
```
where `source` is the pointer to the original SSZ object. (e.g., `*VariableNestedContainer`)
---
In the meantime, Nando was also trying to use `HashTreeRoot()` method that is also *automatically* generated in this [PR](https://github.com/OffchainLabs/prysm/pull/15805). I found we're facing same issue about using `fastssz` interfaces. We need to (somehow) store the **pointer** of SSZ object in `sszInfo` struct. Nando's approach was great to start this, by 1) accepting an interface `SSZObject` as an argument and 2) setting `source` in the function `AnalyzeObject`.
```go
func AnalyzeObject(obj SSZObject) (*sszInfo, error) {
// ...
// Store the original object interface
info.source = obj
// ...
}
```
I started with his idea and found that this approach has a limitation to **recursively** call `SizeSSZ()` method. `AnalyzeObject` is an entry function for building a new `sszInfo` instance, and the actual recursion is happening in `analyzeType` function:
```go!
// analyzeType is an entry point that inspects a reflect.Type and computes its SSZ layout information.
func analyzeType(typ reflect.Type, tag *reflect.StructTag) (*sszInfo, error) {
switch typ.Kind() {
// Basic types (e.g., uintN where N is 8, 16, 32, 64)
// NOTE: uint128 and uint256 are represented as []byte in Go,
// so we handle them as slices. See `analyzeHomogeneousColType`.
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Bool:
return analyzeBasicType(typ)
case reflect.Slice:
return analyzeHomogeneousColType(typ, tag)
case reflect.Struct:
return analyzeContainerType(typ)
case reflect.Ptr:
// Dereference pointer types.
return analyzeType(typ.Elem(), tag)
default:
return nil, fmt.Errorf("unsupported type %v for SSZ calculation", typ.Kind())
}
}
```
{%preview https://github.com/syjn99/prysm/pull/6 %}
Therefore, I'm trying to achieve **recursively store pointers in `sszInfo`** in the above PR. Playing with pointer and reflection is quite tough but I'm quite sure I found some breakthrough to resolve the issue that Radek raised a couple of weeks ago.