diff --git a/rlp/decode.go b/rlp/decode.go index 1ff0557165..9850458141 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -385,6 +385,11 @@ func makeStructDecoder(typ reflect.Type) (decoder, error) { if err != nil { return nil, err } + for _, f := range fields { + if f.info.decoderErr != nil { + return nil, structFieldError{typ, f.index, f.info.decoderErr} + } + } dec := func(s *Stream, val reflect.Value) (err error) { if _, err := s.List(); err != nil { return wrapStreamError(err, typ) diff --git a/rlp/decode_test.go b/rlp/decode_test.go index c0d202c22e..634d1cf3bb 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -365,6 +365,10 @@ type nilStringSlice struct { X *[]uint `rlp:"nilString"` } +type intField struct { + X int +} + var ( veryBigInt = big.NewInt(0).Add( big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), @@ -496,6 +500,11 @@ var decodeTests = []decodeTest{ ptr: new(recstruct), error: "rlp: expected input string or byte for uint, decoding into (rlp.recstruct).Child.I", }, + { + input: "C103", + ptr: new(intField), + error: "rlp: type int is not RLP-serializable (struct field rlp.intField.X)", + }, { input: "C50102C20102", ptr: new(tailUint), @@ -531,12 +540,12 @@ var decodeTests = []decodeTest{ { input: "C0", ptr: new(invalidTail1), - error: "rlp: invalid struct tag \"tail\" for rlp.invalidTail1.A (must be on last field)", + error: `rlp: invalid struct tag "tail" for rlp.invalidTail1.A (must be on last field)`, }, { input: "C0", ptr: new(invalidTail2), - error: "rlp: invalid struct tag \"tail\" for rlp.invalidTail2.B (field type is not slice)", + error: `rlp: invalid struct tag "tail" for rlp.invalidTail2.B (field type is not slice)`, }, // struct tag "-" diff --git a/rlp/encode.go b/rlp/encode.go index 709ff313d4..9c9e8d706d 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -480,6 +480,11 @@ func makeStructWriter(typ reflect.Type) (writer, error) { if err != nil { return nil, err } + for _, f := range fields { + if f.info.writerErr != nil { + return nil, structFieldError{typ, f.index, f.info.writerErr} + } + } writer := func(val reflect.Value, w *encbuf) error { lh := w.list() for _, f := range fields { diff --git a/rlp/encode_test.go b/rlp/encode_test.go index c3efdf9a41..b4b9e51287 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -234,6 +234,7 @@ var encTests = []encTest{ {val: &tailRaw{A: 1, Tail: []RawValue{}}, output: "C101"}, {val: &tailRaw{A: 1, Tail: nil}, output: "C101"}, {val: &hasIgnoredField{A: 1, B: 2, C: 3}, output: "C20103"}, + {val: &intField{X: 3}, error: "rlp: type int is not RLP-serializable (struct field rlp.intField.X)"}, // nil {val: (*uint)(nil), output: "80"}, diff --git a/rlp/typecache.go b/rlp/typecache.go index f122e3d702..e9a1e3f9e2 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -126,6 +126,16 @@ func structFields(typ reflect.Type) (fields []field, err error) { return fields, nil } +type structFieldError struct { + typ reflect.Type + field int + err error +} + +func (e structFieldError) Error() string { + return fmt.Sprintf("%v (struct field %v.%s)", e.err, e.typ, e.typ.Field(e.field).Name) +} + type structTagError struct { typ reflect.Type field, tag, err string