Skip to content

Commit

Permalink
fix(chain): add network args to chain query
Browse files Browse the repository at this point in the history
Allow chain lookup by network and chain Id so we can differentiate same chain id in different networks.

JIRA: https://smartcontract-it.atlassian.net/browse/DPA-1151
  • Loading branch information
graham-chainlink committed Oct 22, 2024
1 parent 8968048 commit 7f834e2
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 6 deletions.
7 changes: 7 additions & 0 deletions .changeset/honest-bugs-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"chainlink": minor
---

#updated
update ethkeys, ethtransactions to handle duplicate chain id in different network
introduce network arg input to Chain graphql query to allow better lookup based on network and chain id
12 changes: 12 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,15 @@ var SupportedNetworks = map[string]struct{}{
NetworkDummy: {},
}

// From returns a NetworkType from a string.
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
4 changes: 2 additions & 2 deletions core/web/loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ func TestLoader_ChainsRelayID_HandleDuplicateIDAcrossNetworks(t *testing.T) {
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)
require.Error(t, results[2].Error)
require.ErrorIs(t, results[2].Error, chains.ErrNotFound)
}

func TestLoader_Nodes(t *testing.T) {
Expand Down
62 changes: 62 additions & 0 deletions core/web/resolver/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"testing"

gqlerrors "github.com/graph-gophers/graphql-go/errors"
Expand Down Expand Up @@ -160,6 +161,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 @@ -291,6 +308,51 @@ ResendAfterThreshold = '1h0m0s'
},
},
},
{
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),
},
}

RunGQLTests(t, testCases)
Expand Down
29 changes: 26 additions & 3 deletions core/web/resolver/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/graph-gophers/graphql-go"
"github.com/pkg/errors"

"github.com/smartcontractkit/chainlink-common/pkg/types"
commonTypes "github.com/smartcontractkit/chainlink/v2/common/types"
"github.com/smartcontractkit/chainlink/v2/core/bridges"
"github.com/smartcontractkit/chainlink/v2/core/chains"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
"github.com/smartcontractkit/chainlink/v2/core/utils/stringutils"
"github.com/smartcontractkit/chainlink/v2/core/web/loader"
Expand Down Expand Up @@ -64,12 +65,34 @@ func (r *Resolver) Bridges(ctx context.Context, args struct {
}

// Chain retrieves a chain by id.
func (r *Resolver) Chain(ctx context.Context, args struct{ ID graphql.ID }) (*ChainPayloadResolver, error) {
func (r *Resolver) Chain(ctx context.Context,
args struct {
ID graphql.ID
Network *string
}) (*ChainPayloadResolver, error) {
if err := authenticateUser(ctx); err != nil {
return nil, err
}

id, err := loader.GetChainByID(ctx, string(args.ID))
// fall back to original behaviour if network is not provided
if args.Network == nil {
id, err := loader.GetChainByID(ctx, string(args.ID))
if err != nil {
if errors.Is(err, chains.ErrNotFound) {
return NewChainPayload(commonTypes.ChainStatusWithID{}, chains.ErrNotFound), nil
}
return nil, err
}
return NewChainPayload(*id, nil), nil
}

networkToUse, err := relay.From(*args.Network)
if err != nil {
return NewChainPayload(commonTypes.ChainStatusWithID{}, chains.ErrNotFound), nil
}

relayID := types.NewRelayID(string(networkToUse), string(args.ID))
id, err := loader.GetChainByRelayID(ctx, relayID.Name())
if err != nil {
if errors.Is(err, chains.ErrNotFound) {
return NewChainPayload(commonTypes.ChainStatusWithID{}, chains.ErrNotFound), nil
Expand Down
2 changes: 1 addition & 1 deletion core/web/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ schema {
type Query {
bridge(id: ID!): BridgePayload!
bridges(offset: Int, limit: Int): BridgesPayload!
chain(id: ID!): ChainPayload!
chain(id: ID!, network: Network): ChainPayload!
chains(offset: Int, limit: Int): ChainsPayload!
configv2: ConfigV2Payload!
csaKeys: CSAKeysPayload!
Expand Down
8 changes: 8 additions & 0 deletions core/web/schema/type/chain.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ type ChainsPayload implements PaginatedPayload {
results: [Chain!]!
metadata: PaginationMetadata!
}

enum Network {
EVM
COSMOS
SOLANA
STARKNET
APTOS
}

0 comments on commit 7f834e2

Please sign in to comment.