diff --git a/rlp/decode.go b/rlp/decode.go index 0fbca243ee..e75e63d0be 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -168,7 +168,7 @@ func makeDecoder(typ reflect.Type, tags rlpstruct.Tags) (dec decoder, err error) return decodeU256NoPtr, nil case kind == reflect.Ptr: return makePtrDecoder(typ, tags) - case reflect.PointerTo(typ).Implements(decoderInterface): + case implementsInterface(reflect.PointerTo(typ), decoderInterface): return decodeDecoder, nil case isUint(kind): return decodeUint, nil @@ -262,7 +262,7 @@ func decodeU256(s *Stream, val reflect.Value) error { func makeListDecoder(typ reflect.Type, tag rlpstruct.Tags) (decoder, error) { etype := typ.Elem() - if etype.Kind() == reflect.Uint8 && !reflect.PointerTo(etype).Implements(decoderInterface) { + if etype.Kind() == reflect.Uint8 && !implementsInterface(reflect.PointerTo(etype), decoderInterface) { if typ.Kind() == reflect.Array { return decodeByteArray, nil } diff --git a/rlp/encode.go b/rlp/encode.go index 3645bbfda0..f95d12a85c 100644 --- a/rlp/encode.go +++ b/rlp/encode.go @@ -151,7 +151,7 @@ func makeWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { return writeU256IntNoPtr, nil case kind == reflect.Ptr: return makePtrWriter(typ, ts) - case reflect.PointerTo(typ).Implements(encoderInterface): + case implementsInterface(reflect.PointerTo(typ), encoderInterface): return makeEncoderWriter(typ), nil case isUint(kind): return writeUint, nil @@ -409,7 +409,7 @@ func makePtrWriter(typ reflect.Type, ts rlpstruct.Tags) (writer, error) { } func makeEncoderWriter(typ reflect.Type) writer { - if typ.Implements(encoderInterface) { + if implementsInterface(typ, encoderInterface) { return func(val reflect.Value, w *encBuffer) error { return val.Interface().(Encoder).EncodeRLP(w) } diff --git a/rlp/reflection.go b/rlp/reflection.go new file mode 100644 index 0000000000..f7f1a507b1 --- /dev/null +++ b/rlp/reflection.go @@ -0,0 +1,25 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build !tinygo + +package rlp + +import "reflect" + +func implementsInterface(t reflect.Type, i reflect.Type) bool { + return t.Implements(i) +} diff --git a/rlp/reflection_tinygo.go b/rlp/reflection_tinygo.go new file mode 100644 index 0000000000..e9cbe07840 --- /dev/null +++ b/rlp/reflection_tinygo.go @@ -0,0 +1,38 @@ +// Copyright 2025 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build tinygo + +package rlp + +import "reflect" + +var customEncodedTypes = make(map[reflect.Type]bool) + +func implementsInterface(t reflect.Type, i reflect.Type) bool { + // reflect implementation of tinygo cannot handle this automatically + // at runtime. So we need custom encoded types to be registered manually. + if i == decoderInterface || i == encoderInterface { + return customEncodedTypes[t] + } + return false +} + +// RegisterCustomEncodedType manually registers a type as an implementation of +// Decoder and Encoder interfaces +func RegisterCustomEncodedType(t reflect.Type) { + customEncodedTypes[t] = true +} diff --git a/rlp/typecache.go b/rlp/typecache.go index eebf4cd611..79b50a6b8a 100644 --- a/rlp/typecache.go +++ b/rlp/typecache.go @@ -199,8 +199,8 @@ func rtypeToStructType(typ reflect.Type, rec map[reflect.Type]*rlpstruct.Type) * t := &rlpstruct.Type{ Name: typ.String(), Kind: k, - IsEncoder: typ.Implements(encoderInterface), - IsDecoder: typ.Implements(decoderInterface), + IsEncoder: implementsInterface(typ, encoderInterface), + IsDecoder: implementsInterface(typ, decoderInterface), } rec[typ] = t if k == reflect.Array || k == reflect.Slice || k == reflect.Ptr { @@ -234,5 +234,5 @@ func isUint(k reflect.Kind) bool { } func isByte(typ reflect.Type) bool { - return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface) + return typ.Kind() == reflect.Uint8 && !implementsInterface(typ, encoderInterface) }