Support typed nil pointer in tree hash (#1590)

This commit is contained in:
Jie Hou 2019-02-14 07:22:12 -08:00 committed by Raul Jordan
parent e052e457df
commit d620361233
2 changed files with 15 additions and 11 deletions

View File

@ -3,7 +3,6 @@ package ssz
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"reflect" "reflect"
@ -22,7 +21,7 @@ type Hashable interface {
// TreeHash calculates tree-hash result for input value. // TreeHash calculates tree-hash result for input value.
func TreeHash(val interface{}) ([32]byte, error) { func TreeHash(val interface{}) ([32]byte, error) {
if val == nil { if val == nil {
return [32]byte{}, newHashError("nil is not supported", nil) return [32]byte{}, newHashError("untyped nil is not supported", nil)
} }
rval := reflect.ValueOf(val) rval := reflect.ValueOf(val)
sszUtils, err := cachedSSZUtils(rval.Type()) sszUtils, err := cachedSSZUtils(rval.Type())
@ -142,19 +141,20 @@ func makeStructHasher(typ reflect.Type) (hasher, error) {
return hasher, nil return hasher, nil
} }
// Notice: Currently we don't support nil pointer:
// - Input for encoding must not contain nil pointer
// - Output for decoding will never contain nil pointer
// (Not to be confused with empty slice. Empty slice is supported)
func makePtrHasher(typ reflect.Type) (hasher, error) { func makePtrHasher(typ reflect.Type) (hasher, error) {
elemSSZUtils, err := cachedSSZUtilsNoAcquireLock(typ.Elem()) elemSSZUtils, err := cachedSSZUtilsNoAcquireLock(typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO(1461): The tree-hash of nil pointer isn't defined in the spec.
// After considered the use case in Prysm, we've decided that:
// - We assume we will only tree-hash pointer of array, slice or struct.
// - The tree-hash for nil pointer shall be 0x00000000.
hasher := func(val reflect.Value) ([]byte, error) { hasher := func(val reflect.Value) ([]byte, error) {
if val.IsNil() { if val.IsNil() {
return nil, errors.New("nil is not supported") return hashedEncoding(val)
} }
return elemSSZUtils.hasher(val.Elem()) return elemSSZUtils.hasher(val.Elem())
} }

View File

@ -119,10 +119,14 @@ var hashTests = []hashTest{
{P: &simpleStruct{B: 4, A: 3}, V: 1}, {P: &simpleStruct{B: 4, A: 3}, V: 1},
}, output: "4AC9B9E64A067F6C007C3FE8116519D86397BDA1D9FBEDEEDF39E50D132669C7"}, }, output: "4AC9B9E64A067F6C007C3FE8116519D86397BDA1D9FBEDEEDF39E50D132669C7"},
// error: nil pointer // nil pointer (not defined in spec)
{val: nil, error: "hash error: nil is not supported for input type <nil>"}, {val: (*[]uint8)(nil), output: "E8E77626586F73B955364C7B4BBF0BB7F7685EBD40E852B164633A4ACBD3244C"},
{val: (*[]uint8)(nil), error: "hash error: nil is not supported for input type *[]uint8"}, {val: pointerStruct{}, output: "721B2869FA1238991B24C369E9ADB23142AFCD7C0B8454EF79C0EA82B7DEE977"},
{val: pointerStruct{P: nil, V: 0}, error: "hash error: failed to hash field of struct: nil is not supported for input type ssz.pointerStruct"}, {val: &pointerStruct{}, output: "721B2869FA1238991B24C369E9ADB23142AFCD7C0B8454EF79C0EA82B7DEE977"},
{val: []*pointerStruct{nil, nil}, output: "83CB52B40904E607A8E0AEF8A018A5A7489229CBCD591E7C6FB7E597BD4F76C3"},
// error: untyped nil pointer
{val: nil, error: "hash error: untyped nil is not supported for input type <nil>"},
// error: unsupported type // error: unsupported type
{val: string("abc"), error: "hash error: type string is not serializable for input type string"}, {val: string("abc"), error: "hash error: type string is not serializable for input type string"},