Skip to content

Commit

Permalink
Improve error messages in evm chain reader and add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed Nov 26, 2023
1 parent 2597944 commit 1a739b6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 23 deletions.
10 changes: 5 additions & 5 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type chainReader struct {
// NewChainReaderService constructor for ChainReader
func NewChainReaderService(lggr logger.Logger, lp logpoller.LogPoller, contractID common.Address, config types.ChainReaderConfig) (*chainReader, error) {
if err := validateChainReaderConfig(config); err != nil {
return nil, err
return nil, fmt.Errorf("%w err: %w", commontypes.ErrInvalidConfig, err)
}

// TODO BCF-2814 implement initialisation of chain reading definitions and pass them into chainReader
Expand Down Expand Up @@ -83,13 +83,13 @@ func (cr *chainReader) GetMaxDecodingSize(ctx context.Context, n int, itemType s

func validateChainReaderConfig(cfg types.ChainReaderConfig) error {
if len(cfg.ChainContractReaders) == 0 {
return fmt.Errorf("chain reader config is empty")
return fmt.Errorf("config is empty")
}

for contractName, chainContractReader := range cfg.ChainContractReaders {
abi, err := abi.JSON(strings.NewReader(chainContractReader.ContractABI))
if err != nil {
return err
return fmt.Errorf("invalid abi: %w", err)
}

for chainReadingDefinitionName, chainReaderDefinition := range chainContractReader.ChainReaderDefinitions {
Expand All @@ -99,10 +99,10 @@ func validateChainReaderConfig(cfg types.ChainReaderConfig) error {
case types.Event:
err = validateEvents(abi, chainReaderDefinition)
default:
return fmt.Errorf("%w: invalid chain reader definition read type: %d", commontypes.ErrInvalidConfig, chainReaderDefinition.ReadType)
return fmt.Errorf("invalid chain reading definition read type: %d for contract: %q", chainReaderDefinition.ReadType, contractName)
}
if err != nil {
return fmt.Errorf("%w: invalid chain reader config for contract: %q chain reading definition: %q, err: %w", commontypes.ErrInvalidConfig, contractName, chainReadingDefinitionName, err)
return fmt.Errorf("invalid chain reading definition: %q for contract: %q, err: %w", chainReadingDefinitionName, contractName, err)
}
}
}
Expand Down
62 changes: 44 additions & 18 deletions core/services/relay/evm/chain_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ func TestNewChainReader(t *testing.T) {
t.Run("ChainReader config is empty", func(t *testing.T) {
emptyChainReaderConfig := evmtypes.ChainReaderConfig{}
_, err := NewChainReaderService(lggr, chain.LogPoller(), contractID, emptyChainReaderConfig)
assert.EqualError(t, err, "chain reader config is empty")
assert.ErrorIs(t, err, commontypes.ErrInvalidConfig)
assert.ErrorContains(t, err, "config is empty")
})
}

Expand All @@ -100,12 +101,11 @@ func TestChainReaderStartClose(t *testing.T) {
assert.NoError(t, err)
}

func TestValidateChainReaderConfig(t *testing.T) {
func TestValidateChainReaderConfig_HappyPath(t *testing.T) {
type testCase struct {
name string
abiInput string
chainReadingDefinitions string
expected error
}

var testCases []testCase
Expand Down Expand Up @@ -323,10 +323,19 @@ func TestValidateChainReaderConfig(t *testing.T) {
assert.NoError(t, err)
assert.NoError(t, validateChainReaderConfig(cfg))
})
}

func TestValidateChainReaderConfig_BadPath(t *testing.T) {
type testCase struct {
name string
abiInput string
chainReadingDefinitions string
expected error
}

var badPathTestCases []testCase
var testCases []testCase
mismatchedEventArgumentsTestABI := `{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"Swap","type":"event"}`
badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "mismatched abi and event chain reading param values",
abiInput: mismatchedEventArgumentsTestABI,
Expand All @@ -340,10 +349,10 @@ func TestValidateChainReaderConfig(t *testing.T) {
],
"readType": 1
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"Swap\", err: params: [malformedParam] don't match abi event indexed inputs: [sender]"),
expected: fmt.Errorf("invalid chain reading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi event indexed inputs: [sender]"),
})

badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "mismatched abi and event chain reading return values",
abiInput: mismatchedEventArgumentsTestABI,
Expand All @@ -357,11 +366,11 @@ func TestValidateChainReaderConfig(t *testing.T) {
],
"readType": 1
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"Swap\", err: return values: [malformedParam] don't match abi event inputs: [sender]"),
expected: fmt.Errorf("invalid chain reading definition: \"Swap\" for contract: \"testContract\", err: return values: [malformedParam] don't match abi event inputs: [sender]"),
})

mismatchedFunctionArgumentsTestABI := `{"constant":true,"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"Swap","outputs":[{"internalType":"address","name":"to","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}`
badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "mismatched abi and method chain reading param values",
abiInput: mismatchedFunctionArgumentsTestABI,
Expand All @@ -375,11 +384,11 @@ func TestValidateChainReaderConfig(t *testing.T) {
],
"readType": 0
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"Swap\", err: params: [malformedParam] don't match abi method inputs: [from]"),
expected: fmt.Errorf("invalid chain reading definition: \"Swap\" for contract: \"testContract\", err: params: [malformedParam] don't match abi method inputs: [from]"),
},
)

badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "mismatched abi and method chain reading return values",
abiInput: mismatchedFunctionArgumentsTestABI,
Expand All @@ -393,42 +402,59 @@ func TestValidateChainReaderConfig(t *testing.T) {
],
"readType": 0
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"Swap\", err: return values: [malformedReturnValue] don't match abi method outputs: [to]"),
expected: fmt.Errorf("invalid chain reading definition: \"Swap\" for contract: \"testContract\", err: return values: [malformedReturnValue] don't match abi method outputs: [to]"),
},
)

badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "event doesn't exist",
abiInput: `{"constant":true,"inputs":[],"name":"someName","outputs":[],"payable":false,"stateMutability":"view","type":"function"}`,
chainReadingDefinitions: `"TestMethod":{
"chainSpecificName": "Swap",
"readType": 1
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"TestMethod\", err: event: Swap doesn't exist"),
expected: fmt.Errorf("invalid chain reading definition: \"TestMethod\" for contract: \"testContract\", err: event: Swap doesn't exist"),
},
)

badPathTestCases = append(badPathTestCases,
testCases = append(testCases,
testCase{
name: "method doesn't exist",
abiInput: `{"constant":true,"inputs":[],"name":"someName","outputs":[],"payable":false,"stateMutability":"view","type":"function"}`,
chainReadingDefinitions: `"TestMethod":{
"chainSpecificName": "Swap",
"readType": 0
}`,
expected: fmt.Errorf("invalid configuration: invalid chain reader config for contract: \"testContract\" chain reading definition: \"TestMethod\", err: method: \"Swap\" doesn't exist"),
expected: fmt.Errorf("invalid chain reading definition: \"TestMethod\" for contract: \"testContract\", err: method: \"Swap\" doesn't exist"),
},
)

for _, tc := range badPathTestCases {
testCases = append(testCases, testCase{
name: "invalid abi",
abiInput: `broken abi`,
chainReadingDefinitions: `"TestMethod":{
"chainSpecificName": "Swap",
"readType": 0
}`,
expected: fmt.Errorf("invalid abi"),
})

testCases = append(testCases, testCase{
name: "invalid read type",
abiInput: `{"constant":true,"inputs":[],"name":"someName","outputs":[],"payable":false,"stateMutability":"view","type":"function"}`,
chainReadingDefinitions: `"TestMethod":{"readType": 59}`,
expected: fmt.Errorf("invalid chain reading definition read type: 59"),
})

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cfg, err := chainReaderTestHelper{}.makeChainReaderConfigFromStrings(tc.abiInput, tc.chainReadingDefinitions)
assert.NoError(t, err)
if tc.expected == nil {
assert.NoError(t, validateChainReaderConfig(cfg))
} else {
assert.EqualError(t, validateChainReaderConfig(cfg), tc.expected.Error())
assert.ErrorContains(t, validateChainReaderConfig(cfg), tc.expected.Error())
}
})
}
Expand Down

0 comments on commit 1a739b6

Please sign in to comment.