mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 21:54:30 +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) {
|
||||
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?
|
||||
return bctx.makeOp(typ, typ.Underlying(), tags)
|
||||
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) {
|
||||
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