Skip to content

Commit

Permalink
testing
Browse files Browse the repository at this point in the history
  • Loading branch information
graham-chainlink committed Oct 16, 2024
1 parent 12af1de commit 8915795
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 95 deletions.
10 changes: 10 additions & 0 deletions common/types/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package types

import "github.com/smartcontractkit/chainlink-common/pkg/types"

// NodeStatusWithRelayID is a composite type of NodeStatus and RelayID.
// It is used to represent the status of a node with its relay ID.
type NodeStatusWithRelayID struct {
types.NodeStatus
types.RelayID
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func (f *FakeRelayerChainInteroperators) List(filter chainlink.FilterFn) chainli
}

func (f *FakeRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, error) {
panic("unimplemented")
r, ok := f.Relayers[id]
if !ok {
return nil, chainlink.ErrNoSuchRelayer
}
return r, nil
}

func (f *FakeRelayerChainInteroperators) GetIDToRelayerMap() (map[types.RelayID]loop.Relayer, error) {
Expand Down
11 changes: 11 additions & 0 deletions core/services/relay/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package relay
import (
"context"
"fmt"
"strings"

"github.com/smartcontractkit/chainlink-common/pkg/loop"
"github.com/smartcontractkit/chainlink-common/pkg/types"
)

type NetworkType string

const (
NetworkEVM = "evm"
NetworkCosmos = "cosmos"
Expand All @@ -28,6 +31,14 @@ var SupportedNetworks = map[string]struct{}{
NetworkDummy: {},
}

func From(s string) (NetworkType, error) {
s = strings.ToLower(s)
if _, ok := SupportedNetworks[s]; !ok {
return "", fmt.Errorf("unknown network type: %s", s)
}
return NetworkType(s), nil
}

var _ loop.Relayer = (*ServerAdapter)(nil)

// ServerAdapter extends [loop.RelayerAdapter] by overriding NewPluginProvider to dispatches calls according to `RelayArgs.ProviderType`.
Expand Down
63 changes: 20 additions & 43 deletions core/web/loader/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package loader

import (
"context"
"slices"

"github.com/graph-gophers/dataloader"
commonTypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink/v2/common/types"
"github.com/smartcontractkit/chainlink/v2/core/chains"
"github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
Expand All @@ -14,55 +14,32 @@ type chainBatcher struct {
app chainlink.Application
}

func (b *chainBatcher) loadByIDs(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
// Create a map for remembering the order of keys passed in
keyOrder := make(map[string]int, len(keys))
// Collect the keys to search for
var chainIDs []string
for ix, key := range keys {
chainIDs = append(chainIDs, key.String())
keyOrder[key.String()] = ix
}

var cs []types.ChainStatusWithID
relayersMap, err := b.app.GetRelayers().GetIDToRelayerMap()
if err != nil {
return []*dataloader.Result{{Data: nil, Error: err}}
}

for k, v := range relayersMap {
s, err := v.GetChainStatus(ctx)
func (b *chainBatcher) loadByRelayIDs(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
results := make([]*dataloader.Result, 0, len(keys))
for _, key := range keys {
var relay commonTypes.RelayID
err := relay.UnmarshalString(key.String())
if err != nil {
return []*dataloader.Result{{Data: nil, Error: err}}
results = append(results, &dataloader.Result{Data: nil, Error: err})
continue
}

if slices.Contains(chainIDs, s.ID) {
cs = append(cs, types.ChainStatusWithID{
ChainStatus: s,
RelayID: k,
})
relayer, err := b.app.GetRelayers().Get(relay)
if err != nil {
results = append(results, &dataloader.Result{Data: nil, Error: chains.ErrNotFound})
continue
}
}

// todo: future improvements to handle multiple chains with same id
if len(cs) > len(keys) {
b.app.GetLogger().Warn("Found multiple chain with same id")
return []*dataloader.Result{{Data: nil, Error: chains.ErrMultipleChainFound}}
}

results := make([]*dataloader.Result, len(keys))
for _, c := range cs {
ix, ok := keyOrder[c.ID]
// if found, remove from index lookup map, so we know elements were found
if ok {
results[ix] = &dataloader.Result{Data: c, Error: nil}
delete(keyOrder, c.ID)
status, err := relayer.GetChainStatus(ctx)
if err != nil {
results = append(results, &dataloader.Result{Data: nil, Error: err})
continue
}
}

// fill array positions without any nodes
for _, ix := range keyOrder {
results[ix] = &dataloader.Result{Data: nil, Error: chains.ErrNotFound}
results = append(results, &dataloader.Result{Data: types.ChainStatusWithID{
ChainStatus: status,
RelayID: relay,
}, Error: err})
}

return results
Expand Down
2 changes: 1 addition & 1 deletion core/web/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func New(app chainlink.Application) *Dataloader {
return &Dataloader{
app: app,

ChainsByIDLoader: dataloader.NewBatchedLoader(chains.loadByIDs),
ChainsByIDLoader: dataloader.NewBatchedLoader(chains.loadByRelayIDs),
EthTxAttemptsByEthTxIDLoader: dataloader.NewBatchedLoader(attmpts.loadByEthTransactionIDs),
FeedsManagersByIDLoader: dataloader.NewBatchedLoader(mgrs.loadByIDs),
FeedsManagerChainConfigsByManagerIDLoader: dataloader.NewBatchedLoader(ccfgs.loadByManagerIDs),
Expand Down
53 changes: 35 additions & 18 deletions core/web/loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,42 +48,59 @@ func TestLoader_Chains(t *testing.T) {
config2, err := chain2.TOMLString()
require.NoError(t, err)

evm1 := commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: "1",
}
evm2 := commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: "2",
}
// check if can handle same chain ID but different network
solana1 := commontypes.RelayID{
Network: relay.NetworkSolana,
ChainID: "1",
}
app.On("GetRelayers").Return(&chainlinkmocks.FakeRelayerChainInteroperators{Relayers: map[commontypes.RelayID]loop.Relayer{
commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: "1",
}: testutils2.MockRelayer{ChainStatus: commontypes.ChainStatus{
evm1: testutils2.MockRelayer{ChainStatus: commontypes.ChainStatus{
ID: "1",
Enabled: true,
Config: config1,
}}, commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: "2",
}: testutils2.MockRelayer{ChainStatus: commontypes.ChainStatus{
}},
evm2: testutils2.MockRelayer{ChainStatus: commontypes.ChainStatus{
ID: "2",
Enabled: true,
Config: config2,
}},
solana1: testutils2.MockRelayer{ChainStatus: commontypes.ChainStatus{
ID: "1",
Enabled: true,
Config: "config",
}},
}})

evm3 := commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: "3",
}

batcher := chainBatcher{app}
keys := dataloader.NewKeysFromStrings([]string{"2", "1", "3"})
results := batcher.loadByIDs(ctx, keys)
keys := dataloader.NewKeysFromStrings([]string{evm2.String(), evm1.String(), evm3.String()})
results := batcher.loadByRelayIDs(ctx, keys)

assert.Len(t, results, 3)

require.NoError(t, err)
want2 := types.ChainStatusWithID{

assert.Equal(t, types.ChainStatusWithID{
ChainStatus: commontypes.ChainStatus{ID: "2", Enabled: true, Config: config2},
RelayID: commontypes.RelayID{Network: relay.NetworkEVM, ChainID: "2"},
}
assert.Equal(t, want2, results[0].Data.(types.ChainStatusWithID))
RelayID: evm2,
}, results[0].Data.(types.ChainStatusWithID))

want1 := types.ChainStatusWithID{
assert.Equal(t, types.ChainStatusWithID{
ChainStatus: commontypes.ChainStatus{ID: "1", Enabled: true, Config: config1},
RelayID: commontypes.RelayID{Network: relay.NetworkEVM, ChainID: "1"},
}
assert.Equal(t, want1, results[1].Data.(types.ChainStatusWithID))
RelayID: evm1,
}, results[1].Data.(types.ChainStatusWithID))
assert.Nil(t, results[2].Data)
assert.Error(t, results[2].Error)
assert.ErrorIs(t, results[2].Error, chains.ErrNotFound)
Expand Down
83 changes: 71 additions & 12 deletions core/web/resolver/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package resolver
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"testing"

gqlerrors "github.com/graph-gophers/graphql-go/errors"
"github.com/pelletier/go-toml/v2"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -160,6 +159,22 @@ func TestResolver_Chain(t *testing.T) {
}
}
`
queryWithNetwork = `
query GetChain($network: Network) {
chain(id: "1", network: $network) {
... on Chain {
id
enabled
config
network
}
... on NotFoundError {
code
message
}
}
}
`
configTOML = `ChainID = '1'
AutoCreateKey = false
BlockBackfillDepth = 100
Expand Down Expand Up @@ -197,7 +212,6 @@ ResendAfterThreshold = '1h0m0s'

configTOMLEscaped, err := json.Marshal(configTOML)
require.NoError(t, err)
multipleChainError := errors.New("multiple chains found with the same chain ID")
testCases := []GQLTestCase{
unauthorizedTestCase(GQLTestCase{query: query}, "chain"),
{
Expand Down Expand Up @@ -250,7 +264,7 @@ ResendAfterThreshold = '1h0m0s'
}`,
},
{
name: "multiple chain with same chainID found error",
name: "default to EVM network if network is not provided",
authenticated: true,
before: func(ctx context.Context, f *gqlTestFramework) {
chainConf := evmtoml.EVMConfig{
Expand Down Expand Up @@ -280,16 +294,61 @@ ResendAfterThreshold = '1h0m0s'
}},
}})
},
query: query,
result: "null",
errors: []*gqlerrors.QueryError{
query: query,
result: fmt.Sprintf(`
{
Extensions: nil,
ResolverError: multipleChainError,
Path: []interface{}{"chain"},
Message: multipleChainError.Error(),
},
"chain": {
"id": "1",
"enabled": true,
"config": %s,
"network": "evm"
}
}`, configTOMLEscaped),
},
{
name: "should return aptos chain if network is aptos",
authenticated: true,
variables: map[string]interface{}{
"network": strings.ToUpper(relay.NetworkAptos),
},
before: func(ctx context.Context, f *gqlTestFramework) {
chainConf := evmtoml.EVMConfig{
Chain: chain,
ChainID: &chainID,
}

chainConfToml, err2 := chainConf.TOMLString()
require.NoError(t, err2)

f.App.On("GetRelayers").Return(&chainlinkmocks.FakeRelayerChainInteroperators{Relayers: map[commontypes.RelayID]loop.Relayer{
commontypes.RelayID{
Network: relay.NetworkEVM,
ChainID: chainID.String(),
}: testutils.MockRelayer{ChainStatus: commontypes.ChainStatus{
ID: chainID.String(),
Enabled: chainConf.IsEnabled(),
Config: chainConfToml,
}},
commontypes.RelayID{
Network: relay.NetworkAptos,
ChainID: chainID.String(),
}: testutils.MockRelayer{ChainStatus: commontypes.ChainStatus{
ID: chainID.String(),
Enabled: chainConf.IsEnabled(),
Config: chainConfToml,
}},
}})
},
query: queryWithNetwork,
result: fmt.Sprintf(`
{
"chain": {
"id": "1",
"enabled": true,
"config": %s,
"network": "aptos"
}
}`, configTOMLEscaped),
},
}

Expand Down
5 changes: 4 additions & 1 deletion core/web/resolver/eth_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/graph-gophers/graphql-go"
commonTypes "github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
"github.com/smartcontractkit/chainlink/v2/core/web/loader"
)

Expand Down Expand Up @@ -37,7 +39,8 @@ func NewETHKeys(keys []ETHKey) []*ETHKeyResolver {
}

func (r *ETHKeyResolver) Chain(ctx context.Context) (*ChainResolver, error) {
chain, err := loader.GetChainByID(ctx, r.key.state.EVMChainID.String())
relayID := commonTypes.NewRelayID(relay.NetworkEVM, r.key.state.EVMChainID.String())
chain, err := loader.GetChainByID(ctx, relayID.Name())
if err != nil {
return nil, err
}
Expand Down
5 changes: 4 additions & 1 deletion core/web/resolver/eth_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/graph-gophers/graphql-go"
commonTypes "github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
"github.com/smartcontractkit/chainlink/v2/core/utils/stringutils"
"github.com/smartcontractkit/chainlink/v2/core/web/loader"
)
Expand Down Expand Up @@ -98,7 +100,8 @@ func (r *EthTransactionResolver) Hex(ctx context.Context) string {

// Chain resolves the node's chain object field.
func (r *EthTransactionResolver) Chain(ctx context.Context) (*ChainResolver, error) {
chain, err := loader.GetChainByID(ctx, string(r.EVMChainID()))
relayID := commonTypes.NewRelayID(relay.NetworkEVM, string(r.EVMChainID()))
chain, err := loader.GetChainByID(ctx, relayID.Name())
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 8915795

Please sign in to comment.