Skip to content

Commit

Permalink
Add smoke test for chain reader and codec
Browse files Browse the repository at this point in the history
  • Loading branch information
nolag committed Dec 13, 2023
1 parent 33f697b commit 282bfeb
Show file tree
Hide file tree
Showing 20 changed files with 359 additions and 92 deletions.
21 changes: 20 additions & 1 deletion core/services/job/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,21 @@ type JSONConfig map[string]interface{}

// Bytes returns the raw bytes
func (r JSONConfig) Bytes() []byte {
b, _ := json.Marshal(r)
var retCopy = make(JSONConfig, len(r))
for key, value := range r {
copiedVal := value
// If the value is a json structure string, unmarshal it to preserve JSON structure
// e.g. instead of this {"key":"{\"nestedKey\":{\"nestedValue\":123}}"}
// we want this {"key":{"nestedKey":{"nestedValue":123}}},
if strValue, ok := copiedVal.(string); ok {
if object, ok := asObject(strValue); ok {
copiedVal = object
}
}
retCopy[key] = copiedVal
}

b, _ := json.Marshal(retCopy)
return b
}

Expand Down Expand Up @@ -306,6 +320,11 @@ func (r JSONConfig) MercuryCredentialName() (string, error) {
return name, nil
}

func asObject(s string) (any, bool) {
var js map[string]interface{}
return js, json.Unmarshal([]byte(s), &js) == nil
}

var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions}

// OCR2OracleSpec defines the job spec for OCR2 jobs.
Expand Down
29 changes: 27 additions & 2 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package evm
import (
"context"
"fmt"
"runtime"
"strings"

"github.com/ethereum/go-ethereum"
Expand Down Expand Up @@ -63,8 +64,13 @@ func (cr *chainReader) Name() string { return cr.lggr.Name() }
var _ commontypes.ContractTypeProvider = &chainReader{}

func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, params any, returnVal any) error {
b := make([]byte, 2048) // adjust buffer size to be larger than expected stack
n := runtime.Stack(b, false)
s := string(b[:n])
cr.lggr.Infof("!!!!!!!!!!\nEVM CR\n%s.%s\n%#v\n%s\n!!!!!!!!!!\n", contractName, method, params, s)
ae, err := cr.bindings.getBinding(contractName, method, false)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM CR err:\n%v\n!!!!!!!!!!\n", err)
return err
}

Expand All @@ -76,29 +82,41 @@ func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method
}

func (cr *chainReader) getLatestValueFromLogPoller(ctx context.Context, contractName, method string, hash common.Hash, returnVal any) error {
cr.lggr.Infof("!!!!!!!!!!\nEVM latest from log poller\n!!!!!!!!!!\n")
ae, err := cr.bindings.getBinding(contractName, method, false)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM no binding err:\n%v\n!!!!!!!!!!\n", err)
return err
}

log, err := cr.lp.LatestLogByEventSigWithConfs(hash, ae.addr, logpoller.Finalized)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nNo sig err:\n%v\n!!!!!!!!!!\n", err)
if strings.Contains(err.Error(), "not found") {
return fmt.Errorf("%w: %w", commontypes.ErrNotFound, err)
}
return fmt.Errorf("%w: %w", commontypes.ErrInternal, err)
}
return cr.codec.Decode(ctx, log.Data, returnVal, wrapItemType(contractName, method, false))
err = cr.codec.Decode(ctx, log.Data, returnVal, wrapItemType(contractName, method, false))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM decode err:\n%v\n!!!!!!!!!!\n", err)
} else {
cr.lggr.Infof("!!!!!!!!!!\nEVM decode success\n%#v\n!!!!!!!!!!\n", returnVal)
}
return err
}

func (cr *chainReader) getLatestValueFromContract(ctx context.Context, contractName, method string, params any, returnVal any) error {
cr.lggr.Infof("!!!!!!!!!!\nEVM latest from contract\n!!!!!!!!!!\n")
data, err := cr.codec.Encode(ctx, params, wrapItemType(contractName, method, true))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM encode err:\n%v\n!!!!!!!!!!\n", err)
return err
}

ae, err := cr.bindings.getBinding(contractName, method, true)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM no binding err:\n%v\n!!!!!!!!!!\n", err)
return err
}
callMsg := ethereum.CallMsg{
Expand All @@ -110,10 +128,17 @@ func (cr *chainReader) getLatestValueFromContract(ctx context.Context, contractN
output, err := cr.client.CallContract(ctx, callMsg, nil)

if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM call err:\n%v\n!!!!!!!!!!\n", err)
return err
}

return cr.codec.Decode(ctx, output, returnVal, wrapItemType(contractName, method, false))
err = cr.codec.Decode(ctx, output, returnVal, wrapItemType(contractName, method, false))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM decode err:\n%v\n!!!!!!!!!!\n", err)
} else {
cr.lggr.Infof("!!!!!!!!!!\nEVM decode success\n%#v\n!!!!!!!!!!\n", returnVal)
}
return err
}

func (cr *chainReader) Start(_ context.Context) error {
Expand Down
26 changes: 13 additions & 13 deletions core/services/relay/evm/chain_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ func (it *chainReaderInterfaceTester) Name() string {
}

func (it *chainReaderInterfaceTester) GetAccountBytes(i int) []byte {
account := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2}
account[i%32] += byte(i)
account[(i+3)%32] += byte(i + 3)
return account
account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
account[i%20] += byte(i)
account[(i+3)%20] += byte(i + 3)
return account[:]
}

func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes.ChainReader {
Expand Down Expand Up @@ -176,7 +176,7 @@ func (it *chainReaderInterfaceTester) TriggerEvent(t *testing.T, testStruct *Tes
it.sendTxWithTestStruct(t, testStruct, (*testfiles.TestfilesTransactor).TriggerEvent)
}

type testStructFn = func(*testfiles.TestfilesTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, [32]byte, [][32]byte, *big.Int, testfiles.MidLevelTestStruct) (*evmtypes.Transaction, error)
type testStructFn = func(*testfiles.TestfilesTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, testfiles.MidLevelTestStruct) (*evmtypes.Transaction, error)

func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStruct *TestStruct, fn testStructFn) {
tx, err := fn(
Expand All @@ -186,7 +186,7 @@ func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStr
testStruct.DifferentField,
uint8(testStruct.OracleID),
convertOracleIDs(testStruct.OracleIDs),
[32]byte(testStruct.Account),
common.Address(testStruct.Account),
convertAccounts(testStruct.Accounts),
testStruct.BigField,
midToInternalType(testStruct.NestedStruct),
Expand All @@ -205,10 +205,10 @@ func convertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte {
return convertedIds
}

func convertAccounts(accounts [][]byte) [][32]byte {
convertedAccounts := make([][32]byte, len(accounts))
func convertAccounts(accounts [][]byte) []common.Address {
convertedAccounts := make([]common.Address, len(accounts))
for i, a := range accounts {
convertedAccounts[i] = [32]byte(a)
convertedAccounts[i] = common.Address(a)
}
return convertedAccounts
}
Expand Down Expand Up @@ -267,10 +267,10 @@ func (it *chainReaderInterfaceTester) incNonce() {
}
}

func getAccounts(first TestStruct) [][32]byte {
accountBytes := make([][32]byte, len(first.Accounts))
func getAccounts(first TestStruct) []common.Address {
accountBytes := make([]common.Address, len(first.Accounts))
for i, account := range first.Accounts {
accountBytes[i] = [32]byte(account)
accountBytes[i] = common.Address(account)
}
return accountBytes
}
Expand Down Expand Up @@ -302,7 +302,7 @@ func toInternalType(testStruct TestStruct) testfiles.TestStruct {
DifferentField: testStruct.DifferentField,
OracleId: byte(testStruct.OracleID),
OracleIds: convertOracleIDs(testStruct.OracleIDs),
Account: [32]byte(testStruct.Account),
Account: common.Address(testStruct.Account),
Accounts: convertAccounts(testStruct.Accounts),
BigField: testStruct.BigField,
NestedStruct: midToInternalType(testStruct.NestedStruct),
Expand Down
17 changes: 13 additions & 4 deletions core/services/relay/evm/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/mitchellh/mapstructure"

Expand All @@ -27,6 +28,7 @@ import (
var evmDecoderHooks = []mapstructure.DecodeHookFunc{decodeAccountHook, codec.BigIntHook, codec.SliceToArrayVerifySizeHook, sizeVerifyBigIntHook}

func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) {
fmt.Printf("!!!!!!!!!!\nNewCodec\n%#v\n!!!!!!!!!!\n", conf.ChainCodecConfigs)
parsed := &parsedTypes{
encoderDefs: map[string]*codecEntry{},
decoderDefs: map[string]*codecEntry{},
Expand All @@ -35,16 +37,19 @@ func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) {
for k, v := range conf.ChainCodecConfigs {
args := abi.Arguments{}
if err := json.Unmarshal(([]byte)(v.TypeAbi), &args); err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec json abi/n%s/n err\n%#v\n!!!!!!!!!!\n%", v.TypeAbi, err)
return nil, err
}

mod, err := v.ModifierConfigs.ToModifier(evmDecoderHooks...)
if err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec mod err\n%#v\n!!!!!!!!!!\n%", err)
return nil, err
}

item := &codecEntry{Args: args, mod: mod}
if err := item.Init(); err != nil {
if err = item.Init(); err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec init err\n%#v\n!!!!!!!!!!\n%", err)
return nil, err
}

Expand Down Expand Up @@ -106,13 +111,17 @@ func sizeVerifyBigIntHook(from, to reflect.Type, data any) (any, error) {
}

func decodeAccountHook(from, to reflect.Type, data any) (any, error) {
b32, _ := types.GetType("bytes32")
if from.Kind() == reflect.String && to == b32.Checked {
if from.Kind() == reflect.String && to == reflect.TypeOf(common.Address{}) {
decoded, err := hexutil.Decode(data.(string))
if err != nil {
return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err)
} else if len(decoded) != common.AddressLength {
return nil, fmt.Errorf(
"%w: wrong number size for address expected %v got %v",
commontypes.ErrWrongNumberOfElements,
common.AddressLength, len(decoded))
}
return [32]byte(decoded), nil
return common.Address(decoded), nil
}
return data, nil
}
4 changes: 4 additions & 0 deletions core/services/relay/evm/codec_entry.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evm

import (
"fmt"
"reflect"
"strings"

Expand Down Expand Up @@ -116,6 +117,9 @@ func getNativeAndCheckedTypes(curType *abi.Type) (reflect.Type, reflect.Type, er

func createTupleType(curType *abi.Type, converter func(reflect.Type) reflect.Type) (reflect.Type, reflect.Type, error) {
if len(curType.TupleElems) == 0 {
if curType.TupleType == nil {
return nil, nil, fmt.Errorf("%w: unsupported solitidy type: %v", commontypes.ErrInvalidType, curType.String())
}
return curType.TupleType, curType.TupleType, nil
}

Expand Down
16 changes: 16 additions & 0 deletions core/services/relay/evm/codec_entry_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evm

import (
"fmt"
"math/big"
"reflect"
"testing"
Expand Down Expand Up @@ -136,4 +137,19 @@ func TestCodecEntry(t *testing.T) {
iNative := reflect.Indirect(native)
iNative.FieldByName("Field1").Set(reflect.ValueOf([3]int16{2, 3, 30}))
})

t.Run("Not return values makes struct{}", func(t *testing.T) {
entry := codecEntry{Args: abi.Arguments{}}
require.NoError(t, entry.Init())
assert.Equal(t, reflect.TypeOf(struct{}{}), entry.nativeType)
assert.Equal(t, reflect.TypeOf(struct{}{}), entry.checkedType)
})

t.Run("Address works", func(t *testing.T) {
address, err := abi.NewType("address", "", []abi.ArgumentMarshaling{})
require.NoError(t, err)
entry := codecEntry{Args: abi.Arguments{{Name: "foo", Type: address}}}
fmt.Printf("%+v\n", address.GetType())
require.NoError(t, entry.Init())
})
}
11 changes: 11 additions & 0 deletions core/services/relay/evm/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package evm

import (
"context"
"fmt"
"reflect"
"runtime"

"github.com/mitchellh/mapstructure"

Expand All @@ -16,13 +18,16 @@ type decoder struct {
var _ commontypes.Decoder = &decoder{}

func (m *decoder) Decode(ctx context.Context, raw []byte, into any, itemType string) error {
fmt.Printf("!!!!!!!!!!\\nDecode\\n%s\\n!!!!!!!!!!\\n", itemType)
info, ok := m.Definitions[itemType]
if !ok {
fmt.Printf("!!!!!!!!!!\\nDecode err not found type\\n%s\\n!!!!!!!!!!\\n", itemType)
return commontypes.ErrInvalidType
}

decode, err := extractDecoding(info, raw)
if err != nil {
fmt.Printf("!!!!!!!!!!\\nDecode err: %v\\n%s\\n!!!!!!!!!!\\n", err, itemType)
return err
}

Expand All @@ -47,6 +52,11 @@ func (m *decoder) Decode(ctx context.Context, raw []byte, into any, itemType str
}

func (m *decoder) GetMaxDecodingSize(ctx context.Context, n int, itemType string) (int, error) {
b := make([]byte, 2048) // adjust buffer size to be larger than expected stack
nb := runtime.Stack(b, false)
s := string(b[:nb])
fmt.Printf("!!!!!!!!!!\\nGetMaxDecodingSize\\n%s\\n\\n%v\\n%s!!!!!!!!!!\\n", itemType, m.Definitions, s)

return m.Definitions[itemType].GetMaxSize(n)
}

Expand Down Expand Up @@ -80,6 +90,7 @@ func mapstructureDecode(src, dest any) error {
Squash: true,
})
if err != nil || mDecoder.Decode(src) != nil {
fmt.Printf("!!!!!!!!!!\\nDecode item error: %v\\n%v\\n!!!!!!!!!!\\n", err, mDecoder.Decode(src))
return commontypes.ErrInvalidType
}
return nil
Expand Down
Loading

0 comments on commit 282bfeb

Please sign in to comment.