From c4557c1e66424c45b54f817cf8ac298e5c4ea404 Mon Sep 17 00:00:00 2001 From: Danny Skubak <8206446+skubakdj@users.noreply.github.com> Date: Wed, 13 Sep 2023 22:02:08 -0400 Subject: [PATCH] Remove Explorer (#10581) * Remove the Explorer client * Remove Explorer config * Update mocks * Update changelog * Remove additional `ExplorerURL` references * Generate docs * Specify removed config in changelog * Make error numbers sequential * Update CHANGELOG.md Co-authored-by: Patrick * Update docs/CHANGELOG.md * Update docs/CHANGELOG.md Co-authored-by: Jordan Krage --------- Co-authored-by: Patrick Co-authored-by: Jordan Krage --- .../evm/config/mocks/chain_scoped_config.go | 16 - core/cmd/app_test.go | 13 - core/config/app_config.go | 1 - core/config/docs/core.toml | 2 - core/config/docs/secrets.toml | 10 - core/config/env/env.go | 2 - core/config/explorer_config.go | 9 - core/config/toml/types.go | 38 -- core/services/chainlink/application.go | 17 +- core/services/chainlink/config.go | 30 +- core/services/chainlink/config_explorer.go | 35 -- .../chainlink/config_explorer_test.go | 20 - core/services/chainlink/config_general.go | 12 - .../chainlink/config_general_secrets.go | 14 - .../services/chainlink/config_general_test.go | 8 - core/services/chainlink/config_test.go | 8 +- core/services/chainlink/legacy.env | 3 - .../chainlink/mocks/general_config.go | 16 - .../testdata/config-empty-effective.toml | 1 - .../chainlink/testdata/config-full.toml | 1 - .../config-multi-chain-effective.toml | 1 - .../mergingsecretsdata/secrets-explorer.toml | 3 - .../testdata/secrets-full-redacted.toml | 4 - .../chainlink/testdata/secrets-full.toml | 4 - .../testdata/secrets-multi-redacted.toml | 4 - .../chainlink/testdata/secrets-multi.toml | 4 - .../synchronization/explorer_client.go | 410 ------------------ .../synchronization/explorer_client_test.go | 213 --------- .../synchronization/mocks/explorer_client.go | 178 -------- core/services/telemetry/explorer.go | 31 -- core/services/telemetry/explorer_test.go | 31 -- core/services/telemetry/noop.go | 2 +- .../testdata/config-empty-effective.toml | 1 - core/web/resolver/testdata/config-full.toml | 1 - .../config-multi-chain-effective.toml | 1 - docs/CHANGELOG.md | 10 + docs/CONFIG.md | 7 - docs/SECRETS.md | 24 - testdata/scripts/node/validate/default.txtar | 1 - .../disk-based-logging-disabled.txtar | 1 - .../validate/disk-based-logging-no-dir.txtar | 1 - .../node/validate/disk-based-logging.txtar | 1 - testdata/scripts/node/validate/invalid.txtar | 1 - testdata/scripts/node/validate/valid.txtar | 1 - tools/docker/config.toml | 2 - 45 files changed, 25 insertions(+), 1168 deletions(-) delete mode 100644 core/config/explorer_config.go delete mode 100644 core/services/chainlink/config_explorer.go delete mode 100644 core/services/chainlink/config_explorer_test.go delete mode 100644 core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml delete mode 100644 core/services/synchronization/explorer_client.go delete mode 100644 core/services/synchronization/explorer_client_test.go delete mode 100644 core/services/synchronization/mocks/explorer_client.go delete mode 100644 core/services/telemetry/explorer.go delete mode 100644 core/services/telemetry/explorer_test.go diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index bf84164cd3e..f1e09cc54ab 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -160,22 +160,6 @@ func (_m *ChainScopedConfig) EVMRPCEnabled() bool { return r0 } -// Explorer provides a mock function with given fields: -func (_m *ChainScopedConfig) Explorer() coreconfig.Explorer { - ret := _m.Called() - - var r0 coreconfig.Explorer - if rf, ok := ret.Get(0).(func() coreconfig.Explorer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(coreconfig.Explorer) - } - } - - return r0 -} - // Feature provides a mock function with given fields: func (_m *ChainScopedConfig) Feature() coreconfig.Feature { ret := _m.Called() diff --git a/core/cmd/app_test.go b/core/cmd/app_test.go index d99f941fded..78331bf7063 100644 --- a/core/cmd/app_test.go +++ b/core/cmd/app_test.go @@ -145,7 +145,6 @@ func Test_initServerConfig(t *testing.T) { fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, secretsFiles: []string{ "../services/chainlink/testdata/mergingsecretsdata/secrets-database.toml", - "../services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-password.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-pyroscope.toml", "../services/chainlink/testdata/mergingsecretsdata/secrets-prometheus.toml", @@ -168,18 +167,6 @@ func Test_initServerConfig(t *testing.T) { }, wantErr: true, }, - { - name: "reading multiple secrets with overrides: Explorer", - args: args{ - opts: new(chainlink.GeneralConfigOpts), - fileNames: []string{testtomlutils.WriteTOMLFile(t, testConfigFileContents, "test.toml")}, - secretsFiles: []string{ - "../testdata/mergingsecretsdata/secrets-explorer.toml", - "../testdata/mergingsecretsdata/secrets-explorer.toml", - }, - }, - wantErr: true, - }, { name: "reading multiple secrets with overrides: Password", args: args{ diff --git a/core/config/app_config.go b/core/config/app_config.go index 82652d3c8ce..1e60644dd0c 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -38,7 +38,6 @@ type AppConfig interface { AuditLogger() AuditLogger AutoPprof() AutoPprof Database() Database - Explorer() Explorer Feature() Feature FluxMonitor() FluxMonitor Insecure() Insecure diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 7253cbd1aad..b9c1063c12a 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -1,5 +1,3 @@ -# ExplorerURL is the websocket URL used by the node to push stats. This variable is required to deliver telemetry. -ExplorerURL = 'ws://explorer.url' # Example # **ADVANCED** # InsecureFastScrypt causes all key stores to encrypt using "fast" scrypt params instead. This is insecure and only useful for local testing. DO NOT ENABLE THIS IN PRODUCTION. InsecureFastScrypt = false # Default diff --git a/core/config/docs/secrets.toml b/core/config/docs/secrets.toml index 5ac02e5f55a..2b491a77497 100644 --- a/core/config/docs/secrets.toml +++ b/core/config/docs/secrets.toml @@ -14,16 +14,6 @@ BackupURL = "postgresql://user:pass@read-replica.example.com:5432/dbname?sslmode # Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` AllowSimplePasswords = false # Default -[Explorer] -# AccessKey is the access key for authenticating with the Explorer. -# -# Environment variable: `CL_EXPLORER_ACCESS_KEY` -AccessKey = "access_key" # Example -# Secret is the secret for authenticating with the Explorer. -# -# Environment variable: `CL_EXPLORER_SECRET` -Secret = "secret" # Example - [Password] # Keystore is the password for the node's account. # diff --git a/core/config/env/env.go b/core/config/env/env.go index 160aae65f6d..7813df4a8cc 100644 --- a/core/config/env/env.go +++ b/core/config/env/env.go @@ -31,8 +31,6 @@ var ( DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") DatabaseURL = Secret("CL_DATABASE_URL") DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") - ExplorerAccessKey = Secret("CL_EXPLORER_ACCESS_KEY") - ExplorerSecret = Secret("CL_EXPLORER_SECRET") PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") PasswordVRF = Secret("CL_PASSWORD_VRF") PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") diff --git a/core/config/explorer_config.go b/core/config/explorer_config.go deleted file mode 100644 index dcb201d616d..00000000000 --- a/core/config/explorer_config.go +++ /dev/null @@ -1,9 +0,0 @@ -package config - -import "net/url" - -type Explorer interface { - AccessKey() string - Secret() string - URL() *url.URL -} diff --git a/core/config/toml/types.go b/core/config/toml/types.go index b5535781a42..5fba0c7ea5e 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -32,7 +32,6 @@ var ErrUnsupported = errors.New("unsupported with config v2") type Core struct { // General/misc AppID uuid.UUID `toml:"-"` // random or test - ExplorerURL *models.URL InsecureFastScrypt *bool RootDir *string ShutdownGracePeriod *models.Duration @@ -57,9 +56,6 @@ type Core struct { // SetFrom updates c with any non-nil values from f. (currently TOML field only!) func (c *Core) SetFrom(f *Core) { - if v := f.ExplorerURL; v != nil { - c.ExplorerURL = v - } if v := f.InsecureFastScrypt; v != nil { c.InsecureFastScrypt = v } @@ -102,7 +98,6 @@ func (c *Core) ValidateConfig() (err error) { type Secrets struct { Database DatabaseSecrets `toml:",omitempty"` - Explorer ExplorerSecrets `toml:",omitempty"` Password Passwords `toml:",omitempty"` Pyroscope PyroscopeSecrets `toml:",omitempty"` Prometheus PrometheusSecrets `toml:",omitempty"` @@ -197,39 +192,6 @@ func (d *DatabaseSecrets) validateMerge(f *DatabaseSecrets) (err error) { return err } -type ExplorerSecrets struct { - AccessKey *models.Secret - Secret *models.Secret -} - -func (e *ExplorerSecrets) SetFrom(f *ExplorerSecrets) (err error) { - err = e.validateMerge(f) - if err != nil { - return err - } - - if v := f.AccessKey; v != nil { - e.AccessKey = v - } - if v := f.Secret; v != nil { - e.Secret = v - } - - return nil -} - -func (e *ExplorerSecrets) validateMerge(f *ExplorerSecrets) (err error) { - if e.AccessKey != nil && f.AccessKey != nil { - err = multierr.Append(err, configutils.ErrOverride{Name: "AccessKey"}) - } - - if e.Secret != nil && f.Secret != nil { - err = multierr.Append(err, configutils.ErrOverride{Name: "Secret"}) - } - - return err -} - type Passwords struct { Keystore *models.Secret VRF *models.Secret diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index b2e8719e607..498d355d7f7 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -125,7 +125,6 @@ type ChainlinkApplication struct { ExternalInitiatorManager webhook.ExternalInitiatorManager SessionReaper utils.SleeperTask shutdownOnce sync.Once - explorerClient synchronization.ExplorerClient srvcs []services.ServiceCtx HealthChecker services.Checker Nurse *services.Nurse @@ -222,21 +221,10 @@ func NewApplication(opts ApplicationOpts) (Application, error) { telemetryIngressClient := synchronization.TelemetryIngressClient(&synchronization.NoopTelemetryIngressClient{}) telemetryIngressBatchClient := synchronization.TelemetryIngressBatchClient(&synchronization.NoopTelemetryIngressBatchClient{}) - explorerClient := synchronization.ExplorerClient(&synchronization.NoopExplorerClient{}) monitoringEndpointGen := telemetry.MonitoringEndpointGenerator(&telemetry.NoopAgent{}) - if cfg.Explorer().URL() != nil && cfg.TelemetryIngress().URL() != nil { - globalLogger.Warn("Both ExplorerUrl and TelemetryIngress.Url are set, defaulting to Explorer") - } - - if cfg.Explorer().URL() != nil { - explorerClient = synchronization.NewExplorerClient(cfg.Explorer().URL(), cfg.Explorer().AccessKey(), cfg.Explorer().Secret(), globalLogger) - monitoringEndpointGen = telemetry.NewExplorerAgent(explorerClient) - } - ticfg := cfg.TelemetryIngress() - // Use Explorer over TelemetryIngress if both URLs are set - if cfg.Explorer().URL() == nil && ticfg.URL() != nil { + if ticfg.URL() != nil { if ticfg.UseBatchSend() { telemetryIngressBatchClient = synchronization.NewTelemetryIngressBatchClient(ticfg.URL(), ticfg.ServerPubKey(), keyStore.CSA(), ticfg.Logging(), globalLogger, ticfg.BufferSize(), ticfg.MaxBatchSize(), ticfg.SendInterval(), ticfg.SendTimeout(), ticfg.UniConn()) @@ -248,7 +236,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { monitoringEndpointGen = telemetry.NewIngressAgentWrapper(telemetryIngressClient) } } - srvcs = append(srvcs, explorerClient, telemetryIngressClient, telemetryIngressBatchClient) + srvcs = append(srvcs, telemetryIngressClient, telemetryIngressBatchClient) backupCfg := cfg.Database().Backup() if backupCfg.Mode() != config.DatabaseBackupModeNone && backupCfg.Frequency() > 0 { @@ -471,7 +459,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { KeyStore: keyStore, SessionReaper: sessions.NewSessionReaper(db.DB, cfg.WebServer(), globalLogger), ExternalInitiatorManager: externalInitiatorManager, - explorerClient: explorerClient, HealthChecker: healthChecker, Nurse: nurse, logger: globalLogger, diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 73bfeb3d973..5578f8c0453 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -129,28 +129,24 @@ func (s *Secrets) SetFrom(f *Secrets) (err error) { err = multierr.Append(err, config.NamedMultiErrorList(err1, "Database")) } - if err2 := s.Explorer.SetFrom(&f.Explorer); err2 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err2, "Explorer")) + if err2 := s.Password.SetFrom(&f.Password); err2 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err2, "Password")) } - if err3 := s.Password.SetFrom(&f.Password); err3 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err3, "Password")) + if err3 := s.Pyroscope.SetFrom(&f.Pyroscope); err3 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err3, "Pyroscope")) } - if err4 := s.Pyroscope.SetFrom(&f.Pyroscope); err4 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err4, "Pyroscope")) + if err4 := s.Prometheus.SetFrom(&f.Prometheus); err4 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err4, "Prometheus")) } - if err5 := s.Prometheus.SetFrom(&f.Prometheus); err5 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err5, "Prometheus")) + if err5 := s.Mercury.SetFrom(&f.Mercury); err5 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err5, "Mercury")) } - if err6 := s.Mercury.SetFrom(&f.Mercury); err6 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err6, "Mercury")) - } - - if err7 := s.Threshold.SetFrom(&f.Threshold); err7 != nil { - err = multierr.Append(err, config.NamedMultiErrorList(err7, "Threshold")) + if err6 := s.Threshold.SetFrom(&f.Threshold); err6 != nil { + err = multierr.Append(err, config.NamedMultiErrorList(err6, "Threshold")) } _, err = utils.MultiErrorList(err) @@ -223,12 +219,6 @@ func (s *Secrets) setEnv() error { s.Database.AllowSimplePasswords = new(bool) *s.Database.AllowSimplePasswords = true } - if explorerKey := env.ExplorerAccessKey.Get(); explorerKey != "" { - s.Explorer.AccessKey = &explorerKey - } - if explorerSecret := env.ExplorerSecret.Get(); explorerSecret != "" { - s.Explorer.Secret = &explorerSecret - } if keystorePassword := env.PasswordKeystore.Get(); keystorePassword != "" { s.Password.Keystore = &keystorePassword } diff --git a/core/services/chainlink/config_explorer.go b/core/services/chainlink/config_explorer.go deleted file mode 100644 index ce6001de195..00000000000 --- a/core/services/chainlink/config_explorer.go +++ /dev/null @@ -1,35 +0,0 @@ -package chainlink - -import ( - "net/url" - - "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -type explorerConfig struct { - explorerURL *models.URL - s toml.ExplorerSecrets -} - -func (e *explorerConfig) URL() *url.URL { - u := (*url.URL)(e.explorerURL) - if *u == zeroURL { - u = nil - } - return u -} - -func (e *explorerConfig) AccessKey() string { - if e.s.AccessKey == nil { - return "" - } - return string(*e.s.AccessKey) -} - -func (e *explorerConfig) Secret() string { - if e.s.Secret == nil { - return "" - } - return string(*e.s.Secret) -} diff --git a/core/services/chainlink/config_explorer_test.go b/core/services/chainlink/config_explorer_test.go deleted file mode 100644 index d68f671690b..00000000000 --- a/core/services/chainlink/config_explorer_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package chainlink - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestExplorerConfig(t *testing.T) { - opts := GeneralConfigOpts{ - ConfigStrings: []string{fullTOML}, - } - cfg, err := opts.New() - require.NoError(t, err) - - e := cfg.Explorer() - assert.Equal(t, "http://explorer.url", e.URL().String()) - -} diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index c25539684de..057b7e554e7 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -409,18 +409,6 @@ func (g *generalConfig) ShutdownGracePeriod() time.Duration { return g.c.ShutdownGracePeriod.Duration() } -func (g *generalConfig) Explorer() config.Explorer { - return &explorerConfig{s: g.secrets.Explorer, explorerURL: g.c.ExplorerURL} -} - -func (g *generalConfig) ExplorerURL() *url.URL { - u := (*url.URL)(g.c.ExplorerURL) - if *u == zeroURL { - u = nil - } - return u -} - func (g *generalConfig) FluxMonitor() config.FluxMonitor { return &fluxMonitorConfig{c: g.c.FluxMonitor} } diff --git a/core/services/chainlink/config_general_secrets.go b/core/services/chainlink/config_general_secrets.go index 6138eab58a3..25dc62d4d01 100644 --- a/core/services/chainlink/config_general_secrets.go +++ b/core/services/chainlink/config_general_secrets.go @@ -14,17 +14,3 @@ func (g *generalConfig) DatabaseURL() url.URL { func (g *generalConfig) DatabaseBackupURL() *url.URL { return g.secrets.Database.BackupURL.URL() } - -func (g *generalConfig) ExplorerAccessKey() string { - if g.secrets.Explorer.AccessKey == nil { - return "" - } - return string(*g.secrets.Explorer.AccessKey) -} - -func (g *generalConfig) ExplorerSecret() string { - if g.secrets.Explorer.Secret == nil { - return "" - } - return string(*g.secrets.Explorer.Secret) -} diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index c640e54beb0..8a0f58ecd48 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -133,9 +133,6 @@ func TestConfig_LogSQL(t *testing.T) { //go:embed testdata/mergingsecretsdata/secrets-database.toml var databaseSecretsTOML string -//go:embed testdata/mergingsecretsdata/secrets-explorer.toml -var explorerSecretsTOML string - //go:embed testdata/mergingsecretsdata/secrets-password.toml var passwordSecretsTOML string @@ -158,8 +155,6 @@ func TestConfig_SecretsMerging(t *testing.T) { t.Run("verify secrets merging in GeneralConfigOpts.New()", func(t *testing.T) { databaseSecrets, err := parseSecrets(databaseSecretsTOML) require.NoErrorf(t, err, "error: %s", err) - explorerSecrets, err1 := parseSecrets(explorerSecretsTOML) - require.NoErrorf(t, err1, "error: %s", err1) passwordSecrets, err2 := parseSecrets(passwordSecretsTOML) require.NoErrorf(t, err2, "error: %s", err2) pyroscopeSecrets, err3 := parseSecrets(pyroscopeSecretsTOML) @@ -179,7 +174,6 @@ func TestConfig_SecretsMerging(t *testing.T) { } secretsFiles := []string{ "testdata/mergingsecretsdata/secrets-database.toml", - "testdata/mergingsecretsdata/secrets-explorer.toml", "testdata/mergingsecretsdata/secrets-password.toml", "testdata/mergingsecretsdata/secrets-pyroscope.toml", "testdata/mergingsecretsdata/secrets-prometheus.toml", @@ -196,8 +190,6 @@ func TestConfig_SecretsMerging(t *testing.T) { assert.Equal(t, databaseSecrets.Database.URL.URL().String(), opts.Secrets.Database.URL.URL().String()) assert.Equal(t, databaseSecrets.Database.BackupURL.URL().String(), opts.Secrets.Database.BackupURL.URL().String()) - assert.Equal(t, (string)(*explorerSecrets.Explorer.AccessKey), (string)(*opts.Secrets.Explorer.AccessKey)) - assert.Equal(t, (string)(*explorerSecrets.Explorer.Secret), (string)(*opts.Secrets.Explorer.Secret)) assert.Equal(t, (string)(*passwordSecrets.Password.Keystore), (string)(*opts.Secrets.Password.Keystore)) assert.Equal(t, (string)(*passwordSecrets.Password.VRF), (string)(*opts.Secrets.Password.VRF)) assert.Equal(t, (string)(*pyroscopeSecrets.Pyroscope.AuthToken), (string)(*opts.Secrets.Pyroscope.AuthToken)) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 61ba9594e04..480d06b5806 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -213,7 +213,6 @@ func TestConfig_Marshal(t *testing.T) { global := Config{ Core: toml.Core{ - ExplorerURL: mustURL("http://explorer.url"), InsecureFastScrypt: ptr(true), RootDir: ptr("test/root/dir"), ShutdownGracePeriod: models.MustNewDuration(10 * time.Second), @@ -635,8 +634,7 @@ func TestConfig_Marshal(t *testing.T) { exp string }{ {"empty", Config{}, ``}, - {"global", global, `ExplorerURL = 'http://explorer.url' -InsecureFastScrypt = true + {"global", global, `InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' @@ -1303,9 +1301,7 @@ func TestSecrets_Validate(t *testing.T) { }{ {name: "partial", toml: ` -Database.AllowSimplePasswords = true -Explorer.AccessKey = "access_key" -Explorer.Secret = "secret"`, +Database.AllowSimplePasswords = true`, exp: `invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty`}, diff --git a/core/services/chainlink/legacy.env b/core/services/chainlink/legacy.env index 142b4e3b872..01469736e0f 100644 --- a/core/services/chainlink/legacy.env +++ b/core/services/chainlink/legacy.env @@ -7,9 +7,6 @@ AUDIT_LOGGER_JSON_WRAPPER_KEY= CHAIN_TYPE= CHAINLINK_DEV= -EXPLORER_ACCESS_KEY= -EXPLORER_SECRET= -EXPLORER_URL= FLAGS_CONTRACT_ADDRESS= INSECURE_FAST_SCRYPT= REAPER_EXPIRATION= diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 289c23b26b2..d91901fce6f 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -207,22 +207,6 @@ func (_m *GeneralConfig) EVMRPCEnabled() bool { return r0 } -// Explorer provides a mock function with given fields: -func (_m *GeneralConfig) Explorer() config.Explorer { - ret := _m.Called() - - var r0 config.Explorer - if rf, ok := ret.Get(0).(func() config.Explorer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(config.Explorer) - } - } - - return r0 -} - // Feature provides a mock function with given fields: func (_m *GeneralConfig) Feature() config.Feature { ret := _m.Called() diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 8c3eef53f6a..45e92a147d3 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index f10d12f35ee..92d0b553d6e 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -1,4 +1,3 @@ -ExplorerURL = 'http://explorer.url' InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 876591c65e2..665de9be8cb 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = 'my/root/dir' ShutdownGracePeriod = '5s' diff --git a/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml b/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml deleted file mode 100644 index 6f0682240a8..00000000000 --- a/core/services/chainlink/testdata/mergingsecretsdata/secrets-explorer.toml +++ /dev/null @@ -1,3 +0,0 @@ -[Explorer] -AccessKey = "EXPLORER_ACCESS_KEY" -Secret = "EXPLORER_TOKEN" \ No newline at end of file diff --git a/core/services/chainlink/testdata/secrets-full-redacted.toml b/core/services/chainlink/testdata/secrets-full-redacted.toml index d2bf45e0bc2..740c3250edb 100644 --- a/core/services/chainlink/testdata/secrets-full-redacted.toml +++ b/core/services/chainlink/testdata/secrets-full-redacted.toml @@ -3,10 +3,6 @@ URL = 'xxxxx' BackupURL = 'xxxxx' AllowSimplePasswords = false -[Explorer] -AccessKey = 'xxxxx' -Secret = 'xxxxx' - [Password] Keystore = 'xxxxx' VRF = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-full.toml b/core/services/chainlink/testdata/secrets-full.toml index 7dd8b38a834..37e5dafc7d7 100644 --- a/core/services/chainlink/testdata/secrets-full.toml +++ b/core/services/chainlink/testdata/secrets-full.toml @@ -2,10 +2,6 @@ URL = "postgresql://user:pass@localhost:5432/dbname?sslmode=disable" BackupURL = "postgresql://user:pass@localhost:5432/backupdbname?sslmode=disable" -[Explorer] -AccessKey = "access_key" -Secret = "secret" - [Password] Keystore = "keystore_pass" VRF = "VRF_pass" diff --git a/core/services/chainlink/testdata/secrets-multi-redacted.toml b/core/services/chainlink/testdata/secrets-multi-redacted.toml index 32e4b6fca34..27a1eb9fb6c 100644 --- a/core/services/chainlink/testdata/secrets-multi-redacted.toml +++ b/core/services/chainlink/testdata/secrets-multi-redacted.toml @@ -2,9 +2,5 @@ URL = 'xxxxx' AllowSimplePasswords = false -[Explorer] -AccessKey = 'xxxxx' -Secret = 'xxxxx' - [Password] Keystore = 'xxxxx' diff --git a/core/services/chainlink/testdata/secrets-multi.toml b/core/services/chainlink/testdata/secrets-multi.toml index f497d20f307..23438f9e4ab 100644 --- a/core/services/chainlink/testdata/secrets-multi.toml +++ b/core/services/chainlink/testdata/secrets-multi.toml @@ -1,9 +1,5 @@ [Database] URL = "postgresql://user:pass@localhost:5432/dbname?sslmode=disable" -[Explorer] -AccessKey = "access_key" -Secret = "secret" - [Password] Keystore = "keystore_pass" diff --git a/core/services/synchronization/explorer_client.go b/core/services/synchronization/explorer_client.go deleted file mode 100644 index 4bdcc30b134..00000000000 --- a/core/services/synchronization/explorer_client.go +++ /dev/null @@ -1,410 +0,0 @@ -package synchronization - -import ( - "context" - "errors" - "fmt" - "net/http" - "net/url" - "sync" - "sync/atomic" - "time" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/gorilla/websocket" -) - -var ( - // ErrReceiveTimeout is returned when no message is received after a - // specified duration in Receive - ErrReceiveTimeout = errors.New("timeout waiting for message") -) - -type ConnectionStatus string - -const ( - // ConnectionStatusDisconnected is the default state - ConnectionStatusDisconnected = ConnectionStatus("disconnected") - // ConnectionStatusConnected is used when the client is successfully connected - ConnectionStatusConnected = ConnectionStatus("connected") - // ConnectionStatusError is used when there is an error - ConnectionStatusError = ConnectionStatus("error") -) - -// SendBufferSize is the number of messages to keep in the buffer before dropping additional ones -const SendBufferSize = 100 - -const ( - ExplorerTextMessage = websocket.TextMessage - ExplorerBinaryMessage = websocket.BinaryMessage -) - -//go:generate mockery --quiet --name ExplorerClient --output ./mocks --case=underscore - -// ExplorerClient encapsulates all the functionality needed to -// push run information to explorer. -type ExplorerClient interface { - services.ServiceCtx - Url() url.URL - Status() ConnectionStatus - Send(context.Context, []byte, ...int) - Receive(context.Context, ...time.Duration) ([]byte, error) -} - -type NoopExplorerClient struct{} - -func (NoopExplorerClient) HealthReport() map[string]error { return map[string]error{} } -func (NoopExplorerClient) Name() string { return "NoopExplorerClient" } - -// Url always returns underlying url. -func (NoopExplorerClient) Url() url.URL { return url.URL{} } - -// Status always returns ConnectionStatusDisconnected. -func (NoopExplorerClient) Status() ConnectionStatus { return ConnectionStatusDisconnected } - -// Start is a no-op -func (NoopExplorerClient) Start(context.Context) error { return nil } - -// Close is a no-op -func (NoopExplorerClient) Close() error { return nil } - -// Ready is a no-op -func (NoopExplorerClient) Ready() error { return nil } - -// Send is a no-op -func (NoopExplorerClient) Send(context.Context, []byte, ...int) {} - -// Receive is a no-op -func (NoopExplorerClient) Receive(context.Context, ...time.Duration) ([]byte, error) { return nil, nil } - -type explorerClient struct { - utils.StartStopOnce - conn *websocket.Conn - sendText chan []byte - sendBinary chan []byte - dropMessageCount atomic.Uint32 - receive chan []byte - sleeper utils.Sleeper - status ConnectionStatus - url *url.URL - accessKey string - secret string - lggr logger.Logger - - chStop utils.StopChan - wg sync.WaitGroup - writePumpDone chan struct{} - - statusMtx sync.RWMutex -} - -// NewExplorerClient returns a stats pusher using a websocket for -// delivery. -func NewExplorerClient(url *url.URL, accessKey, secret string, lggr logger.Logger) ExplorerClient { - return &explorerClient{ - url: url, - receive: make(chan []byte), - sleeper: utils.NewBackoffSleeper(), - status: ConnectionStatusDisconnected, - accessKey: accessKey, - secret: secret, - lggr: lggr.Named("ExplorerClient"), - - sendText: make(chan []byte, SendBufferSize), - sendBinary: make(chan []byte, SendBufferSize), - } -} - -// Url returns the URL the client was initialized with -func (ec *explorerClient) Url() url.URL { - return *ec.url -} - -// Status returns the current connection status -func (ec *explorerClient) Status() ConnectionStatus { - ec.statusMtx.RLock() - defer ec.statusMtx.RUnlock() - return ec.status -} - -// Start starts a write pump over a websocket. -func (ec *explorerClient) Start(context.Context) error { - return ec.StartOnce("Explorer client", func() error { - ec.chStop = make(chan struct{}) - ec.wg.Add(1) - go ec.connectAndWritePump() - return nil - }) -} - -func (ec *explorerClient) Name() string { - return ec.lggr.Name() -} - -func (ec *explorerClient) HealthReport() map[string]error { - return map[string]error{ - ec.Name(): ec.StartStopOnce.Healthy(), - } -} - -// Send sends data asynchronously across the websocket if it's open, or -// holds it in a small buffer until connection, throwing away messages -// once buffer is full. -// func (ec *explorerClient) Receive(durationParams ...time.Duration) ([]byte, error) { -func (ec *explorerClient) Send(ctx context.Context, data []byte, messageTypes ...int) { - messageType := ExplorerTextMessage - if len(messageTypes) > 0 { - messageType = messageTypes[0] - } - var send chan []byte - switch messageType { - case ExplorerTextMessage: - send = ec.sendText - case ExplorerBinaryMessage: - send = ec.sendBinary - default: - err := fmt.Errorf("send on explorer client received unsupported message type %d", messageType) - ec.SvcErrBuffer.Append(err) - ec.lggr.Critical(err.Error()) - return - } - select { - case send <- data: - ec.dropMessageCount.Store(0) - case <-ctx.Done(): - return - default: - ec.logBufferFullWithExpBackoff(data) - } -} - -// logBufferFullWithExpBackoff logs messages at -// 1 -// 2 -// 4 -// 8 -// 16 -// 32 -// 64 -// 100 -// 200 -// 300 -// etc... -func (ec *explorerClient) logBufferFullWithExpBackoff(data []byte) { - count := ec.dropMessageCount.Add(1) - if count > 0 && (count%100 == 0 || count&(count-1) == 0) { - ec.lggr.Warnw("explorer client buffer full, dropping message", "data", data, "droppedCount", count) - } -} - -// Receive blocks the caller while waiting for a response from the server, -// returning the raw response bytes -func (ec *explorerClient) Receive(ctx context.Context, durationParams ...time.Duration) ([]byte, error) { - duration := defaultReceiveTimeout - if len(durationParams) > 0 { - duration = durationParams[0] - } - - select { - case data := <-ec.receive: - return data, nil - case <-time.After(duration): - return nil, ErrReceiveTimeout - case <-ctx.Done(): - return nil, nil - } -} - -const ( - // Time allowed to write a message to the peer. - writeWait = 10 * time.Second - - // Time allowed to read the next pong message from the peer. - pongWait = 60 * time.Second - - // Send pings to peer with this period. Must be less than pongWait. - pingPeriod = (pongWait * 9) / 10 - - // Maximum message size allowed from peer. - maxMessageSize = 512 - - // defaultReceiveTimeout is the default amount of time to wait for receipt of messages - defaultReceiveTimeout = 30 * time.Second -) - -// Inspired by https://github.com/gorilla/websocket/blob/master/examples/chat/client.go -// lexical confinement of done chan allows multiple connectAndWritePump routines -// to clean up independent of itself by reducing shared state. i.e. a passed done, not ec.done. -func (ec *explorerClient) connectAndWritePump() { - defer ec.wg.Done() - ctx, cancel := ec.chStop.NewCtx() - defer cancel() - for { - select { - case <-time.After(ec.sleeper.After()): - ec.lggr.Infow("Connecting to explorer", "url", ec.url) - err := ec.connect(ctx) - if ctx.Err() != nil { - return - } else if err != nil { - ec.setStatus(ConnectionStatusError) - ec.lggr.Warn("Failed to connect to explorer (", ec.url.String(), "): ", err) - break - } - - ec.setStatus(ConnectionStatusConnected) - - ec.lggr.Infow("Connected to explorer", "url", ec.url) - start := time.Now() - ec.writePumpDone = make(chan struct{}) - ec.wg.Add(1) - go ec.readPump() - ec.writePump() - if time.Since(start) > time.Second { - ec.sleeper.Reset() - } - - case <-ec.chStop: - return - } - } -} - -func (ec *explorerClient) setStatus(s ConnectionStatus) { - ec.statusMtx.Lock() - defer ec.statusMtx.Unlock() - ec.status = s -} - -// Inspired by https://github.com/gorilla/websocket/blob/master/examples/chat/client.go#L82 -func (ec *explorerClient) writePump() { - ticker := time.NewTicker(pingPeriod) - defer func() { - ticker.Stop() - ec.wrapConnErrorIf(ec.conn.Close()) // exclusive responsibility to close ws conn - }() - - for { - select { - case message, open := <-ec.sendText: - if !open { - ec.wrapConnErrorIf(ec.conn.WriteMessage(websocket.CloseMessage, []byte{})) - } - - err := ec.writeMessage(message, websocket.TextMessage) - if err != nil { - ec.lggr.Warnw("websocketStatsPusher: error writing text message", "err", err) - return - } - - case message, open := <-ec.sendBinary: - if !open { - ec.wrapConnErrorIf(ec.conn.WriteMessage(websocket.CloseMessage, []byte{})) - } - - err := ec.writeMessage(message, websocket.BinaryMessage) - if err != nil { - ec.lggr.Warnw("websocketStatsPusher: error writing binary message", "err", err) - return - } - - case <-ticker.C: - ec.wrapConnErrorIf(ec.conn.SetWriteDeadline(time.Now().Add(writeWait))) - if err := ec.conn.WriteMessage(websocket.PingMessage, nil); err != nil { - ec.wrapConnErrorIf(err) - return - } - - case <-ec.writePumpDone: - return - case <-ec.chStop: - return - } - } -} - -func (ec *explorerClient) writeMessage(message []byte, messageType int) error { - ec.wrapConnErrorIf(ec.conn.SetWriteDeadline(time.Now().Add(writeWait))) - writer, err := ec.conn.NextWriter(messageType) - if err != nil { - return err - } - - if _, err := writer.Write(message); err != nil { - return err - } - ec.lggr.Tracew("websocketStatsPusher successfully wrote message", "messageType", messageType, "message", message) - - return writer.Close() -} - -func (ec *explorerClient) connect(ctx context.Context) error { - authHeader := http.Header{} - authHeader.Add("X-Explore-Chainlink-Accesskey", ec.accessKey) - authHeader.Add("X-Explore-Chainlink-Secret", ec.secret) - authHeader.Add("X-Explore-Chainlink-Core-Version", static.Version) - authHeader.Add("X-Explore-Chainlink-Core-Sha", static.Sha) - - conn, _, err := websocket.DefaultDialer.DialContext(ctx, ec.url.String(), authHeader) - if ctx.Err() != nil { - return fmt.Errorf("websocketStatsPusher#connect context canceled: %w", ctx.Err()) - } else if err != nil { - return fmt.Errorf("websocketStatsPusher#connect: %v", err) - } - - ec.conn = conn - return nil -} - -var expectedCloseMessages = []int{websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNormalClosure} - -// readPump listens on the websocket connection for control messages and -// response messages (text) -// -// For more details on how disconnection messages are handled, see: -// - https://stackoverflow.com/a/48181794/639773 -// - https://github.com/gorilla/websocket/blob/master/examples/chat/client.go#L56 -func (ec *explorerClient) readPump() { - defer ec.wg.Done() - ec.conn.SetReadLimit(maxMessageSize) - _ = ec.conn.SetReadDeadline(time.Now().Add(pongWait)) - ec.conn.SetPongHandler(func(string) error { - _ = ec.conn.SetReadDeadline(time.Now().Add(pongWait)) - return nil - }) - - for { - messageType, message, err := ec.conn.ReadMessage() - if err != nil { - if websocket.IsUnexpectedCloseError(err, expectedCloseMessages...) { - ec.lggr.Warnw("Unexpected close error on ExplorerClient", "err", err) - } - close(ec.writePumpDone) - return - } - - switch messageType { - case websocket.TextMessage: - ec.receive <- message - } - } -} - -func (ec *explorerClient) wrapConnErrorIf(err error) { - if err != nil && websocket.IsUnexpectedCloseError(err, expectedCloseMessages...) { - ec.setStatus(ConnectionStatusError) - ec.lggr.Error(fmt.Sprintf("websocketStatsPusher: %v", err)) - } -} - -func (ec *explorerClient) Close() error { - return ec.StopOnce("Explorer client", func() error { - close(ec.chStop) - ec.wg.Wait() - return nil - }) -} diff --git a/core/services/synchronization/explorer_client_test.go b/core/services/synchronization/explorer_client_test.go deleted file mode 100644 index 727b8dd6d33..00000000000 --- a/core/services/synchronization/explorer_client_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package synchronization_test - -import ( - "net/http" - "net/http/httptest" - "net/url" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - "github.com/smartcontractkit/chainlink/v2/core/static" -) - -func TestWebSocketClient_ReconnectLoop(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - cltest.CallbackOrTimeout(t, "ws client connects", func() { - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - // reconnect after server disconnect - wsserver.WriteCloseMessage() - cltest.CallbackOrTimeout(t, "ws client reconnects", func() { - <-wsserver.Disconnected - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - require.NoError(t, explorerClient.Close()) -} - -func TestWebSocketClient_Authentication(t *testing.T) { - headerChannel := make(chan http.Header, 1) - handler := func(w http.ResponseWriter, r *http.Request) { - headerChannel <- r.Header - } - server := httptest.NewServer(http.HandlerFunc(handler)) - defer server.Close() - - url := cltest.MustParseURL(t, server.URL) - url.Scheme = "ws" - explorerClient := synchronization.NewExplorerClient(url, "accessKey", "secret", logger.TestLogger(t)) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - cltest.CallbackOrTimeout(t, "receive authentication headers", func() { - headers := <-headerChannel - assert.Equal(t, []string{"accessKey"}, headers["X-Explore-Chainlink-Accesskey"]) - assert.Equal(t, []string{"secret"}, headers["X-Explore-Chainlink-Secret"]) - assert.Equal(t, []string{static.Version}, headers["X-Explore-Chainlink-Core-Version"]) - assert.Equal(t, []string{static.Sha}, headers["X-Explore-Chainlink-Core-Sha"]) - }) -} - -func TestWebSocketClient_Send_DefaultsToTextMessage(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_TextMessage(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation), synchronization.ExplorerTextMessage) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_Binary(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - address := common.HexToAddress("0xabc123") - addressBytes := address.Bytes() - explorerClient.Send(testutils.Context(t), addressBytes, synchronization.ExplorerBinaryMessage) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, addressBytes, <-wsserver.ReceivedBinary) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_Unsupported(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - - explorerClient.Send(testutils.Context(t), []byte(`{"hello": "world"}`), -1) - require.Contains(t, explorerClient.HealthReport()[explorerClient.Name()].Error(), "send on explorer client received unsupported message type -1") - require.NoError(t, explorerClient.Close()) -} - -func TestWebSocketClient_Send_WithAck(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - err := wsserver.Broadcast(`{"result": 200}`) - assert.NoError(t, err) - }, testutils.WaitTimeout(t)) - - cltest.CallbackOrTimeout(t, "receive response", func() { - response, err := explorerClient.Receive(testutils.Context(t)) - assert.NoError(t, err) - assert.NotNil(t, response) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Send_WithAckTimeout(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - - expectation := `{"hello": "world"}` - explorerClient.Send(testutils.Context(t), []byte(expectation)) - cltest.CallbackOrTimeout(t, "receive stats", func() { - require.Equal(t, expectation, <-wsserver.ReceivedText) - }, testutils.WaitTimeout(t)) - - cltest.CallbackOrTimeout(t, "receive response", func() { - _, err := explorerClient.Receive(testutils.Context(t), 100*time.Millisecond) - assert.ErrorIs(t, err, synchronization.ErrReceiveTimeout) - }, testutils.WaitTimeout(t)) -} - -func TestWebSocketClient_Status_ConnectAndServerDisconnect(t *testing.T) { - wsserver, cleanup := cltest.NewEventWebSocketServer(t) - defer cleanup() - - explorerClient := newTestExplorerClient(t, wsserver.URL) - assert.Equal(t, synchronization.ConnectionStatusDisconnected, explorerClient.Status()) - - require.NoError(t, explorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, explorerClient.Close()) }() - cltest.CallbackOrTimeout(t, "ws client connects", func() { - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return explorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusConnected)) - - // this triggers ConnectionStatusError and then the client gets reconnected - wsserver.WriteCloseMessage() - - cltest.CallbackOrTimeout(t, "ws client disconnects and reconnects", func() { - <-wsserver.Disconnected - <-wsserver.Connected - }, testutils.WaitTimeout(t)) - - // expecting the client to reconnect - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return explorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusConnected)) - - require.Equal(t, 1, wsserver.ConnectionsCount()) -} - -func TestWebSocketClient_Status_ConnectError(t *testing.T) { - badURL, err := url.Parse("http://badhost.com") - require.NoError(t, err) - - errorExplorerClient := newTestExplorerClient(t, badURL) - require.NoError(t, errorExplorerClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, errorExplorerClient.Close()) }() - - gomega.NewWithT(t).Eventually(func() synchronization.ConnectionStatus { - return errorExplorerClient.Status() - }).Should(gomega.Equal(synchronization.ConnectionStatusError)) -} - -func newTestExplorerClient(t *testing.T, wsURL *url.URL) synchronization.ExplorerClient { - return synchronization.NewExplorerClient(wsURL, "", "", logger.TestLogger(t)) -} diff --git a/core/services/synchronization/mocks/explorer_client.go b/core/services/synchronization/mocks/explorer_client.go deleted file mode 100644 index 2aa1616d1ca..00000000000 --- a/core/services/synchronization/mocks/explorer_client.go +++ /dev/null @@ -1,178 +0,0 @@ -// Code generated by mockery v2.28.1. DO NOT EDIT. - -package mocks - -import ( - context "context" - time "time" - - synchronization "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - mock "github.com/stretchr/testify/mock" - - url "net/url" -) - -// ExplorerClient is an autogenerated mock type for the ExplorerClient type -type ExplorerClient struct { - mock.Mock -} - -// Close provides a mock function with given fields: -func (_m *ExplorerClient) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// HealthReport provides a mock function with given fields: -func (_m *ExplorerClient) HealthReport() map[string]error { - ret := _m.Called() - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *ExplorerClient) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Ready provides a mock function with given fields: -func (_m *ExplorerClient) Ready() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Receive provides a mock function with given fields: _a0, _a1 -func (_m *ExplorerClient) Receive(_a0 context.Context, _a1 ...time.Duration) ([]byte, error) { - _va := make([]interface{}, len(_a1)) - for _i := range _a1 { - _va[_i] = _a1[_i] - } - var _ca []interface{} - _ca = append(_ca, _a0) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []byte - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...time.Duration) ([]byte, error)); ok { - return rf(_a0, _a1...) - } - if rf, ok := ret.Get(0).(func(context.Context, ...time.Duration) []byte); ok { - r0 = rf(_a0, _a1...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, ...time.Duration) error); ok { - r1 = rf(_a0, _a1...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Send provides a mock function with given fields: _a0, _a1, _a2 -func (_m *ExplorerClient) Send(_a0 context.Context, _a1 []byte, _a2 ...int) { - _va := make([]interface{}, len(_a2)) - for _i := range _a2 { - _va[_i] = _a2[_i] - } - var _ca []interface{} - _ca = append(_ca, _a0, _a1) - _ca = append(_ca, _va...) - _m.Called(_ca...) -} - -// Start provides a mock function with given fields: _a0 -func (_m *ExplorerClient) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Status provides a mock function with given fields: -func (_m *ExplorerClient) Status() synchronization.ConnectionStatus { - ret := _m.Called() - - var r0 synchronization.ConnectionStatus - if rf, ok := ret.Get(0).(func() synchronization.ConnectionStatus); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(synchronization.ConnectionStatus) - } - - return r0 -} - -// Url provides a mock function with given fields: -func (_m *ExplorerClient) Url() url.URL { - ret := _m.Called() - - var r0 url.URL - if rf, ok := ret.Get(0).(func() url.URL); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(url.URL) - } - - return r0 -} - -type mockConstructorTestingTNewExplorerClient interface { - mock.TestingT - Cleanup(func()) -} - -// NewExplorerClient creates a new instance of ExplorerClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewExplorerClient(t mockConstructorTestingTNewExplorerClient) *ExplorerClient { - mock := &ExplorerClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/telemetry/explorer.go b/core/services/telemetry/explorer.go deleted file mode 100644 index aa0f8410404..00000000000 --- a/core/services/telemetry/explorer.go +++ /dev/null @@ -1,31 +0,0 @@ -package telemetry - -import ( - "context" - - ocrtypes "github.com/smartcontractkit/libocr/commontypes" - - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" -) - -var _ MonitoringEndpointGenerator = &ExplorerAgent{} - -type ExplorerAgent struct { - explorerClient synchronization.ExplorerClient -} - -// NewExplorerAgent returns a Agent which is just a thin wrapper over -// the explorerClient for now -func NewExplorerAgent(explorerClient synchronization.ExplorerClient) *ExplorerAgent { - return &ExplorerAgent{explorerClient} -} - -// SendLog sends a telemetry log to the explorer -func (t *ExplorerAgent) SendLog(log []byte) { - t.explorerClient.Send(context.Background(), log, synchronization.ExplorerBinaryMessage) -} - -// GenMonitoringEndpoint creates a monitoring endpoint for telemetry -func (t *ExplorerAgent) GenMonitoringEndpoint(contractID string, telemType synchronization.TelemetryType) ocrtypes.MonitoringEndpoint { - return t -} diff --git a/core/services/telemetry/explorer_test.go b/core/services/telemetry/explorer_test.go deleted file mode 100644 index c3f50033d35..00000000000 --- a/core/services/telemetry/explorer_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package telemetry_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" - "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" -) - -func TestExplorerAgent(t *testing.T) { - explorerClient := mocks.NewExplorerClient(t) - explorerAgent := telemetry.NewExplorerAgent(explorerClient) - monitoringEndpoint := explorerAgent.GenMonitoringEndpoint("0xa", synchronization.OCR) - - // Handle the Send call and store the logs - var sentLog []byte - explorerClient.On("Send", mock.AnythingOfType("*context.emptyCtx"), mock.AnythingOfType("[]uint8"), synchronization.ExplorerBinaryMessage).Return().Run(func(args mock.Arguments) { - sentLog = args[1].([]byte) - }) - - // Send the log to the monitoring endpoint - log := []byte("test log") - monitoringEndpoint.SendLog(log) - - // Logs should be sent to the mock as they were passed in - assert.Equal(t, log, sentLog) -} diff --git a/core/services/telemetry/noop.go b/core/services/telemetry/noop.go index 2603c87875c..71670f2a198 100644 --- a/core/services/telemetry/noop.go +++ b/core/services/telemetry/noop.go @@ -11,7 +11,7 @@ var _ MonitoringEndpointGenerator = &NoopAgent{} type NoopAgent struct { } -// SendLog sends a telemetry log to the explorer +// SendLog sends a telemetry log to the ingress service func (t *NoopAgent) SendLog(log []byte) { } diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 8c3eef53f6a..45e92a147d3 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index ceb3849c3ab..ff7eb832c9c 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -1,4 +1,3 @@ -ExplorerURL = 'http://explorer.url' InsecureFastScrypt = true RootDir = 'test/root/dir' ShutdownGracePeriod = '10s' diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 876591c65e2..665de9be8cb 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -1,4 +1,3 @@ -ExplorerURL = '' InsecureFastScrypt = false RootDir = 'my/root/dir' ShutdownGracePeriod = '5s' diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d593f30b923..69ea7739f5a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [dev] +### Removed + +- Removed support for sending telemetry to the deprecated Explorer service. All nodes will have to remove `Explorer` related keys from TOML configuration and env vars. + + All nodes will have to remove the following secret configurations: + * `Explorer.AccessKey` + * `Explorer.Secret` + + All nodes will have to remove the following configuration field: `ExplorerURL` + ### Fixed - Unauthenticated users executing CLI commands previously generated a confusing error log, which is now removed: diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 16021193172..f956d14c7aa 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -20,19 +20,12 @@ HTTPURL = 'https://foo.bar' # Required ## Global ```toml -ExplorerURL = 'ws://explorer.url' # Example InsecureFastScrypt = false # Default RootDir = '~/.chainlink' # Default ShutdownGracePeriod = '5s' # Default ``` -### ExplorerURL -```toml -ExplorerURL = 'ws://explorer.url' # Example -``` -ExplorerURL is the websocket URL used by the node to push stats. This variable is required to deliver telemetry. - ### InsecureFastScrypt :warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ ```toml diff --git a/docs/SECRETS.md b/docs/SECRETS.md index 717603a4779..af316cab14b 100644 --- a/docs/SECRETS.md +++ b/docs/SECRETS.md @@ -51,30 +51,6 @@ AllowSimplePasswords skips the password complexity check normally enforced on UR Environment variable: `CL_DATABASE_ALLOW_SIMPLE_PASSWORDS` -## Explorer -```toml -[Explorer] -AccessKey = "access_key" # Example -Secret = "secret" # Example -``` - - -### AccessKey -```toml -AccessKey = "access_key" # Example -``` -AccessKey is the access key for authenticating with the Explorer. - -Environment variable: `CL_EXPLORER_ACCESS_KEY` - -### Secret -```toml -Secret = "secret" # Example -``` -Secret is the secret for authenticating with the Explorer. - -Environment variable: `CL_EXPLORER_SECRET` - ## Password ```toml [Password] diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 8a678e96cb9..85b16edaa27 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -10,7 +10,6 @@ AllowSimplePasswords = false # Input Configuration: # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index 1692480a698..5f02793ff57 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 7f6104afeca..527a739f7ca 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index e5d5151376e..791a8aad076 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -54,7 +54,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index 974bb507f9a..e9db92fb8f7 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -44,7 +44,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 0fc036a899c..f48fa1926d8 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -51,7 +51,6 @@ WSURL = 'wss://foo.bar/ws' HTTPURL = 'https://foo.bar' # Effective Configuration, with defaults applied: -ExplorerURL = '' InsecureFastScrypt = false RootDir = '~/.chainlink' ShutdownGracePeriod = '5s' diff --git a/tools/docker/config.toml b/tools/docker/config.toml index 2c21ce008c8..23108ae295c 100644 --- a/tools/docker/config.toml +++ b/tools/docker/config.toml @@ -1,5 +1,3 @@ -ExplorerURL = 'ws://explorer:3001' - [Log] Level = 'info'