mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
feat: Add support for named types with underlying basic types (#236)
## Why this should be merged The current rlpgen partially supports named types with basic underlying, and it generates the rlp without correct conversion i.e: `w.WriteUint64(obj.Uint64NewT)` This PR adds the full support it ## How this works Adds check for `isNamedWithBasicUnderlying` and then returns a `op` with `makeNamedBasicOp` which is basically a `basicOp` but with the `typ` refers to the named type so that it can correctly encode decode with the named type. ## How this was tested Added UT tests --------- Signed-off-by: Ceyhun Onur <ceyhunonur54@gmail.com>
This commit is contained in:
parent
910e897c54
commit
9ed36b613a
5 changed files with 126 additions and 1 deletions
|
|
@ -687,6 +687,12 @@ func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstru
|
||||||
if bctx.isDecoder(typ) {
|
if bctx.isDecoder(typ) {
|
||||||
return nil, fmt.Errorf("type %v implements rlp.Decoder with non-pointer receiver", typ)
|
return nil, fmt.Errorf("type %v implements rlp.Decoder with non-pointer receiver", typ)
|
||||||
}
|
}
|
||||||
|
if hasBasicUnderlying(typ) {
|
||||||
|
// libevm: named types are reduced to their underlying basic type in this loop.
|
||||||
|
// We're handling named types here by passing the named type as the main type.
|
||||||
|
// See [named.libevm.go] for more details.
|
||||||
|
return bctx.makeNamedBasicOp(typ)
|
||||||
|
}
|
||||||
// TODO: same check for encoder?
|
// TODO: same check for encoder?
|
||||||
return bctx.makeOp(typ, typ.Underlying(), tags)
|
return bctx.makeOp(typ, typ.Underlying(), tags)
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256", "alias"}
|
var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256", "alias", "named.libevm"}
|
||||||
|
|
||||||
func TestOutput(t *testing.T) {
|
func TestOutput(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
||||||
55
rlp/rlpgen/named.libevm.go
Normal file
55
rlp/rlpgen/named.libevm.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2025 the libevm authors.
|
||||||
|
//
|
||||||
|
// The libevm additions to go-ethereum are free software: you can redistribute
|
||||||
|
// them and/or modify them 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 libevm additions are distributed in the hope that they 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
|
||||||
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// makeNamedBasicOp is a convenience wrapper for basicOp.
|
||||||
|
// It returns a basicOp with the named type as the main type instead of the underlying basic type.
|
||||||
|
func (bctx *buildContext) makeNamedBasicOp(named *types.Named) (op, error) {
|
||||||
|
underlying := named.Underlying()
|
||||||
|
basic, ok := underlying.(*types.Basic)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expected basic type, got %T", underlying)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use basic op because it actually supports necessary conversions (through writeNeedsConversion and decodeNeedsConversion)
|
||||||
|
// for named types.
|
||||||
|
// The only problem with that is it does not support the named type as the main type.
|
||||||
|
// So we use the named type as the main type instead of the underlying basic type.
|
||||||
|
baseOp, err := bctx.makeBasicOp(basic)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
op, ok := baseOp.(basicOp)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("expected basicOp, got %T", baseOp)
|
||||||
|
}
|
||||||
|
op.typ = named
|
||||||
|
|
||||||
|
return op, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasBasicUnderlying checks whether `named` has an underlying basic type.
|
||||||
|
func hasBasicUnderlying(named *types.Named) bool {
|
||||||
|
_, ok := named.Underlying().(*types.Basic)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
15
rlp/rlpgen/testdata/named.libevm.in.txt
vendored
Normal file
15
rlp/rlpgen/testdata/named.libevm.in.txt
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
// -*- mode: go -*-
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
type (
|
||||||
|
BoolT bool
|
||||||
|
Uint64T uint64
|
||||||
|
StringT string
|
||||||
|
)
|
||||||
|
|
||||||
|
type Test struct {
|
||||||
|
BoolNewT BoolT
|
||||||
|
Uint64NewT Uint64T
|
||||||
|
StringNewT StringT
|
||||||
|
}
|
||||||
49
rlp/rlpgen/testdata/named.libevm.out.txt
vendored
Normal file
49
rlp/rlpgen/testdata/named.libevm.out.txt
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import "github.com/ava-labs/libevm/rlp"
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
func (obj *Test) EncodeRLP(_w io.Writer) error {
|
||||||
|
w := rlp.NewEncoderBuffer(_w)
|
||||||
|
_tmp0 := w.List()
|
||||||
|
w.WriteBool(bool(obj.BoolNewT))
|
||||||
|
w.WriteUint64(uint64(obj.Uint64NewT))
|
||||||
|
w.WriteString(string(obj.StringNewT))
|
||||||
|
w.ListEnd(_tmp0)
|
||||||
|
return w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj *Test) DecodeRLP(dec *rlp.Stream) error {
|
||||||
|
var _tmp0 Test
|
||||||
|
{
|
||||||
|
if _, err := dec.List(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// BoolNewT:
|
||||||
|
_tmp1, err := dec.Bool()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_tmp2 := BoolT(_tmp1)
|
||||||
|
_tmp0.BoolNewT = _tmp2
|
||||||
|
// Uint64NewT:
|
||||||
|
_tmp3, err := dec.Uint64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_tmp4 := Uint64T(_tmp3)
|
||||||
|
_tmp0.Uint64NewT = _tmp4
|
||||||
|
// StringNewT:
|
||||||
|
_tmp5, err := dec.String()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_tmp6 := StringT(_tmp5)
|
||||||
|
_tmp0.StringNewT = _tmp6
|
||||||
|
if err := dec.ListEnd(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*obj = _tmp0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue