Skip to content

Commit

Permalink
Soft migration to Generalize Multinode client for EVM BCI-2286 (#11369)
Browse files Browse the repository at this point in the history
* Allow switching to Generalized MultiNode EVM client via feature flag

* test how linter reacts to deprecation

* deprecate evm.client

* address review comments

* revert adding feature flag

* create new client

* fix call context

* unwrapp CallContext args

* deprecation msg improvements
  • Loading branch information
dhaidashenko authored Nov 28, 2023
1 parent 1788c04 commit 25deefa
Show file tree
Hide file tree
Showing 11 changed files with 45 additions and 42 deletions.
2 changes: 1 addition & 1 deletion core/chains/evm/client/chain_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (c *chainClient) BlockByNumber(ctx context.Context, number *big.Int) (b *ty
}

func (c *chainClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
return c.multiNode.CallContext(ctx, result, method)
return c.multiNode.CallContext(ctx, result, method, args...)
}

func (c *chainClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
Expand Down
2 changes: 2 additions & 0 deletions core/chains/evm/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ var _ htrktypes.Client[*evmtypes.Head, ethereum.Subscription, *big.Int, common.H

// NewClientWithNodes instantiates a client from a list of nodes
// Currently only supports one primary
//
// Deprecated: use [NewChainClient]
func NewClientWithNodes(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) {
pool := NewPool(logger, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType)
return &client{
Expand Down
4 changes: 4 additions & 0 deletions core/chains/evm/client/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ var (
//go:generate mockery --quiet --name Node --output ../mocks/ --case=underscore

// Node represents a client that connects to an ethereum-compatible RPC node
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.Node]
type Node interface {
Start(ctx context.Context) error
Close() error
Expand Down Expand Up @@ -179,6 +181,8 @@ type node struct {
}

// NewNode returns a new *node as Node
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewNode]
func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, wsuri url.URL, httpuri *url.URL, name string, id int32, chainID *big.Int, nodeOrder int32) Node {
n := new(node)
n.name = name
Expand Down
2 changes: 2 additions & 0 deletions core/chains/evm/client/node_fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ var (

// NodeState represents the current state of the node
// Node is a FSM (finite state machine)
//
// Deprecated: to be removed. It is now internal in common/client
type NodeState int

func (n NodeState) String() string {
Expand Down
1 change: 1 addition & 0 deletions core/chains/evm/client/node_selector_highest_head.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

type highestHeadNodeSelector []Node

// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewHighestHeadNodeSelector]
func NewHighestHeadNodeSelector(nodes []Node) NodeSelector {
return highestHeadNodeSelector(nodes)
}
Expand Down
1 change: 1 addition & 0 deletions core/chains/evm/client/node_selector_priority_level.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type nodeWithPriority struct {
priority int32
}

// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewPriorityLevelNodeSelector]
func NewPriorityLevelNodeSelector(nodes []Node) NodeSelector {
return &priorityLevelNodeSelector{
nodes: nodes,
Expand Down
1 change: 1 addition & 0 deletions core/chains/evm/client/node_selector_round_robin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type roundRobinSelector struct {
roundRobinCount atomic.Uint32
}

// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewRoundRobinSelector]
func NewRoundRobinSelector(nodes []Node) NodeSelector {
return &roundRobinSelector{
nodes: nodes,
Expand Down
1 change: 1 addition & 0 deletions core/chains/evm/client/node_selector_total_difficulty.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

type totalDifficultyNodeSelector []Node

// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewTotalDifficultyNodeSelector]
func NewTotalDifficultyNodeSelector(nodes []Node) NodeSelector {
return totalDifficultyNodeSelector(nodes)
}
Expand Down
9 changes: 9 additions & 0 deletions core/chains/evm/client/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const (
)

// NodeSelector represents a strategy to select the next node from the pool.
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NodeSelector]
type NodeSelector interface {
// Select returns a Node, or nil if none can be selected.
// Implementation must be thread-safe.
Expand All @@ -48,6 +50,8 @@ type NodeSelector interface {
}

// PoolConfig represents settings for the Pool
//
// Deprecated: to be removed
type PoolConfig interface {
NodeSelectionMode() string
NodeNoNewHeadsThreshold() time.Duration
Expand All @@ -56,6 +60,8 @@ type PoolConfig interface {

// Pool represents an abstraction over one or more primary nodes
// It is responsible for liveness checking and balancing queries across live nodes
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.MultiNode]
type Pool struct {
services.StateMachine
nodes []Node
Expand All @@ -76,6 +82,9 @@ type Pool struct {
wg sync.WaitGroup
}

// NewPool - creates new instance of [Pool]
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewMultiNode]
func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsTreshold time.Duration, nodes []Node, sendonlys []SendOnlyNode, chainID *big.Int, chainType config.ChainType) *Pool {
if chainID == nil {
panic("chainID is required")
Expand Down
4 changes: 4 additions & 0 deletions core/chains/evm/client/send_only_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
//go:generate mockery --quiet --name SendOnlyNode --output ../mocks/ --case=underscore

// SendOnlyNode represents one ethereum node used as a sendonly
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.SendOnlyNode]
type SendOnlyNode interface {
// Start may attempt to connect to the node, but should only return error for misconfiguration - never for temporary errors.
Start(context.Context) error
Expand Down Expand Up @@ -73,6 +75,8 @@ type sendOnlyNode struct {
}

// NewSendOnlyNode returns a new sendonly node
//
// Deprecated: use [pkg/github.com/smartcontractkit/chainlink/v2/common/client.NewSendOnlyNode]
func NewSendOnlyNode(lggr logger.Logger, httpuri url.URL, name string, chainID *big.Int) SendOnlyNode {
s := new(sendOnlyNode)
s.name = name
Expand Down
60 changes: 19 additions & 41 deletions core/chains/legacyevm/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types"

commonclient "github.com/smartcontractkit/chainlink/v2/common/client"
commonconfig "github.com/smartcontractkit/chainlink/v2/common/config"
"github.com/smartcontractkit/chainlink/v2/core/chains"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
Expand Down Expand Up @@ -220,11 +221,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod
if !cfg.EVMRPCEnabled() {
client = evmclient.NewNullClient(chainID, l)
} else if opts.GenEthClient == nil {
var err2 error
client, err2 = newEthClientFromChain(cfg.EVM().NodePool(), cfg.EVM().NodeNoNewHeadsThreshold(), l, chainID, chainType, nodes)
if err2 != nil {
return nil, fmt.Errorf("failed to instantiate eth client for chain with ID %s: %w", cfg.EVM().ChainID().String(), err2)
}
client = newEthClientFromCfg(cfg.EVM().NodePool(), cfg.EVM().NodeNoNewHeadsThreshold(), l, chainID, chainType, nodes)
} else {
client = opts.GenEthClient(chainID)
}
Expand Down Expand Up @@ -474,46 +471,27 @@ func (c *chain) Logger() logger.Logger { return c.logger }
func (c *chain) BalanceMonitor() monitor.BalanceMonitor { return c.balanceMonitor }
func (c *chain) GasEstimator() gas.EvmFeeEstimator { return c.gasEstimator }

func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) (evmclient.Client, error) {
var primaries []evmclient.Node
var sendonlys []evmclient.SendOnlyNode
func newEthClientFromCfg(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType commonconfig.ChainType, nodes []*toml.Node) evmclient.Client {
var empty url.URL
var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient]
var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient]
for i, node := range nodes {
if node.SendOnly != nil && *node.SendOnly {
sendonly := evmclient.NewSendOnlyNode(lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID)
name := fmt.Sprintf("eth-sendonly-rpc-%d", i)
rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), name, int32(i), chainID,
commonclient.Secondary)
sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL),
*node.Name, chainID, rpc)
sendonlys = append(sendonlys, sendonly)
} else {
primary, err := newPrimary(cfg, noNewHeadsThreshold, lggr, node, int32(i), chainID)
if err != nil {
return nil, err
}
primaries = append(primaries, primary)
name := fmt.Sprintf("eth-primary-rpc-%d", i)
rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), name, int32(i),
chainID, commonclient.Primary)
primaryNode := commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold,
lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order,
rpc, "EVM")
primaries = append(primaries, primaryNode)
}
}
return evmclient.NewClientWithNodes(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType)
return evmclient.NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType)
}

func newPrimary(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, n *toml.Node, id int32, chainID *big.Int) (evmclient.Node, error) {
if n.SendOnly != nil && *n.SendOnly {
return nil, errors.New("cannot cast send-only node to primary")
}

return evmclient.NewNode(cfg, noNewHeadsThreshold, lggr, (url.URL)(*n.WSURL), (*url.URL)(n.HTTPURL), *n.Name, id, chainID, *n.Order), nil
}

// TODO-1663: replace newEthClientFromChain with the function below once client.go is deprecated.
//func newEthClientFromChain(cfg evmconfig.NodePool, noNewHeadsThreshold time.Duration, lggr logger.Logger, chainID *big.Int, chainType config.ChainType, nodes []*toml.Node) evmclient.Client {
// var empty url.URL
// var primaries []commonclient.Node[*big.Int, *evmtypes.Head, evmclient.RPCCLient]
// var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient]
// for i, node := range nodes {
// if node.SendOnly != nil && *node.SendOnly {
// rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary)
// sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc)
// sendonlys = append(sendonlys, sendonly)
// } else {
// rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), fmt.Sprintf("eth-sendonly-rpc-%d", i), int32(i), chainID, commontypes.Primary)
// primaries = append(primaries, commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, rpc, "EVM"))
// }
// }
// return evmclient.NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), noNewHeadsThreshold, primaries, sendonlys, chainID, chainType)
//}

0 comments on commit 25deefa

Please sign in to comment.