From 739ba847f6f407f63fd6a24175b24e56fea583a1 Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Thu, 27 Feb 2025 12:13:11 +0100 Subject: [PATCH] feat(rlp/rlpgen): support alias types (#154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why this should be merged To be able to generate RLP code using type aliases (defined e.g. in `coreth`). This can and should be PR-ed upstream as well I think. ## How this works Call `types.Unalias()` at the start of `buildContext.makeOp()`. The alternative of adding a `case` to the switch statement adds unnecessary recursive calls while `types.Unalias()` is a no-op if not an alias. ## How this was tested New `rlpgen` unit test with aliases of well-known types that have special handling—these make their proper handling easy to spot when inspecting generated code. A recursive alias in the same test also demonstrates full alias resolution. --------- Co-authored-by: Arran Schlosberg --- rlp/rlpgen/gen.go | 2 +- rlp/rlpgen/gen_test.go | 2 +- rlp/rlpgen/testdata/alias.in.txt | 22 ++++++++++++++++ rlp/rlpgen/testdata/alias.out.txt | 43 +++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 rlp/rlpgen/testdata/alias.in.txt create mode 100644 rlp/rlpgen/testdata/alias.out.txt diff --git a/rlp/rlpgen/gen.go b/rlp/rlpgen/gen.go index 150797c7aa..7ec38a4c38 100644 --- a/rlp/rlpgen/gen.go +++ b/rlp/rlpgen/gen.go @@ -673,7 +673,7 @@ func (op sliceOp) genDecode(ctx *genContext) (string, string) { } func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstruct.Tags) (op, error) { - switch typ := typ.(type) { + switch typ := types.Unalias(typ).(type) { case *types.Named: if isBigInt(typ) { return bigIntOp{}, nil diff --git a/rlp/rlpgen/gen_test.go b/rlp/rlpgen/gen_test.go index 3b4f5df287..be43990261 100644 --- a/rlp/rlpgen/gen_test.go +++ b/rlp/rlpgen/gen_test.go @@ -47,7 +47,7 @@ func init() { } } -var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"} +var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256", "alias"} func TestOutput(t *testing.T) { for _, test := range tests { diff --git a/rlp/rlpgen/testdata/alias.in.txt b/rlp/rlpgen/testdata/alias.in.txt new file mode 100644 index 0000000000..c7aa8a3106 --- /dev/null +++ b/rlp/rlpgen/testdata/alias.in.txt @@ -0,0 +1,22 @@ +// -*- mode: go -*- + +package test + +import ( + "math/big" + "github.com/holiman/uint256" +) + +// Alias types chosen because their originals have special handling that is easy +// to spot when inspecting generated output. +type ( + Big = big.Int + // Demonstrate recursive unaliasing + intermediate = uint256.Int + Uint256 = intermediate +) + +type Test struct { + BigAlias Big + Uint256Alias Uint256 +} diff --git a/rlp/rlpgen/testdata/alias.out.txt b/rlp/rlpgen/testdata/alias.out.txt new file mode 100644 index 0000000000..0746f97494 --- /dev/null +++ b/rlp/rlpgen/testdata/alias.out.txt @@ -0,0 +1,43 @@ +package test + +import "github.com/ava-labs/libevm/rlp" +import "github.com/holiman/uint256" +import "io" + +func (obj *Test) EncodeRLP(_w io.Writer) error { + w := rlp.NewEncoderBuffer(_w) + _tmp0 := w.List() + if obj.BigAlias.Sign() == -1 { + return rlp.ErrNegativeBigInt + } + w.WriteBigInt(&obj.BigAlias) + w.WriteUint256(&obj.Uint256Alias) + 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 + } + // BigAlias: + _tmp1, err := dec.BigInt() + if err != nil { + return err + } + _tmp0.BigAlias = (*_tmp1) + // Uint256Alias: + var _tmp2 uint256.Int + if err := dec.ReadUint256(&_tmp2); err != nil { + return err + } + _tmp0.Uint256Alias = _tmp2 + if err := dec.ListEnd(); err != nil { + return err + } + } + *obj = _tmp0 + return nil +}