diff --git a/pkg/solana/chain.go b/pkg/solana/chain.go index e45018bd2..b1021fdc8 100644 --- a/pkg/solana/chain.go +++ b/pkg/solana/chain.go @@ -95,8 +95,9 @@ type chain struct { lggr logger.Logger // if multiNode is enabled, the clientCache will not be used - multiNode *client.MultiNodeWrappedClient - txSender *mn.TransactionSender[*solanago.Transaction, *client.SendTxResult, mn.StringID, *client.MultiNodeClient] + multiNode *mn.MultiNode[mn.StringID, *client.MultiNodeClient] + txSender *mn.TransactionSender[*solanago.Transaction, *client.SendTxResult, mn.StringID, *client.MultiNodeClient] + multiClient *client.MultiClient // tracking node chain id for verification clientCache map[string]*verifiedCachedClient // map URL -> {client, chainId} [mainnet/testnet/devnet/localnet] @@ -238,6 +239,7 @@ func newChain(id string, cfg *config.TOMLConfig, ks core.Keystore, lggr logger.L var tc internal.Loader[client.ReaderWriter] = utils.NewLazyLoad(func() (client.ReaderWriter, error) { return ch.getClient() }) var bc internal.Loader[monitor.BalanceClient] = utils.NewLazyLoad(func() (monitor.BalanceClient, error) { return ch.getClient() }) + ch.multiClient = client.NewMultiNodeWrappedClient(ch.getClient) // txm will default to sending transactions using a single RPC client if sendTx is nil var sendTx func(ctx context.Context, tx *solanago.Transaction) (solanago.Signature, error) @@ -289,8 +291,11 @@ func newChain(id string, cfg *config.TOMLConfig, ks core.Keystore, lggr logger.L 0, // use the default value provided by the implementation ) - ch.multiNode = client.NewMultiNodeWrappedClient(multiNode) + ch.multiNode = multiNode ch.txSender = txSender + ch.multiClient = client.NewMultiNodeWrappedClient(func() (client.ReaderWriter, error) { + return ch.multiNode.SelectRPC() + }) // clientCache will not be used if multinode is enabled ch.clientCache = nil @@ -304,8 +309,8 @@ func newChain(id string, cfg *config.TOMLConfig, ks core.Keystore, lggr logger.L return result.Signature(), result.Error() } - tc = internal.NewLoader[client.ReaderWriter](func() (client.ReaderWriter, error) { return ch.multiNode, nil }) - bc = internal.NewLoader[monitor.BalanceClient](func() (monitor.BalanceClient, error) { return ch.multiNode, nil }) + tc = internal.NewLoader[client.ReaderWriter](func() (client.ReaderWriter, error) { return ch.multiNode.SelectRPC() }) + bc = internal.NewLoader[monitor.BalanceClient](func() (monitor.BalanceClient, error) { return ch.multiNode.SelectRPC() }) } ch.txm = txm.NewTxm(ch.id, tc, sendTx, cfg, ks, lggr) @@ -413,7 +418,7 @@ func (c *chain) ChainID() string { // If multinode is enabled, it will return a client using the multinode selection instead. func (c *chain) getClient() (client.ReaderWriter, error) { if c.cfg.MultiNode.Enabled() { - return c.multiNode, nil + return c.multiNode.SelectRPC() } var node *config.Node diff --git a/pkg/solana/client/multinode_wrapped_client.go b/pkg/solana/client/multinode_wrapped_client.go index 4ac955b40..d955bb8ab 100644 --- a/pkg/solana/client/multinode_wrapped_client.go +++ b/pkg/solana/client/multinode_wrapped_client.go @@ -9,23 +9,22 @@ import ( mn "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/multinode" ) -var _ ReaderWriter = (*MultiNodeWrappedClient)(nil) +var _ ReaderWriter = (*MultiClient)(nil) -// MultiNodeWrappedClient - wrapper over MultiNode that reselect an RPC for each method call. -type MultiNodeWrappedClient struct { - multiNode *mn.MultiNode[mn.StringID, *MultiNodeClient] +// MultiClient - wrapper over multiple RPCs, underlying provider can be MultiNode or LazyLoader. +// Main purpose is to eliminate need for frequent error handling on selection of a client. +type MultiClient struct { + getClient func() (ReaderWriter, error) } -func NewMultiNodeWrappedClient(multiNode *mn.MultiNode[mn.StringID, *MultiNodeClient]) *MultiNodeWrappedClient { - return &MultiNodeWrappedClient{multiNode} -} - -func (m *MultiNodeWrappedClient) Start(ctx context.Context) error { - return m.multiNode.Start(ctx) +func NewMultiNodeWrappedClient(getClient func() (ReaderWriter, error)) *MultiClient { + return &MultiClient{ + getClient: getClient, + } } -func (m *MultiNodeWrappedClient) GetLatestBlockHeight(ctx context.Context) (uint64, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetLatestBlockHeight(ctx context.Context) (uint64, error) { + r, err := m.getClient() if err != nil { return 0, err } @@ -33,8 +32,8 @@ func (m *MultiNodeWrappedClient) GetLatestBlockHeight(ctx context.Context) (uint return r.GetLatestBlockHeight(ctx) } -func (m *MultiNodeWrappedClient) SendTx(ctx context.Context, tx *solana.Transaction) (solana.Signature, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) SendTx(ctx context.Context, tx *solana.Transaction) (solana.Signature, error) { + r, err := m.getClient() if err != nil { return solana.Signature{}, err } @@ -42,8 +41,8 @@ func (m *MultiNodeWrappedClient) SendTx(ctx context.Context, tx *solana.Transact return r.SendTx(ctx, tx) } -func (m *MultiNodeWrappedClient) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -51,8 +50,8 @@ func (m *MultiNodeWrappedClient) SimulateTx(ctx context.Context, tx *solana.Tran return r.SimulateTx(ctx, tx, opts) } -func (m *MultiNodeWrappedClient) SignatureStatuses(ctx context.Context, sigs []solana.Signature) ([]*rpc.SignatureStatusesResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) SignatureStatuses(ctx context.Context, sigs []solana.Signature) ([]*rpc.SignatureStatusesResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -60,8 +59,8 @@ func (m *MultiNodeWrappedClient) SignatureStatuses(ctx context.Context, sigs []s return r.SignatureStatuses(ctx, sigs) } -func (m *MultiNodeWrappedClient) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -69,8 +68,8 @@ func (m *MultiNodeWrappedClient) GetAccountInfoWithOpts(ctx context.Context, add return r.GetAccountInfoWithOpts(ctx, addr, opts) } -func (m *MultiNodeWrappedClient) Balance(ctx context.Context, addr solana.PublicKey) (uint64, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) Balance(ctx context.Context, addr solana.PublicKey) (uint64, error) { + r, err := m.getClient() if err != nil { return 0, err } @@ -78,8 +77,8 @@ func (m *MultiNodeWrappedClient) Balance(ctx context.Context, addr solana.Public return r.Balance(ctx, addr) } -func (m *MultiNodeWrappedClient) SlotHeight(ctx context.Context) (uint64, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) SlotHeight(ctx context.Context) (uint64, error) { + r, err := m.getClient() if err != nil { return 0, err } @@ -87,8 +86,8 @@ func (m *MultiNodeWrappedClient) SlotHeight(ctx context.Context) (uint64, error) return r.SlotHeight(ctx) } -func (m *MultiNodeWrappedClient) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -96,8 +95,8 @@ func (m *MultiNodeWrappedClient) LatestBlockhash(ctx context.Context) (*rpc.GetL return r.LatestBlockhash(ctx) } -func (m *MultiNodeWrappedClient) ChainID(ctx context.Context) (mn.StringID, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) ChainID(ctx context.Context) (mn.StringID, error) { + r, err := m.getClient() if err != nil { return "", err } @@ -105,8 +104,8 @@ func (m *MultiNodeWrappedClient) ChainID(ctx context.Context) (mn.StringID, erro return r.ChainID(ctx) } -func (m *MultiNodeWrappedClient) GetFeeForMessage(ctx context.Context, msg string) (uint64, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetFeeForMessage(ctx context.Context, msg string) (uint64, error) { + r, err := m.getClient() if err != nil { return 0, err } @@ -114,8 +113,8 @@ func (m *MultiNodeWrappedClient) GetFeeForMessage(ctx context.Context, msg strin return r.GetFeeForMessage(ctx, msg) } -func (m *MultiNodeWrappedClient) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -123,8 +122,8 @@ func (m *MultiNodeWrappedClient) GetLatestBlock(ctx context.Context) (*rpc.GetBl return r.GetLatestBlock(ctx) } -func (m *MultiNodeWrappedClient) GetTransaction(ctx context.Context, txHash solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetTransaction(ctx context.Context, txHash solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -132,8 +131,8 @@ func (m *MultiNodeWrappedClient) GetTransaction(ctx context.Context, txHash sola return r.GetTransaction(ctx, txHash, opts) } -func (m *MultiNodeWrappedClient) GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64) (rpc.BlocksResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64) (rpc.BlocksResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -141,8 +140,8 @@ func (m *MultiNodeWrappedClient) GetBlocks(ctx context.Context, startSlot uint64 return r.GetBlocks(ctx, startSlot, endSlot) } -func (m *MultiNodeWrappedClient) GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -150,8 +149,8 @@ func (m *MultiNodeWrappedClient) GetBlocksWithLimit(ctx context.Context, startSl return r.GetBlocksWithLimit(ctx, startSlot, limit) } -func (m *MultiNodeWrappedClient) GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error) { + r, err := m.getClient() if err != nil { return nil, err } @@ -159,15 +158,11 @@ func (m *MultiNodeWrappedClient) GetBlock(ctx context.Context, slot uint64) (*rp return r.GetBlock(ctx, slot) } -func (m *MultiNodeWrappedClient) GetSignaturesForAddressWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { - r, err := m.multiNode.SelectRPC() +func (m *MultiClient) GetSignaturesForAddressWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) { + r, err := m.getClient() if err != nil { return nil, err } return r.GetSignaturesForAddressWithOpts(ctx, addr, opts) } - -func (m *MultiNodeWrappedClient) Close() error { - return m.multiNode.Close() -}