From a57c2a50451d04d1c12a04d15287ad2706385ba2 Mon Sep 17 00:00:00 2001 From: Ryan Tinianov Date: Tue, 4 Jun 2024 09:59:01 -0400 Subject: [PATCH] Automatically upper case nested tuple's field names in go (#13320) --- core/services/relay/evm/types/codec_entry.go | 11 +++++- .../relay/evm/types/codec_entry_test.go | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/core/services/relay/evm/types/codec_entry.go b/core/services/relay/evm/types/codec_entry.go index 21e5ac59847..a63460b0897 100644 --- a/core/services/relay/evm/types/codec_entry.go +++ b/core/services/relay/evm/types/codec_entry.go @@ -85,7 +85,15 @@ func (entry *codecEntry) EncodingPrefix() []byte { return tmp } -func (entry *codecEntry) Init() error { +func (entry *codecEntry) Init() (err error) { + // Since reflection panics if errors occur, best to recover in case of any unknown errors + defer func() { + if r := recover(); r != nil { + entry.checkedType = nil + entry.nativeType = nil + err = fmt.Errorf("%w: %v", commontypes.ErrInvalidConfig, r) + } + }() if entry.checkedType != nil { return nil } @@ -234,6 +242,7 @@ func createTupleType(curType *abi.Type, converter func(reflect.Type) reflect.Typ checkedFields := make([]reflect.StructField, len(curType.TupleElems)) for i, elm := range curType.TupleElems { name := curType.TupleRawNames[i] + name = strings.ToUpper(name[:1]) + name[1:] nativeFields[i].Name = name checkedFields[i].Name = name nativeArgType, checkedArgType, err := getNativeAndCheckedTypes(elm) diff --git a/core/services/relay/evm/types/codec_entry_test.go b/core/services/relay/evm/types/codec_entry_test.go index 1ea3a9ae576..d4a0dd8edea 100644 --- a/core/services/relay/evm/types/codec_entry_test.go +++ b/core/services/relay/evm/types/codec_entry_test.go @@ -94,6 +94,43 @@ func TestCodecEntry(t *testing.T) { assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) }) + t.Run("nested tuple member names are capitalized", func(t *testing.T) { + type1, err := abi.NewType("uint16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + tupleType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "field3", Type: "uint24"}, + {Name: "field4", Type: "int24"}, + }) + require.NoError(t, err) + args := abi.Arguments{ + {Name: "field1", Type: type1}, + {Name: "field2", Type: tupleType}, + } + entry := NewCodecEntry(args, nil, nil) + require.NoError(t, entry.Init()) + + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + f1 := uint16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&f1)) + f2 := iChecked.FieldByName("Field2") + f2.Set(reflect.New(f2.Type().Elem())) + f2 = reflect.Indirect(f2) + f3 := big.NewInt( /*2^24 - 1*/ 16777215) + setAndVerifyLimit(t, (*uint24)(f3), f3, f2.FieldByName("Field3")) + f4 := big.NewInt( /*2^23 - 1*/ 8388607) + setAndVerifyLimit(t, (*int24)(f4), f4, f2.FieldByName("Field4")) + + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + require.Equal(t, iNative.Field(0).Interface(), iChecked.Field(0).Interface()) + nF2 := reflect.Indirect(iNative.Field(1)) + assert.Equal(t, nF2.Field(0).Interface(), f3) + assert.Equal(t, nF2.Field(1).Interface(), f4) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + t.Run("unwrapped types", func(t *testing.T) { // This exists to allow you to decode single returned values without naming the parameter wrappedTuple, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{