github.com/protolambda/zssz@v0.1.5/zssz_test.go (about)

     1  package zssz
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"crypto/sha256"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"fmt"
    10  	"github.com/protolambda/zssz/bitfields"
    11  	"github.com/protolambda/zssz/htr"
    12  	. "github.com/protolambda/zssz/types"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  type emptyTestStruct struct{}
    19  
    20  type singleFieldTestStruct struct {
    21  	A byte
    22  }
    23  
    24  type smallTestStruct struct {
    25  	A uint16
    26  	B uint16
    27  }
    28  
    29  type fixedTestStruct struct {
    30  	A uint8
    31  	B uint64
    32  	C uint32
    33  }
    34  
    35  type withPointerChildren struct {
    36  	A *smallTestStruct
    37  	B fixedTestStruct
    38  	C *uint64
    39  }
    40  
    41  type uint16List128 []uint16
    42  
    43  func (li *uint16List128) Limit() uint64 {
    44  	return 128
    45  }
    46  
    47  type uint16List1024 []uint16
    48  
    49  func (li *uint16List1024) Limit() uint64 {
    50  	return 1024
    51  }
    52  
    53  type bytelist256 []byte
    54  
    55  func (li *bytelist256) Limit() uint64 {
    56  	return 256
    57  }
    58  
    59  type VarTestStruct struct {
    60  	A uint16
    61  	B uint16List1024
    62  	C uint8
    63  }
    64  
    65  type complexTestStruct struct {
    66  	A uint16
    67  	B uint16List128
    68  	C uint8
    69  	D bytelist256
    70  	E VarTestStruct
    71  	F [4]fixedTestStruct
    72  	G [2]VarTestStruct
    73  }
    74  
    75  type embeddingStruct struct {
    76  	A             VarTestStruct
    77  	VarTestStruct // squash field by embedding (must be a public type)
    78  	B             uint16
    79  	Foo           smallTestStruct `ssz:"squash"` // Squash field explicitly
    80  }
    81  
    82  type ListA []smallTestStruct
    83  
    84  func (*ListA) Limit() uint64 { return 4 }
    85  
    86  type ListB []VarTestStruct
    87  
    88  func (*ListB) Limit() uint64 { return 8 }
    89  
    90  type ListStruct struct {
    91  	A ListA
    92  	B ListB
    93  }
    94  
    95  type Squash1 struct {
    96  	A uint8
    97  	D *uint32 `ssz:"omit"`
    98  	B uint64
    99  	C uint32
   100  }
   101  
   102  type Squash2 struct {
   103  	D uint32
   104  	E uint8 `ssz:"omit"`
   105  	Squash1
   106  	More Squash1 `ssz:"squash"`
   107  }
   108  
   109  type Squash3 struct {
   110  	Foo Squash1 `ssz:"squash"`
   111  	Squash1
   112  	X   Squash2 `ssz:"squash"`
   113  	Bar Squash1 `ssz:"squash"`
   114  	Squash2
   115  }
   116  
   117  func chunk(v string) string {
   118  	res := [32]byte{}
   119  	data, _ := hex.DecodeString(v)
   120  	copy(res[:], data)
   121  	return hex.EncodeToString(res[:])
   122  }
   123  
   124  func h(a string, b string) string {
   125  	aBytes, _ := hex.DecodeString(a)
   126  	bBytes, _ := hex.DecodeString(b)
   127  	data := append(append(make([]byte, 0, 64), aBytes...), bBytes...)
   128  	res := sha256.Sum256(data)
   129  	return hex.EncodeToString(res[:])
   130  }
   131  
   132  func merge(a string, branch []string) (out string) {
   133  	out = a
   134  	for _, b := range branch {
   135  		out = h(out, b)
   136  	}
   137  	return
   138  }
   139  
   140  func repeat(v string, count int) (out string) {
   141  	for i := 0; i < count; i++ {
   142  		out += v
   143  	}
   144  	return
   145  }
   146  
   147  // Many different Bitvector types for testing
   148  
   149  type bitvec513 [64 + 1]byte
   150  
   151  func (*bitvec513) BitLen() uint64 { return 513 }
   152  
   153  type bitvec512 [64]byte
   154  
   155  func (*bitvec512) BitLen() uint64 { return 512 }
   156  
   157  type bitvec16 [2]byte
   158  
   159  func (*bitvec16) BitLen() uint64 { return 16 }
   160  
   161  type bitvec10 [2]byte
   162  
   163  func (*bitvec10) BitLen() uint64 { return 10 }
   164  
   165  type bitvec8 [1]byte
   166  
   167  func (*bitvec8) BitLen() uint64 { return 8 }
   168  
   169  type bitvec4 [1]byte
   170  
   171  func (*bitvec4) BitLen() uint64 { return 4 }
   172  
   173  type bitvec3 [1]byte
   174  
   175  func (*bitvec3) BitLen() uint64 { return 3 }
   176  
   177  // Many different Bitlist types for testing
   178  
   179  type bitlist513 []byte
   180  
   181  func (*bitlist513) Limit() uint64   { return 513 }
   182  func (b bitlist513) BitLen() uint64 { return bitfields.BitlistLen(b) }
   183  
   184  type bitlist512 []byte
   185  
   186  func (*bitlist512) Limit() uint64   { return 512 }
   187  func (b bitlist512) BitLen() uint64 { return bitfields.BitlistLen(b) }
   188  
   189  type bitlist16 []byte
   190  
   191  func (*bitlist16) Limit() uint64   { return 16 }
   192  func (b bitlist16) BitLen() uint64 { return bitfields.BitlistLen(b) }
   193  
   194  type bitlist10 []byte
   195  
   196  func (*bitlist10) Limit() uint64   { return 10 }
   197  func (b bitlist10) BitLen() uint64 { return bitfields.BitlistLen(b) }
   198  
   199  type bitlist8 []byte
   200  
   201  func (*bitlist8) Limit() uint64   { return 8 }
   202  func (b bitlist8) BitLen() uint64 { return bitfields.BitlistLen(b) }
   203  
   204  type bitlist4 []byte
   205  
   206  func (*bitlist4) Limit() uint64   { return 4 }
   207  func (b bitlist4) BitLen() uint64 { return bitfields.BitlistLen(b) }
   208  
   209  type bitlist3 []byte
   210  
   211  func (*bitlist3) Limit() uint64   { return 3 }
   212  func (b bitlist3) BitLen() uint64 { return bitfields.BitlistLen(b) }
   213  
   214  // Some list types for testing
   215  
   216  type list32uint16 []uint16
   217  
   218  func (*list32uint16) Limit() uint64 { return 32 }
   219  
   220  type list128uint32 []uint32
   221  
   222  func (*list128uint32) Limit() uint64 { return 128 }
   223  
   224  type list64bytes32 [][32]byte
   225  
   226  func (*list64bytes32) Limit() uint64 { return 64 }
   227  
   228  type list128bytes32 [][32]byte
   229  
   230  func (*list128bytes32) Limit() uint64 { return 128 }
   231  
   232  func getTyp(ptr interface{}) reflect.Type {
   233  	return reflect.TypeOf(ptr).Elem()
   234  }
   235  
   236  type sszTestCase struct {
   237  	// name of test
   238  	name string
   239  	// any value
   240  	value interface{}
   241  	// hex formatted, no prefix
   242  	hex string
   243  	// hex formatted, no prefix
   244  	root string
   245  	// typ getter
   246  	typ reflect.Type
   247  }
   248  
   249  // note: expected strings are in little-endian, hence the seemingly out of order bytes.
   250  var testCases []sszTestCase
   251  
   252  var valUint64 uint64 = 0x42
   253  
   254  func init() {
   255  	var zeroHashes = []string{chunk("")}
   256  
   257  	for layer := 1; layer < 32; layer++ {
   258  		zeroHashes = append(zeroHashes, h(zeroHashes[layer-1], zeroHashes[layer-1]))
   259  	}
   260  
   261  	testCases = []sszTestCase{
   262  		{"bool F", false, "00", chunk("00"), getTyp((*bool)(nil))},
   263  		{"bool T", true, "01", chunk("01"), getTyp((*bool)(nil))},
   264  		{"bitvector TTFTFTFF", bitvec8{0x2b}, "2b", chunk("2b"), getTyp((*bitvec8)(nil))},
   265  		{"bitlist TTFTFTFF", bitlist8{0x2b, 0x01}, "2b01", h(chunk("2b"), chunk("08")), getTyp((*bitlist8)(nil))},
   266  		{"bitvector FTFT", bitvec4{0x0a}, "0a", chunk("0a"), getTyp((*bitvec4)(nil))},
   267  		{"bitlist FTFT", bitlist4{0x1a}, "1a", h(chunk("0a"), chunk("04")), getTyp((*bitlist4)(nil))},
   268  		{"bitvector FTF", bitvec3{0x02}, "02", chunk("02"), getTyp((*bitvec3)(nil))},
   269  		{"bitlist FTF", bitlist3{0x0a}, "0a", h(chunk("02"), chunk("03")), getTyp((*bitlist3)(nil))},
   270  		{"bitvector TFTFFFTTFT", bitvec10{0xc5, 0x02}, "c502", chunk("c502"), getTyp((*bitvec10)(nil))},
   271  		{"bitlist TFTFFFTTFT", bitlist10{0xc5, 0x06}, "c506", h(chunk("c502"), chunk("0A")), getTyp((*bitlist10)(nil))},
   272  		{"bitvector TFTFFFTTFTFFFFTT", bitvec16{0xc5, 0xc2}, "c5c2", chunk("c5c2"), getTyp((*bitvec16)(nil))},
   273  		{"bitlist TFTFFFTTFTFFFFTT", bitlist16{0xc5, 0xc2, 0x01}, "c5c201", h(chunk("c5c2"), chunk("10")), getTyp((*bitlist16)(nil))},
   274  		{"long bitvector", bitvec512{
   275  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   276  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   277  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   278  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   279  		}, repeat("ff", 64), h(repeat("ff", 32), repeat("ff", 32)), getTyp((*bitvec512)(nil)),
   280  		},
   281  		{"long bitlist", bitlist512{7}, "07", h(h(chunk("03"), chunk("")), chunk("02")), getTyp((*bitlist512)(nil))},
   282  		{"long bitlist filled", bitlist512{
   283  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   284  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   285  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   286  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   287  			0x01,
   288  		}, repeat("ff", 64) + "01", h(h(repeat("ff", 32), repeat("ff", 32)), chunk("0002")), getTyp((*bitlist512)(nil))},
   289  		{"odd bitvector filled", bitvec513{
   290  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   291  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   292  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   293  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   294  			0x01,
   295  		}, repeat("ff", 64) + "01", h(h(repeat("ff", 32), repeat("ff", 32)), h(chunk("01"), chunk(""))), getTyp((*bitvec513)(nil))},
   296  		{"odd bitlist filled", bitlist513{
   297  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   298  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   299  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   300  			0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   301  			0x03,
   302  		}, repeat("ff", 64) + "03", h(h(h(repeat("ff", 32), repeat("ff", 32)), h(chunk("01"), chunk(""))), chunk("0102")), getTyp((*bitlist513)(nil))},
   303  		{"uint8 00", uint8(0x00), "00", chunk("00"), getTyp((*uint8)(nil))},
   304  		{"uint8 01", uint8(0x01), "01", chunk("01"), getTyp((*uint8)(nil))},
   305  		{"uint8 ab", uint8(0xab), "ab", chunk("ab"), getTyp((*uint8)(nil))},
   306  		{"uint16 0000", uint16(0x0000), "0000", chunk("0000"), getTyp((*uint16)(nil))},
   307  		{"uint16 abcd", uint16(0xabcd), "cdab", chunk("cdab"), getTyp((*uint16)(nil))},
   308  		{"uint32 00000000", uint32(0x00000000), "00000000", chunk("00000000"), getTyp((*uint32)(nil))},
   309  		{"uint32 01234567", uint32(0x01234567), "67452301", chunk("67452301"), getTyp((*uint32)(nil))},
   310  		{"small {4567, 0123}", smallTestStruct{0x4567, 0x0123}, "67452301", h(chunk("6745"), chunk("2301")), getTyp((*smallTestStruct)(nil))},
   311  		{"small [4567, 0123]::2", [2]uint16{0x4567, 0x0123}, "67452301", chunk("67452301"), getTyp((*[2]uint16)(nil))},
   312  		{"uint32 01234567", uint32(0x01234567), "67452301", chunk("67452301"), getTyp((*uint32)(nil))},
   313  		{"uint64 0000000000000000", uint64(0x00000000), "0000000000000000", chunk("0000000000000000"), getTyp((*uint64)(nil))},
   314  		{"uint64 0123456789abcdef", uint64(0x0123456789abcdef), "efcdab8967452301", chunk("efcdab8967452301"), getTyp((*uint64)(nil))},
   315  		{"sig", [96]byte{0: 1, 32: 2, 64: 3, 95: 0xff},
   316  			"01" + repeat("00", 31) + "02" + repeat("00", 31) + "03" + repeat("00", 30) + "ff",
   317  			h(h(chunk("01"), chunk("02")), h("03"+repeat("00", 30)+"ff", chunk(""))), getTyp((*[96]byte)(nil))},
   318  		{"emptyTestStruct", emptyTestStruct{}, "", chunk(""), getTyp((*emptyTestStruct)(nil))},
   319  		{"singleFieldTestStruct", singleFieldTestStruct{0xab}, "ab", chunk("ab"), getTyp((*singleFieldTestStruct)(nil))},
   320  
   321  		{"uint16 list", list32uint16{0xaabb, 0xc0ad, 0xeeff}, "bbaaadc0ffee",
   322  			h(h(chunk("bbaaadc0ffee"), chunk("")), chunk("03000000")), // max length: 32 * 2 = 64 bytes = 2 chunks
   323  			getTyp((*list32uint16)(nil)),
   324  		},
   325  		{"uint32 list", list128uint32{0xaabb, 0xc0ad, 0xeeff}, "bbaa0000adc00000ffee0000",
   326  			// max length: 128 * 4 = 512 bytes = 16 chunks
   327  			h(merge(chunk("bbaa0000adc00000ffee0000"), zeroHashes[0:4]), chunk("03000000")),
   328  			getTyp((*list128uint32)(nil)),
   329  		},
   330  		{"bytes32 list", list64bytes32{[32]byte{0xbb, 0xaa}, [32]byte{0xad, 0xc0}, [32]byte{0xff, 0xee}},
   331  			"bbaa000000000000000000000000000000000000000000000000000000000000" +
   332  				"adc0000000000000000000000000000000000000000000000000000000000000" +
   333  				"ffee000000000000000000000000000000000000000000000000000000000000",
   334  			h(merge(h(h(chunk("bbaa"), chunk("adc0")), h(chunk("ffee"), chunk(""))), zeroHashes[2:6]), chunk("03000000")),
   335  			getTyp((*list64bytes32)(nil)),
   336  		},
   337  		{"bytes32 list long", list128bytes32{
   338  			{1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10},
   339  			{11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19},
   340  		},
   341  			"01" + repeat("00", 31) + "02" + repeat("00", 31) +
   342  				"03" + repeat("00", 31) + "04" + repeat("00", 31) +
   343  				"05" + repeat("00", 31) + "06" + repeat("00", 31) +
   344  				"07" + repeat("00", 31) + "08" + repeat("00", 31) +
   345  				"09" + repeat("00", 31) + "0a" + repeat("00", 31) +
   346  				"0b" + repeat("00", 31) + "0c" + repeat("00", 31) +
   347  				"0d" + repeat("00", 31) + "0e" + repeat("00", 31) +
   348  				"0f" + repeat("00", 31) + "10" + repeat("00", 31) +
   349  				"11" + repeat("00", 31) + "12" + repeat("00", 31) +
   350  				"13" + repeat("00", 31),
   351  			h(merge(
   352  				h(
   353  					h(
   354  						h(
   355  							h(h(chunk("01"), chunk("02")), h(chunk("03"), chunk("04"))),
   356  							h(h(chunk("05"), chunk("06")), h(chunk("07"), chunk("08"))),
   357  						),
   358  						h(
   359  							h(h(chunk("09"), chunk("0a")), h(chunk("0b"), chunk("0c"))),
   360  							h(h(chunk("0d"), chunk("0e")), h(chunk("0f"), chunk("10"))),
   361  						),
   362  					),
   363  					h(
   364  						h(
   365  							h(h(chunk("11"), chunk("12")), h(chunk("13"), chunk(""))),
   366  							zeroHashes[2],
   367  						),
   368  						zeroHashes[3],
   369  					),
   370  				),
   371  				// 128 chunks = 7 deep
   372  				zeroHashes[5:7]), chunk("13000000")),
   373  			getTyp((*list128bytes32)(nil)),
   374  		},
   375  		{"withPointerChildren", withPointerChildren{
   376  			A: &smallTestStruct{A: 0x1122, B: 0x3344},
   377  			B: fixedTestStruct{A: 0xab, B: 0xaabbccdd00112233, C: 0x12345678},
   378  			C: &valUint64,
   379  		}, "22114433" + "ab33221100ddccbbaa78563412" + "4200000000000000", h(
   380  			h(
   381  				h(chunk("2211"), chunk("4433")),
   382  				h(h(chunk("ab"), chunk("33221100ddccbbaa")), h(chunk("78563412"), chunk(""))),
   383  			),
   384  			h(chunk("42"), chunk("")),
   385  		), getTyp((*withPointerChildren)(nil))},
   386  		{"fixedTestStruct", fixedTestStruct{A: 0xab, B: 0xaabbccdd00112233, C: 0x12345678}, "ab33221100ddccbbaa78563412",
   387  			h(h(chunk("ab"), chunk("33221100ddccbbaa")), h(chunk("78563412"), chunk(""))), getTyp((*fixedTestStruct)(nil))},
   388  		{"VarTestStruct nil", VarTestStruct{A: 0xabcd, B: nil, C: 0xff}, "cdab07000000ff",
   389  			// log2(1024*2/32)= 6 deep
   390  			h(h(chunk("cdab"), h(zeroHashes[6], chunk("00000000"))), h(chunk("ff"), chunk(""))), getTyp((*VarTestStruct)(nil))},
   391  		{"VarTestStruct empty", VarTestStruct{A: 0xabcd, B: make([]uint16, 0), C: 0xff}, "cdab07000000ff",
   392  			h(h(chunk("cdab"), h(zeroHashes[6], chunk("00000000"))), h(chunk("ff"), chunk(""))), getTyp((*VarTestStruct)(nil))},
   393  		{"VarTestStruct some", VarTestStruct{A: 0xabcd, B: []uint16{1, 2, 3}, C: 0xff}, "cdab07000000ff010002000300",
   394  			h(
   395  				h(
   396  					chunk("cdab"),
   397  					h(
   398  						merge(
   399  							chunk("010002000300"),
   400  							zeroHashes[0:6],
   401  						),
   402  						chunk("03000000"), // length mix in
   403  					),
   404  				),
   405  				h(chunk("ff"), chunk("")),
   406  			),
   407  			getTyp((*VarTestStruct)(nil))},
   408  		{"empty list", ListA{}, "", h(zeroHashes[2], chunk("00000000")), getTyp((*ListA)(nil))},
   409  		{"empty var element list", ListB{}, "", h(zeroHashes[3], chunk("00000000")), getTyp((*ListB)(nil))},
   410  		{"var element list", ListB{
   411  			{A: 0xdead, B: []uint16{1, 2, 3}, C: 0x11},
   412  			{A: 0xbeef, B: []uint16{4, 5, 6}, C: 0x22}},
   413  			"08000000" + "15000000" +
   414  				"adde0700000011010002000300" +
   415  				"efbe0700000022040005000600",
   416  			h(h(
   417  				h(
   418  					h(
   419  						h(h(chunk("adde"), h(merge(chunk("010002000300"), zeroHashes[0:6]), chunk("03000000"))),
   420  							h(chunk("11"), chunk(""))),
   421  						h(h(chunk("efbe"), h(merge(chunk("040005000600"), zeroHashes[0:6]), chunk("03000000"))),
   422  							h(chunk("22"), chunk(""))),
   423  					),
   424  					zeroHashes[1],
   425  				),
   426  				zeroHashes[2],
   427  			), chunk("02000000")), getTyp((*ListB)(nil))},
   428  		{"empty list fields", ListStruct{}, "08000000" + "08000000",
   429  			h(h(zeroHashes[2], chunk("")), h(zeroHashes[3], chunk(""))), getTyp((*ListStruct)(nil))},
   430  		{"empty last field", ListStruct{A: ListA{
   431  			smallTestStruct{A: 0xaa11, B: 0xbb22},
   432  			smallTestStruct{A: 0xcc33, B: 0xdd44},
   433  			smallTestStruct{A: 0x1234, B: 0x4567},
   434  		}}, "08000000" + "14000000" + ("11aa22bb" + "33cc44dd" + "34126745"),
   435  			h(
   436  				h(
   437  					h(
   438  						h(
   439  							h(chunk("11aa"), chunk("22bb")),
   440  							h(chunk("33cc"), chunk("44dd")),
   441  						),
   442  						h(
   443  							h(chunk("3412"), chunk("6745")),
   444  							chunk(""),
   445  						),
   446  					),
   447  					chunk("03000000"),
   448  				),
   449  				h(zeroHashes[3], chunk("")),
   450  			), getTyp((*ListStruct)(nil))},
   451  		{"complexTestStruct",
   452  			complexTestStruct{
   453  				A: 0xaabb,
   454  				B: uint16List128{0x1122, 0x3344},
   455  				C: 0xff,
   456  				D: bytelist256("foobar"),
   457  				E: VarTestStruct{A: 0xabcd, B: uint16List1024{1, 2, 3}, C: 0xff},
   458  				F: [4]fixedTestStruct{
   459  					{0xcc, 0x4242424242424242, 0x13371337},
   460  					{0xdd, 0x3333333333333333, 0xabcdabcd},
   461  					{0xee, 0x4444444444444444, 0x00112233},
   462  					{0xff, 0x5555555555555555, 0x44556677}},
   463  				G: [2]VarTestStruct{
   464  					{A: 0xdead, B: []uint16{1, 2, 3}, C: 0x11},
   465  					{A: 0xbeef, B: []uint16{4, 5, 6}, C: 0x22}},
   466  			},
   467  			"bbaa" +
   468  				"47000000" + // offset of B, []uint16
   469  				"ff" +
   470  				"4b000000" + // offset of foobar
   471  				"51000000" + // offset of E
   472  				"cc424242424242424237133713" +
   473  				"dd3333333333333333cdabcdab" +
   474  				"ee444444444444444433221100" +
   475  				"ff555555555555555577665544" +
   476  				"5e000000" + // pointer to G
   477  				"22114433" + // contents of B
   478  				"666f6f626172" + // foobar
   479  				"cdab07000000ff010002000300" + // contents of E
   480  				"08000000" + "15000000" + // [start G]: local offsets of [2]VarTestStruct
   481  				"adde0700000011010002000300" +
   482  				"efbe0700000022040005000600",
   483  			h(
   484  				h(
   485  					h( // A and B
   486  						chunk("bbaa"),
   487  						h(merge(chunk("22114433"), zeroHashes[0:3]), chunk("02000000")), // 2*128/32 = 8 chunks
   488  					),
   489  					h( // C and D
   490  						chunk("ff"),
   491  						h(merge(chunk("666f6f626172"), zeroHashes[0:3]), chunk("06000000")), // 256/32 = 8 chunks
   492  					),
   493  				),
   494  				h(
   495  					h( // E and F
   496  						h(h(chunk("cdab"), h(merge(chunk("010002000300"), zeroHashes[0:6]), chunk("03000000"))),
   497  							h(chunk("ff"), chunk(""))),
   498  						h(
   499  							h(
   500  								h(h(chunk("cc"), chunk("4242424242424242")), h(chunk("37133713"), chunk(""))),
   501  								h(h(chunk("dd"), chunk("3333333333333333")), h(chunk("cdabcdab"), chunk(""))),
   502  							),
   503  							h(
   504  								h(h(chunk("ee"), chunk("4444444444444444")), h(chunk("33221100"), chunk(""))),
   505  								h(h(chunk("ff"), chunk("5555555555555555")), h(chunk("77665544"), chunk(""))),
   506  							),
   507  						),
   508  					),
   509  					h( // G and padding
   510  						h(
   511  							h(h(chunk("adde"), h(merge(chunk("010002000300"), zeroHashes[0:6]), chunk("03000000"))),
   512  								h(chunk("11"), chunk(""))),
   513  							h(h(chunk("efbe"), h(merge(chunk("040005000600"), zeroHashes[0:6]), chunk("03000000"))),
   514  								h(chunk("22"), chunk(""))),
   515  						),
   516  						chunk(""),
   517  					),
   518  				),
   519  			),
   520  			getTyp((*complexTestStruct)(nil))},
   521  		{"embeddingStruct",
   522  			embeddingStruct{
   523  				A:             VarTestStruct{A: 0xabcd, B: uint16List1024{1, 2, 3}, C: 0xff},
   524  				VarTestStruct: VarTestStruct{A: 0xeeff, B: uint16List1024{4, 5, 6, 7, 8}, C: 0xaa},
   525  				B:             0x1234,
   526  				Foo: smallTestStruct{
   527  					A: 0x4567,
   528  					B: 0x8901,
   529  				},
   530  			},
   531  			"11000000" + // offset to dynamic part A
   532  				"ffee" + "1e000000" + "aa" + // embedded VarTestStruct, fixed part
   533  				"3412" + // B
   534  				"6745" + "0189" + // embedded smallTestStruct
   535  				"cdab07000000ff010002000300" + // A, contents
   536  				"04000500060007000800", // embedded VarTestStruct, dynamic part
   537  			h(
   538  				h(
   539  					h(
   540  						// A
   541  						h(
   542  							h(chunk("cdab"), h(merge(chunk("010002000300"), zeroHashes[0:6]), chunk("03000000"))),
   543  							h(chunk("ff"), chunk("")),
   544  						),
   545  						// embedded
   546  						chunk("ffee"),
   547  					),
   548  					h(
   549  						// embedded continued
   550  						h(merge(chunk("04000500060007000800"), zeroHashes[0:6]), chunk("05000000")),
   551  						chunk("aa"),
   552  					),
   553  				),
   554  				h(
   555  					h(
   556  						chunk("3412"), // B
   557  						chunk("6745"), // embedded smallTestStruct
   558  					),
   559  					h(
   560  						chunk("0189"), // embedded continued
   561  						chunk(""),
   562  					),
   563  				),
   564  			),
   565  			getTyp((*embeddingStruct)(nil))},
   566  		{"squash chaos", Squash3{
   567  			Foo:     Squash1{01, nil, 0xa8a7a6a5a4a3a2a1, 0xaabbccdd},
   568  			Squash1: Squash1{02, nil, 0xb8b7b6b5b4b3b2b1, 0x00001111},
   569  			X: Squash2{
   570  				D:       0x11223344,
   571  				E:       0, // omitted
   572  				Squash1: Squash1{03, nil, 0xc8c7c6c5c4c3c2c1, 0x22223333},
   573  				More:    Squash1{04, nil, 0xd8d7d6d5d4d3d2d1, 0x42424242},
   574  			},
   575  			Bar: Squash1{0xab, nil, 0x1000000000000001, 0x12341234},
   576  			Squash2: Squash2{
   577  				D:       0x12345678,
   578  				E:       0, // omitted
   579  				Squash1: Squash1{05, nil, 0xe8e7e6e5e4e3e2e1, 0x55665566},
   580  				More:    Squash1{06, nil, 0xf8f7f6f5f4f3f2f1, 0x78787878},
   581  			},
   582  		}, "01" + "a1a2a3a4a5a6a7a8" + "ddccbbaa" +
   583  			"02" + "b1b2b3b4b5b6b7b8" + "11110000" +
   584  			"44332211" +
   585  			"03" + "c1c2c3c4c5c6c7c8" + "33332222" +
   586  			"04" + "d1d2d3d4d5d6d7d8" + "42424242" +
   587  			"ab" + "0100000000000010" + "34123412" +
   588  			"78563412" +
   589  			"05" + "e1e2e3e4e5e6e7e8" + "66556655" +
   590  			"06" + "f1f2f3f4f5f6f7f8" + "78787878",
   591  			h(
   592  				h(
   593  					h(
   594  						h(h(chunk("01"), chunk("a1a2a3a4a5a6a7a8")), h(chunk("ddccbbaa"), chunk("02"))),
   595  						h(h(chunk("b1b2b3b4b5b6b7b8"), chunk("11110000")), h(chunk("44332211"), chunk("03"))),
   596  					),
   597  					h(
   598  						h(h(chunk("c1c2c3c4c5c6c7c8"), chunk("33332222")), h(chunk("04"), chunk("d1d2d3d4d5d6d7d8"))),
   599  						h(h(chunk("42424242"), chunk("ab")), h(chunk("0100000000000010"), chunk("34123412"))),
   600  					),
   601  				),
   602  				h(
   603  					h(
   604  						h(h(chunk("78563412"), chunk("05")), h(chunk("e1e2e3e4e5e6e7e8"), chunk("66556655"))),
   605  						h(h(chunk("06"), chunk("f1f2f3f4f5f6f7f8")), h(chunk("78787878"), chunk(""))),
   606  					),
   607  					zeroHashes[3],
   608  				),
   609  			),
   610  			getTyp((*Squash3)(nil))},
   611  	}
   612  }
   613  
   614  func TestEncode(t *testing.T) {
   615  	var buf bytes.Buffer
   616  	bufWriter := bufio.NewWriter(&buf)
   617  
   618  	for _, tt := range testCases {
   619  		t.Run(tt.name, func(t *testing.T) {
   620  			buf.Reset()
   621  			sszTyp, err := SSZFactory(tt.typ)
   622  			if err != nil {
   623  				t.Fatal(err)
   624  			}
   625  			if n, err := Encode(bufWriter, tt.value, sszTyp); err != nil {
   626  				t.Fatalf("encoding failed, wrote to byte %d, err: %v", n, err)
   627  			}
   628  			if err := bufWriter.Flush(); err != nil {
   629  				t.Fatal(err)
   630  			}
   631  			data := buf.Bytes()
   632  			if res := fmt.Sprintf("%x", data); res != tt.hex {
   633  				t.Fatalf("encoded different data:\n     got %s\nexpected %s", res, tt.hex)
   634  			}
   635  			if size := SizeOf(tt.value, sszTyp); uint64(len(data)) != size {
   636  				t.Errorf("encoded output does not match expected size:"+
   637  					" len(data): %d but expected: %d", len(data), size)
   638  			}
   639  		})
   640  	}
   641  }
   642  
   643  func TestDecode(t *testing.T) {
   644  	for _, tt := range testCases {
   645  		t.Run(tt.name, func(t *testing.T) {
   646  			sszTyp, err := SSZFactory(tt.typ)
   647  			if err != nil {
   648  				t.Fatal(err)
   649  			}
   650  			data, err := hex.DecodeString(tt.hex)
   651  			if err != nil {
   652  				t.Fatal(err)
   653  			}
   654  			r := bytes.NewReader(data)
   655  			// For dynamic types, we need to pass the length of the message to the decoder.
   656  			// See SSZ-envelope discussion
   657  			bytesLen := uint64(len(tt.hex)) / 2
   658  
   659  			destination := reflect.New(tt.typ).Interface()
   660  			if err := Decode(r, bytesLen, destination, sszTyp); err != nil {
   661  				t.Fatal(err)
   662  			}
   663  			res, err := json.Marshal(destination)
   664  			if err != nil {
   665  				t.Fatal(err)
   666  			}
   667  			expected, err := json.Marshal(tt.value)
   668  			if err != nil {
   669  				t.Fatal(err)
   670  			}
   671  			// adjust expected json string. No effective difference between null and an empty slice. We prefer nil.
   672  			if adjusted := strings.ReplaceAll(string(expected), "[]", "null"); string(res) != adjusted {
   673  				t.Fatalf("decoded different data:\n     got %s\nexpected %s", res, adjusted)
   674  			}
   675  		})
   676  	}
   677  }
   678  
   679  func TestDryCheck(t *testing.T) {
   680  	for _, tt := range testCases {
   681  		t.Run(tt.name, func(t *testing.T) {
   682  			sszTyp, err := SSZFactory(tt.typ)
   683  			if err != nil {
   684  				t.Fatal(err)
   685  			}
   686  			data, err := hex.DecodeString(tt.hex)
   687  			if err != nil {
   688  				t.Fatal(err)
   689  			}
   690  			r := bytes.NewReader(data)
   691  			// For dynamic types, we need to pass the length of the message to the decoder.
   692  			// See SSZ-envelope discussion
   693  			bytesLen := uint64(len(tt.hex)) / 2
   694  
   695  			if err := DryCheck(r, bytesLen, sszTyp); err != nil {
   696  				t.Error(err)
   697  			}
   698  		})
   699  	}
   700  }
   701  
   702  func TestHashTreeRoot(t *testing.T) {
   703  	var buf bytes.Buffer
   704  
   705  	// re-use a hash function
   706  	sha := sha256.New()
   707  	hashFn := htr.HashFn(func(input []byte) (out [32]byte) {
   708  		sha.Reset()
   709  		sha.Write(input)
   710  		copy(out[:], sha.Sum(nil))
   711  		return
   712  	})
   713  
   714  	for _, tt := range testCases {
   715  		t.Run(tt.name, func(t *testing.T) {
   716  			buf.Reset()
   717  			sszTyp, err := SSZFactory(tt.typ)
   718  			if err != nil {
   719  				t.Fatal(err)
   720  			}
   721  			root := HashTreeRoot(hashFn, tt.value, sszTyp)
   722  			res := hex.EncodeToString(root[:])
   723  			if res != tt.root {
   724  				t.Errorf("Expected root %s but got %s", tt.root, res)
   725  			}
   726  		})
   727  	}
   728  }
   729  
   730  func TestSigningRoot(t *testing.T) {
   731  	var buf bytes.Buffer
   732  
   733  	// re-use a hash function
   734  	sha := sha256.New()
   735  	hashFn := htr.HashFn(func(input []byte) (out [32]byte) {
   736  		sha.Reset()
   737  		sha.Write(input)
   738  		copy(out[:], sha.Sum(nil))
   739  		return
   740  	})
   741  
   742  	for _, tt := range testCases {
   743  		t.Run(tt.name, func(t *testing.T) {
   744  			buf.Reset()
   745  			sszTyp, err := SSZFactory(tt.typ)
   746  			if err != nil {
   747  				t.Fatal(err)
   748  			}
   749  			signedSSZ, ok := sszTyp.(SignedSSZ)
   750  			if !ok {
   751  				// only test signing root for applicable types
   752  				return
   753  			}
   754  			root := SigningRoot(hashFn, tt.value, signedSSZ)
   755  			res := hex.EncodeToString(root[:])
   756  			if res == tt.root && root != ([32]byte{}) {
   757  				t.Errorf("Signing root is not different than hash-tree-root. "+
   758  					"Expected root: %s but got %s (should be different)", tt.root, res)
   759  			}
   760  			t.Logf("signing root: %x\n", root)
   761  		})
   762  	}
   763  }