From fc92abec2cc6e27e7e56a6a05850ad4ebbf63d7e Mon Sep 17 00:00:00 2001
From: Felix Lange <fjl@twurst.com>
Date: Thu, 15 Jan 2015 23:21:41 +0100
Subject: [PATCH] rlp: allow encoding non-empty interface values

This needs to be supported because []someInterface does occur sometimes.

Funny enough, the fix involves changes to the decoder. makeDecoder
cannot return an error for non-empty interfaces anymore because the type
cache builds both decoder and writer. Do the check at 'runtime' instead.
---
 rlp/decode.go      |  5 ++++-
 rlp/decode_test.go |  5 +++++
 rlp/encode.go      |  3 +--
 rlp/encode_test.go | 13 +++++++++++++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/rlp/decode.go b/rlp/decode.go
index 972e662c2..55f7187a3 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -137,7 +137,7 @@ func makeDecoder(typ reflect.Type) (dec decoder, err error) {
 		return makeStructDecoder(typ)
 	case kind == reflect.Ptr:
 		return makePtrDecoder(typ)
-	case kind == reflect.Interface && typ.NumMethod() == 0:
+	case kind == reflect.Interface:
 		return decodeInterface, nil
 	default:
 		return nil, fmt.Errorf("rlp: type %v is not RLP-serializable", typ)
@@ -378,6 +378,9 @@ func makePtrDecoder(typ reflect.Type) (decoder, error) {
 var ifsliceType = reflect.TypeOf([]interface{}{})
 
 func decodeInterface(s *Stream, val reflect.Value) error {
+	if val.Type().NumMethod() != 0 {
+		return fmt.Errorf("rlp: type %v is not RLP-serializable", val.Type())
+	}
 	kind, _, err := s.Kind()
 	if err != nil {
 		return err
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 9142ef56d..9f66840b1 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -325,6 +325,11 @@ var decodeTests = []decodeTest{
 	{input: "850505050505", ptr: new(interface{}), value: []byte{5, 5, 5, 5, 5}},
 	{input: "C0", ptr: new(interface{}), value: []interface{}{}},
 	{input: "C50183040404", ptr: new(interface{}), value: []interface{}{[]byte{1}, []byte{4, 4, 4}}},
+	{
+		input: "C3010203",
+		ptr:   new([]io.Reader),
+		error: "rlp: type io.Reader is not RLP-serializable",
+	},
 }
 
 func uintp(i uint) *uint { return &i }
diff --git a/rlp/encode.go b/rlp/encode.go
index 689d25dd8..d80b66315 100644
--- a/rlp/encode.go
+++ b/rlp/encode.go
@@ -280,7 +280,6 @@ func (r *encReader) next() []byte {
 
 var (
 	encoderInterface = reflect.TypeOf(new(Encoder)).Elem()
-	emptyInterface   = reflect.TypeOf(new(interface{})).Elem()
 	big0             = big.NewInt(0)
 )
 
@@ -292,7 +291,7 @@ func makeWriter(typ reflect.Type) (writer, error) {
 		return writeEncoder, nil
 	case kind != reflect.Ptr && reflect.PtrTo(typ).Implements(encoderInterface):
 		return writeEncoderNoPtr, nil
-	case typ == emptyInterface:
+	case kind == reflect.Interface:
 		return writeInterface, nil
 	case typ.AssignableTo(reflect.PtrTo(bigInt)):
 		return writeBigIntPtr, nil
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index 8dba3671b..18b843737 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -32,9 +32,19 @@ func (e byteEncoder) EncodeRLP(w io.Writer) error {
 	return nil
 }
 
+type encodableReader struct {
+	A, B uint
+}
+
+func (e *encodableReader) Read(b []byte) (int, error) {
+	panic("called")
+}
+
 var (
 	_ = Encoder(&testEncoder{})
 	_ = Encoder(byteEncoder(0))
+
+	reader io.Reader = &encodableReader{1, 2}
 )
 
 type encTest struct {
@@ -176,6 +186,9 @@ var encTests = []encTest{
 	{val: (*[]struct{ uint })(nil), output: "C0"},
 	{val: (*interface{})(nil), output: "C0"},
 
+	// interfaces
+	{val: []io.Reader{reader}, output: "C3C20102"}, // the contained value is a struct
+
 	// Encoder
 	{val: (*testEncoder)(nil), output: "00000000"},
 	{val: &testEncoder{}, output: "00010001000100010001"},
-- 
GitLab