From db0c09ba9667865935818105909412771d4496bb Mon Sep 17 00:00:00 2001 From: Awbrey Hughlett Date: Fri, 1 Mar 2024 15:04:12 -0500 Subject: [PATCH] Skeleton Implementation of Solana Chain Reader Service (#610) * Skeleton Implementation of Solana Chain Reader Service This commit adds a new package that contains a limited chain reader for solana that implements the basic interfaces of ServiceCtx and ChainReader. All functions required for ServiceCtx are complete and included in a test. All functions required for ChainReader return an 'unimplemented' error. * fix duplicate imports --- go.mod | 1 + pkg/solana/chain_reader.go | 74 +++++++++++++++++++++++++++++++++ pkg/solana/chain_reader_test.go | 37 +++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 pkg/solana/chain_reader.go create mode 100644 pkg/solana/chain_reader_test.go diff --git a/go.mod b/go.mod index 51d17145a..92e546feb 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/smartcontractkit/chainlink-common v0.1.7-0.20240213113935-001c2f4befd4 github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/stretchr/testify v1.8.4 + github.com/test-go/testify v1.1.4 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa diff --git a/pkg/solana/chain_reader.go b/pkg/solana/chain_reader.go new file mode 100644 index 000000000..6642cf62a --- /dev/null +++ b/pkg/solana/chain_reader.go @@ -0,0 +1,74 @@ +package solana + +import ( + "context" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +const ServiceName = "SolanaChainReader" + +type SolanaChainReaderService struct { + lggr logger.Logger + services.StateMachine +} + +var ( + _ services.Service = &SolanaChainReaderService{} + _ types.ChainReader = &SolanaChainReaderService{} +) + +// NewChainReaderService is a constructor for a new ChainReaderService for Solana. Returns a nil service on error. +func NewChainReaderService(lggr logger.Logger) (*SolanaChainReaderService, error) { + return &SolanaChainReaderService{ + lggr: logger.Named(lggr, ServiceName), + }, nil +} + +// Name implements the services.ServiceCtx interface and returns the logger service name. +func (s *SolanaChainReaderService) Name() string { + return s.lggr.Name() +} + +// Start implements the services.ServiceCtx interface and starts necessary background services. +// An error is returned if starting any internal services fails. Subsequent calls to Start return +// and error. +func (s *SolanaChainReaderService) Start(_ context.Context) error { + return s.StartOnce(ServiceName, func() error { + return nil + }) +} + +// Close implements the services.ServiceCtx interface and stops all background services and cleans +// up used resources. Subsequent calls to Close return an error. +func (s *SolanaChainReaderService) Close() error { + return s.StopOnce(ServiceName, func() error { + return nil + }) +} + +// Ready implements the services.ServiceCtx interface and returns an error if starting the service +// encountered any errors or if the service is not ready to serve requests. +func (s *SolanaChainReaderService) Ready() error { + return s.StateMachine.Ready() +} + +// HealthReport implements the services.ServiceCtx interface and returns errors for any internal +// function or service that may have failed. +func (s *SolanaChainReaderService) HealthReport() map[string]error { + return map[string]error{s.Name(): s.Healthy()} +} + +// GetLatestValue implements the types.ChainReader interface and requests and parses on-chain +// data named by the provided contract, method, and params. +func (s *SolanaChainReaderService) GetLatestValue(_ context.Context, contractName, method string, params any, returnVal any) error { + return types.UnimplementedError("GetLatestValue not available") +} + +// Bind implements the types.ChainReader interface and allows new contract bindings to be added +// to the service. +func (s *SolanaChainReaderService) Bind(_ context.Context, bindings []types.BoundContract) error { + return types.UnimplementedError("Bind not available") +} diff --git a/pkg/solana/chain_reader_test.go b/pkg/solana/chain_reader_test.go new file mode 100644 index 000000000..9db536a6c --- /dev/null +++ b/pkg/solana/chain_reader_test.go @@ -0,0 +1,37 @@ +package solana_test + +import ( + "testing" + + "github.com/test-go/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink-solana/pkg/solana" +) + +func TestSolanaChainReaderService_ServiceCtx(t *testing.T) { + t.Parallel() + + ctx := tests.Context(t) + svc, err := solana.NewChainReaderService(logger.Test(t)) + + require.NoError(t, err) + require.NotNil(t, svc) + + require.Error(t, svc.Ready()) + require.Len(t, svc.HealthReport(), 1) + require.Contains(t, svc.HealthReport(), solana.ServiceName) + require.Error(t, svc.HealthReport()[solana.ServiceName]) + + require.NoError(t, svc.Start(ctx)) + require.NoError(t, svc.Ready()) + require.Equal(t, map[string]error{solana.ServiceName: nil}, svc.HealthReport()) + + require.Error(t, svc.Start(ctx)) + + require.NoError(t, svc.Close()) + require.Error(t, svc.Ready()) + require.Error(t, svc.Close()) +}