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 }