prysm-pulse/shared/ssz/decode_test.go
shayzluf 6c1740eefc Add Caching to Tree Hashing Algorithm (#1929)
* added todo to hash file in ssz

* params and copy of block cache

* start hash cache

* Hash cache implementation

* fixed some comments

* fixed promatheus duplicate counter name

* removed TODO

* change to use special expiration cache

* function name fixes junk object generator

* naming changes

* gazzle fix

* added pruning last read data test

* fixed gometallinter errors

* fix benchmarks and no int64 not serializable

* move struct from test

* add feature flag

* fix merge issues

* add featureflag to beacon and validator

* featureflag init for tests

* added feature flag to all ssz dependent tests

* remove setter func

* replace k8s tweaked expiration cache to https://github.com/karlseguin/ccache

* remove else

* change request by preston

* added init featureflags to genesis_test

* Update shared/ssz/hash_cache.go

add dot

Co-Authored-By: shayzluf <thezluf@gmail.com>

* Update shared/ssz/hash_cache.go

Co-Authored-By: shayzluf <thezluf@gmail.com>

* Update shared/ssz/hash_cache.go

remove extra space

Co-Authored-By: shayzluf <thezluf@gmail.com>

* Update shared/params/config.go

add dot

Co-Authored-By: shayzluf <thezluf@gmail.com>

* Update shared/featureconfig/config.go

remove dot

Co-Authored-By: shayzluf <thezluf@gmail.com>

* Update shared/featureconfig/config.go

remove dot

Co-Authored-By: shayzluf <thezluf@gmail.com>

* remove powchain from prometheus hash cache name

* fixes fron change requests

* fix change requests

* remove faulty merge test

* gazelle fix

* fix fmt.sprintf

* remove debug binary

* fix gazelle
2019-04-24 13:39:02 +08:00

231 lines
8.9 KiB
Go

package ssz
import (
"bytes"
"encoding/hex"
"fmt"
"reflect"
"testing"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
)
type decodeTest struct {
input string
ptr interface{}
value interface{}
error string
}
// Notice: spaces in the input string will be ignored.
var decodeTests = []decodeTest{
// bool
{input: "00", ptr: new(bool), value: false},
{input: "01", ptr: new(bool), value: true},
// uint8
{input: "00", ptr: new(uint8), value: uint8(0)},
{input: "01", ptr: new(uint8), value: uint8(1)},
{input: "10", ptr: new(uint8), value: uint8(16)},
{input: "80", ptr: new(uint8), value: uint8(128)},
{input: "FF", ptr: new(uint8), value: uint8(255)},
// uint16
{input: "0000", ptr: new(uint16), value: uint16(0)},
{input: "0100", ptr: new(uint16), value: uint16(1)},
{input: "1000", ptr: new(uint16), value: uint16(16)},
{input: "8000", ptr: new(uint16), value: uint16(128)},
{input: "FF00", ptr: new(uint16), value: uint16(255)},
{input: "FFFF", ptr: new(uint16), value: uint16(65535)},
// uint32
{input: "00000000", ptr: new(uint32), value: uint32(0)},
{input: "01000000", ptr: new(uint32), value: uint32(1)},
{input: "10000000", ptr: new(uint32), value: uint32(16)},
{input: "80000000", ptr: new(uint32), value: uint32(128)},
{input: "FF000000", ptr: new(uint32), value: uint32(255)},
{input: "FFFF0000", ptr: new(uint32), value: uint32(65535)},
{input: "FFFFFFFF", ptr: new(uint32), value: uint32(4294967295)},
// uint64
{input: "0000000000000000", ptr: new(uint64), value: uint64(0)},
{input: "0100000000000000", ptr: new(uint64), value: uint64(1)},
{input: "1000000000000000", ptr: new(uint64), value: uint64(16)},
{input: "8000000000000000", ptr: new(uint64), value: uint64(128)},
{input: "FF00000000000000", ptr: new(uint64), value: uint64(255)},
{input: "FFFF000000000000", ptr: new(uint64), value: uint64(65535)},
{input: "FFFFFFFF00000000", ptr: new(uint64), value: uint64(4294967295)},
{input: "FFFFFFFFFFFFFFFF", ptr: new(uint64), value: uint64(18446744073709551615)},
// bytes
{input: "00000000", ptr: new([]byte), value: []byte{}},
{input: "0100000001", ptr: new([]byte), value: []byte{1}},
{input: "06000000 010203040506", ptr: new([]byte), value: []byte{1, 2, 3, 4, 5, 6}},
// slice
{input: "00000000", ptr: new([]uint16), value: []uint16(nil)},
{input: "04000000 0100 0200", ptr: new([]uint16), value: []uint16{1, 2}},
{input: "18000000 08000000 0100 0200 0300 0400 08000000 0500 0600 0700 0800", ptr: new([][]uint16),
value: [][]uint16{
{1, 2, 3, 4},
{5, 6, 7, 8},
},
},
// array
{input: "01000000 01", ptr: new([1]byte), value: [1]byte{1}},
{input: "06000000 010203040506", ptr: new([6]byte), value: [6]byte{1, 2, 3, 4, 5, 6}},
{input: "02000000 0100", ptr: new([1]uint16), value: [1]uint16{1}},
{input: "04000000 0100 0200", ptr: new([2]uint16), value: [2]uint16{1, 2}},
{input: "18000000 08000000 0100 0200 0300 0400 08000000 0500 0600 0700 0800", ptr: new([2][4]uint16),
value: [2][4]uint16{
{1, 2, 3, 4},
{5, 6, 7, 8},
},
},
// struct
{input: "03000000 00 0000", ptr: new(simpleStruct), value: simpleStruct{}},
{input: "03000000 0200 01", ptr: new(simpleStruct), value: simpleStruct{B: 2, A: 1}},
{input: "07000000 03 02000000 0600", ptr: new(outerStruct),
value: outerStruct{
V: 3,
SubV: innerStruct{6},
}},
// slice + struct
{input: "12000000 0E000000 03000000 020001 03000000 040003", ptr: new(arrayStruct),
value: arrayStruct{
V: []simpleStruct{
{B: 2, A: 1},
{B: 4, A: 3},
},
}},
{input: "16000000 07000000 03 02000000 0600 07000000 05 02000000 0700", ptr: new([]outerStruct),
value: []outerStruct{
{V: 3, SubV: innerStruct{V: 6}},
{V: 5, SubV: innerStruct{V: 7}},
}},
// pointer
{input: "03000000 0200 01", ptr: new(*simpleStruct), value: &simpleStruct{B: 2, A: 1}},
{input: "08000000 03000000 0200 01 03", ptr: new(pointerStruct),
value: pointerStruct{P: &simpleStruct{B: 2, A: 1}, V: 3}},
{input: "08000000 03000000 0200 01 03", ptr: new(*pointerStruct),
value: &pointerStruct{P: &simpleStruct{B: 2, A: 1}, V: 3}},
{input: "04000000 01020304", ptr: new(*[]uint8), value: &[]uint8{1, 2, 3, 4}},
{input: "10000000 0100000000000000 0200000000000000", ptr: new(*[]uint64), value: &[]uint64{1, 2}},
{input: "0E000000 03000000 0200 01 03000000 0400 03", ptr: new([]*simpleStruct),
value: []*simpleStruct{
{B: 2, A: 1},
{B: 4, A: 3},
},
},
{input: "0E000000 03000000 0200 01 03000000 0400 03", ptr: new([2]*simpleStruct),
value: [2]*simpleStruct{
{B: 2, A: 1},
{B: 4, A: 3},
},
},
{input: "18000000 08000000 03000000 0200 01 00 08000000 03000000 0400 03 01", ptr: new([]*pointerStruct),
value: []*pointerStruct{
{P: &simpleStruct{B: 2, A: 1}, V: 0},
{P: &simpleStruct{B: 4, A: 3}, V: 1},
},
},
// nil pointer
{input: "00000000", ptr: new(*[]uint8), value: (*[]uint8)(nil)},
{input: "05000000 00000000 00", ptr: new(pointerStruct), value: pointerStruct{}},
{input: "05000000 00000000 00", ptr: new(*pointerStruct), value: &pointerStruct{}},
{input: "08000000 00000000 00000000", ptr: new([]*pointerStruct), value: []*pointerStruct{nil, nil}},
// error: nil target
{input: "00", ptr: nil, value: nil, error: "decode error: cannot decode into nil for output type <nil>"},
// error: non-pointer target
{input: "00", ptr: uint8(0), error: "decode error: can only decode into pointer target for output type uint8"},
// error: unsupported type
{input: "00", ptr: new(string), error: "decode error: type string is not serializable for output type string"},
// error: bool: wrong input value
{input: "02", ptr: new(bool), error: "decode error: expect 0 or 1 for decoding bool but got 2 for output type bool"},
// error: uint16: wrong header
{input: "00", ptr: new(uint16), error: "decode error: can only read 1 bytes while expected to read 2 bytes for output type uint16"},
// error: bytes: wrong input
{input: "01000000", ptr: new([]byte), error: "decode error: can only read 0 bytes while expected to read 1 bytes for output type []uint8"},
// error: slice: wrong header
{input: "010000", ptr: new([]uint16), error: "decode error: failed to decode header of slice: can only read 3 bytes while expected to read 4 bytes for output type []uint16"},
// error: slice: wrong input
{input: "01000000", ptr: new([]uint16), error: "decode error: failed to decode element of slice: can only read 0 bytes while expected to read 2 bytes for output type []uint16"},
// error: byte array: wrong input
{input: "01000000 01", ptr: new([2]byte), error: "decode error: input byte array size (1) isn't euqal to output array size (2) for output type [2]uint8"},
// error: array: input too short
{input: "02000000 0100", ptr: new([2]uint16), error: "decode error: input is too short for output type [2]uint16"},
// error: array: input too long
{input: "04000000 0100 0200", ptr: new([1]uint16), error: "decode error: input is too long for output type [1]uint16"},
// error: struct: wrong header
{input: "010000", ptr: new(simpleStruct), error: "decode error: failed to decode header of struct: can only read 3 bytes while expected to read 4 bytes for output type ssz.simpleStruct"},
// error: struct: wrong input
{input: "03000000 01 02", ptr: new(simpleStruct), error: "decode error: failed to decode field of slice: can only read 0 bytes while expected to read 1 bytes for output type ssz.simpleStruct"},
// error: struct: input too short
{input: "02000000 0200", ptr: new(simpleStruct), error: "decode error: input is too short for output type ssz.simpleStruct"},
// error: struct: input too long
{input: "04000000 0200 01 01", ptr: new(simpleStruct), error: "decode error: input is too long for output type ssz.simpleStruct"},
}
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func runTests(t *testing.T, decode func([]byte, interface{}) error) {
for i, test := range decodeTests {
input, err := hex.DecodeString(stripSpace(test.input))
if err != nil {
t.Errorf("test %d: invalid hex input %q", i, test.input)
continue
}
err = decode(input, test.ptr)
// Check unexpected error
if test.error == "" && err != nil {
t.Errorf("test %d: unexpected decode error: %v\ndecoding into %T\ninput %q",
i, err, test.ptr, test.input)
continue
}
// Check expected error
if test.error != "" && fmt.Sprint(err) != test.error {
t.Errorf("test %d: decode error mismatch\ngot %v\nwant %v\ndecoding into %T\ninput %q",
i, err, test.error, test.ptr, test.input)
continue
}
// Check expected output
if err == nil {
output := reflect.ValueOf(test.ptr).Elem().Interface()
if !reflect.DeepEqual(output, test.value) {
t.Errorf("test %d: value mismatch\ngot %#v\nwant %#v\ndecoding into %T\ninput %q",
i, output, test.value, test.ptr, test.input)
}
}
}
}
func TestDecodeWithByteReader(t *testing.T) {
runTests(t, func(input []byte, into interface{}) error {
return Decode(bytes.NewReader(input), into)
})
}