diff --git a/.changeset/cute-pianos-cheat.md b/.changeset/cute-pianos-cheat.md new file mode 100644 index 00000000000..b79f45e362e --- /dev/null +++ b/.changeset/cute-pianos-cheat.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +**DirectRequest and FluxMonitor job types have been removed.** Creating new jobs of these types is no longer supported and will return an error. Any existing jobs of these types that are still present in the database will surface an error in the job UI on node startup rather than running. The underlying database tables (`direct_request_specs`, `flux_monitor_specs`, `flux_monitor_round_stats_v2`) are **unchanged in this release** and will be cleaned up in a future migration. The `[FluxMonitor]` TOML config section is now a no-op but is still accepted to avoid breaking existing config files during the transition. #breaking_change #nops diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4550d55b3ae..2c4f3ac597d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,7 +26,6 @@ /core/capabilities/ccip/ccipton/ @smartcontractkit/bix-build # To be deprecated in Chainlink V3 -/core/services/fluxmonitorv2/ @smartcontractkit/foundations @smartcontractkit/core /core/services/job/ @smartcontractkit/foundations @smartcontractkit/core /core/services/keystore/ @smartcontractkit/foundations /core/services/ocr*/ @smartcontractkit/foundations @smartcontractkit/core diff --git a/.github/workflows/legacy-system-tests.yml b/.github/workflows/legacy-system-tests.yml index 2d7d15e9fc3..c4c3d05f6d4 100644 --- a/.github/workflows/legacy-system-tests.yml +++ b/.github/workflows/legacy-system-tests.yml @@ -122,18 +122,6 @@ jobs: runner: "ubuntu-latest" tests_dir: "cron" logs_archive_name: "cron" - - display_name: "Test Direct Request Smoke" - testcmd: "go test -v -run TestSmoke" - envcmd: "cl u env.toml,products/directrequest/basic.toml" - runner: "ubuntu-latest" - tests_dir: "directrequest" - logs_archive_name: "directrequest" - - display_name: "Test Flux Smoke" - testcmd: "go test -v -run TestSmoke" - envcmd: "cl u env.toml,products/flux/basic.toml" - runner: "ubuntu-latest" - tests_dir: "flux" - logs_archive_name: "flux" - display_name: "Test VRF Smoke" testcmd: "go test -v -timeout 10m -run TestVRFBasic\\|TestVRFJobReplacement" envcmd: "cl u env.toml,products/vrf/basic.toml" diff --git a/.mockery.yaml b/.mockery.yaml index 2d6971b35bd..5b3a6756832 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -86,14 +86,6 @@ packages: interfaces: TelemetryIngress: TelemetryIngressEndpoint: - github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper: - config: - dir: core/internal/mocks - filename: flux_aggregator.go - interfaces: - FluxAggregatorInterface: - config: - mockname: FluxAggregator github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flags_wrapper: config: dir: core/internal/mocks @@ -133,12 +125,6 @@ packages: dir: "core/services/feeds/mocks" interfaces: FeedsManagerClient: - github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2: - interfaces: - ContractSubmitter: - Flags: - KeyStoreInterface: - ORM: github.com/smartcontractkit/chainlink/v2/core/services/functions: interfaces: ExternalAdapterClient: diff --git a/GNUmakefile b/GNUmakefile index 7514aeb1d40..c77a6bf7b8c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -104,7 +104,6 @@ install-plugins-testing: ## Build & install testing only LOOPP binaries (plugins GOPRIVATE=github.com/smartcontractkit/* go tool loopinstall --concurrency 5 $(LOOPINSTALL_TESTING_ARGS) ./plugins/plugins.testing.yaml; \ fi - .PHONY: install-plugins-local install-plugins-local: ## Build & install local plugins go install -ldflags="-s" \ diff --git a/core/cmd/direct-request-spec-template.yml b/core/cmd/direct-request-spec-template.yml deleted file mode 100644 index e6fda87af92..00000000000 --- a/core/cmd/direct-request-spec-template.yml +++ /dev/null @@ -1,13 +0,0 @@ -type = "directrequest" -schemaVersion = 1 -evmChainID = "%s" -name = "%s" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "%s" -observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_merge [type=merge left="{}"] - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; -""" diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index 1d6b10a65e0..aba93d91487 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -31,7 +31,7 @@ func TestJobPresenter_RenderTable(t *testing.T) { var ( id = "1" name = "Job 1" - jobSpecType = "fluxmonitor" + jobSpecType = "cron" schemaVersion = uint32(1) maxTaskDuration = sqlutil.Interval(1 * time.Second) @@ -49,7 +49,7 @@ func TestJobPresenter_RenderTable(t *testing.T) { SchemaVersion: schemaVersion, MaxTaskDuration: maxTaskDuration, DirectRequestSpec: nil, - FluxMonitorSpec: &presenters.FluxMonitorSpec{ + CronSpec: &presenters.CronSpec{ CreatedAt: createdAt, UpdatedAt: updatedAt, }, @@ -156,30 +156,6 @@ func TestJob_FriendlyCreatedAt(t *testing.T) { job *cmd.JobPresenter result string }{ - { - "gets the direct request spec created at timestamp", - &cmd.JobPresenter{ - JobResource: presenters.JobResource{ - Type: presenters.DirectRequestJobSpec, - DirectRequestSpec: &presenters.DirectRequestSpec{ - CreatedAt: now, - }, - }, - }, - now.Format(time.RFC3339), - }, - { - "gets the flux monitor spec created at timestamp", - &cmd.JobPresenter{ - JobResource: presenters.JobResource{ - Type: presenters.FluxMonitorJobSpec, - FluxMonitorSpec: &presenters.FluxMonitorSpec{ - CreatedAt: now, - }, - }, - }, - now.Format(time.RFC3339), - }, { "gets the cron spec created at timestamp", &cmd.JobPresenter{ @@ -253,7 +229,7 @@ func TestJob_FriendlyCreatedAt(t *testing.T) { "no spec exists", &cmd.JobPresenter{ JobResource: presenters.JobResource{ - Type: presenters.DirectRequestJobSpec, + Type: presenters.CronJobSpec, }, }, "N/A", @@ -276,8 +252,8 @@ func TestJob_ToRows(t *testing.T) { JAID: cmd.NewJAID("1"), JobResource: presenters.JobResource{ Name: "Test Job", - Type: presenters.DirectRequestJobSpec, - DirectRequestSpec: &presenters.DirectRequestSpec{ + Type: presenters.CronJobSpec, + CronSpec: &presenters.CronSpec{ CreatedAt: now, }, PipelineSpec: presenters.PipelineSpec{ @@ -287,80 +263,18 @@ func TestJob_ToRows(t *testing.T) { } assert.Equal(t, [][]string{ - {"1", "Test Job", "directrequest", "ds1 http", now.Format(time.RFC3339)}, - {"1", "Test Job", "directrequest", "ds1_parse jsonparse", now.Format(time.RFC3339)}, - {"1", "Test Job", "directrequest", "ds1_multiply multiply", now.Format(time.RFC3339)}, + {"1", "Test Job", "cron", "ds1 http", now.Format(time.RFC3339)}, + {"1", "Test Job", "cron", "ds1_parse jsonparse", now.Format(time.RFC3339)}, + {"1", "Test Job", "cron", "ds1_multiply multiply", now.Format(time.RFC3339)}, }, job.ToRows()) // Produce a single row even if there is not DAG job.PipelineSpec.DotDAGSource = "" assert.Equal(t, [][]string{ - {"1", "Test Job", "directrequest", "", now.Format(time.RFC3339)}, + {"1", "Test Job", "cron", "", now.Format(time.RFC3339)}, }, job.ToRows()) } -//go:embed direct-request-spec-template.yml -var directRequestSpecTemplate string - -func getDirectRequestSpec() string { - return fmt.Sprintf(directRequestSpecTemplate, testutils.FixtureChainID.String(), uuid.New(), uuid.New()) -} - -func TestShell_ListFindJobs(t *testing.T) { - t.Parallel() - - app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].Enabled = ptr(true) - }) - client, r := app.NewShellAndRenderer() - - // Create the job - fs := flag.NewFlagSet("", flag.ExitOnError) - flagSetApplyFromAction(client.CreateJob, fs, "") - - require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) - - err := client.CreateJob(cli.NewContext(nil, fs, nil)) - require.NoError(t, err) - require.Len(t, r.Renders, 1) - createOutput, ok := r.Renders[0].(*cmd.JobPresenter) - require.True(t, ok, "Expected Renders[0] to be *cmd.JobPresenter, got %T", r.Renders[0]) - - require.NoError(t, client.ListJobs(cltest.EmptyCLIContext())) - jobs := *r.Renders[1].(*cmd.JobPresenters) - require.Len(t, jobs, 1) - assert.Equal(t, createOutput.ID, jobs[0].ID) -} - -func TestShell_ShowJob(t *testing.T) { - t.Parallel() - - app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].Enabled = ptr(true) - }) - client, r := app.NewShellAndRenderer() - - // Create the job - fs := flag.NewFlagSet("", flag.ExitOnError) - flagSetApplyFromAction(client.CreateJob, fs, "") - - require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) - - err := client.CreateJob(cli.NewContext(nil, fs, nil)) - require.NoError(t, err) - require.Len(t, r.Renders, 1) - createOutput, ok := r.Renders[0].(*cmd.JobPresenter) - require.True(t, ok, "Expected Renders[0] to be *cmd.JobPresenter, got %T", r.Renders[0]) - - set := flag.NewFlagSet("test", 0) - err = set.Parse([]string{createOutput.ID}) - require.NoError(t, err) - c := cli.NewContext(nil, set, nil) - - require.NoError(t, client.ShowJob(c)) - job := *r.Renders[0].(*cmd.JobPresenter) - assert.Equal(t, createOutput.ID, job.ID) -} //go:embed ocr-bootstrap-spec.yml var ocrBootstrapSpec string @@ -403,54 +317,6 @@ func TestShell_CreateJobV2(t *testing.T) { assert.Equal(t, "0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15", output.OffChainReportingSpec.ContractAddress.String()) } -func TestShell_DeleteJob(t *testing.T) { - t.Parallel() - - app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) - c.EVM[0].Enabled = ptr(true) - c.EVM[0].NonceAutoSync = ptr(false) - c.EVM[0].BalanceMonitor.Enabled = ptr(false) - c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") - }) - client, r := app.NewShellAndRenderer() - - // Create the job - fs := flag.NewFlagSet("", flag.ExitOnError) - flagSetApplyFromAction(client.CreateJob, fs, "") - - require.NoError(t, fs.Parse([]string{getDirectRequestSpec()})) - - err := client.CreateJob(cli.NewContext(nil, fs, nil)) - require.NoError(t, err) - require.NotEmpty(t, r.Renders) - - output := *r.Renders[0].(*cmd.JobPresenter) - - requireJobsCount(t, app.JobORM(), 1) - - ctx := testutils.Context(t) - jobs, _, err := app.JobORM().FindJobs(ctx, 0, 1000) - require.NoError(t, err) - jobID := jobs[0].ID - cltest.AwaitJobActive(t, app.JobSpawner(), jobID, 3*time.Second) - - // Must supply job id - set := flag.NewFlagSet("test", 0) - flagSetApplyFromAction(client.DeleteJob, set, "") - c := cli.NewContext(nil, set, nil) - require.Equal(t, "must pass the job id to be archived", client.DeleteJob(c).Error()) - - set = flag.NewFlagSet("test", 0) - flagSetApplyFromAction(client.DeleteJob, set, "") - - require.NoError(t, set.Parse([]string{output.ID})) - - c = cli.NewContext(nil, set, nil) - require.NoError(t, client.DeleteJob(c)) - - requireJobsCount(t, app.JobORM(), 0) -} func requireJobsCount(t *testing.T, orm job.ORM, expected int) { ctx := testutils.Context(t) diff --git a/core/config/app_config.go b/core/config/app_config.go index 37755cbb265..89ce9558d42 100644 --- a/core/config/app_config.go +++ b/core/config/app_config.go @@ -41,7 +41,6 @@ type AppConfig interface { Workflows() Workflows Database() Database Feature() Feature - FluxMonitor() FluxMonitor Insecure() Insecure JobDistributor() JobDistributor JobPipeline() JobPipeline diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index 62d666b08d2..dea22ea13c0 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -334,11 +334,12 @@ DefaultTimeout = '15s' # Default # MaxSize defines the maximum size for HTTP requests and responses made by `http` and `bridge` adapters. MaxSize = '32768' # Default +# Deprecated: FluxMonitor job type has been removed. These settings are accepted for backwards-compatible +# config parsing only and have no effect. [FluxMonitor] -# **ADVANCED** -# DefaultTransactionQueueDepth controls the queue size for `DropOldestStrategy` in Flux Monitor. Set to 0 to use `SendEvery` strategy instead. +# DefaultTransactionQueueDepth **DEPRECATED**: has no effect. The FluxMonitor job type has been removed. DefaultTransactionQueueDepth = 1 # Default -# SimulateTransactions enables transaction simulation for Flux Monitor. +# SimulateTransactions **DEPRECATED**: has no effect. The FluxMonitor job type has been removed. SimulateTransactions = false # Default [OCR2] diff --git a/core/config/flux_monitor_config.go b/core/config/flux_monitor_config.go deleted file mode 100644 index e0ac6e7c81c..00000000000 --- a/core/config/flux_monitor_config.go +++ /dev/null @@ -1,6 +0,0 @@ -package config - -type FluxMonitor interface { - DefaultTransactionQueueDepth() uint32 - SimulateTransactions() bool -} diff --git a/core/config/toml/types.go b/core/config/toml/types.go index cb0ec6a9ff6..633db0600ff 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -40,14 +40,16 @@ type Core struct { RootDir *string ShutdownGracePeriod *commonconfig.Duration - Feature Feature `toml:",omitempty"` - Database Database `toml:",omitempty"` - TelemetryIngress TelemetryIngress `toml:",omitempty"` - AuditLogger AuditLogger `toml:",omitempty"` - Log Log `toml:",omitempty"` - WebServer WebServer `toml:",omitempty"` - JobDistributor JobDistributor `toml:",omitempty"` - JobPipeline JobPipeline `toml:",omitempty"` + Feature Feature `toml:",omitempty"` + Database Database `toml:",omitempty"` + TelemetryIngress TelemetryIngress `toml:",omitempty"` + AuditLogger AuditLogger `toml:",omitempty"` + Log Log `toml:",omitempty"` + WebServer WebServer `toml:",omitempty"` + JobDistributor JobDistributor `toml:",omitempty"` + JobPipeline JobPipeline `toml:",omitempty"` + // Deprecated: FluxMonitor job type has been removed. This field is retained for + // backwards-compatible config parsing only and has no effect. FluxMonitor FluxMonitor `toml:",omitempty"` OCR2 OCR2 `toml:",omitempty"` OCR OCR `toml:",omitempty"` @@ -91,8 +93,8 @@ func (c *Core) SetFrom(f *Core) { c.WebServer.setFrom(&f.WebServer) c.JobPipeline.setFrom(&f.JobPipeline) - c.FluxMonitor.setFrom(&f.FluxMonitor) + c.OCR2.setFrom(&f.OCR2) c.OCR.setFrom(&f.OCR) c.P2P.setFrom(&f.P2P) @@ -1414,17 +1416,19 @@ func (j *JobPipelineHTTPRequest) setFrom(f *JobPipelineHTTPRequest) { } } +// FluxMonitor is retained for backwards-compatible TOML parsing only. +// The FluxMonitor job type has been removed and these settings have no effect. type FluxMonitor struct { DefaultTransactionQueueDepth *uint32 SimulateTransactions *bool } -func (m *FluxMonitor) setFrom(f *FluxMonitor) { +func (fm *FluxMonitor) setFrom(f *FluxMonitor) { if v := f.DefaultTransactionQueueDepth; v != nil { - m.DefaultTransactionQueueDepth = v + fm.DefaultTransactionQueueDepth = v } if v := f.SimulateTransactions; v != nil { - m.SimulateTransactions = v + fm.SimulateTransactions = v } } diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index 96c9c0d0294..8644ac0e308 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -28,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -198,19 +197,6 @@ NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0,0 return spec } -func MakeDirectRequestJobSpec(t *testing.T) *job.Job { - t.Helper() - drs := &job.DirectRequestSpec{EVMChainID: (*sqlutil.Big)(testutils.FixtureChainID)} - spec := &job.Job{ - Type: job.DirectRequest, - SchemaVersion: 1, - ExternalJobID: uuid.New(), - DirectRequestSpec: drs, - Pipeline: pipeline.Pipeline{}, - PipelineSpec: &pipeline.Spec{}, - } - return spec -} func MustInsertExternalInitiator(t *testing.T, orm bridges.ORM) (ei bridges.ExternalInitiator) { return MustInsertExternalInitiatorWithOpts(t, orm, ExternalInitiatorOpts{}) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index f8c512f1152..08873e6e3d1 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -343,127 +343,6 @@ func setupOperatorContracts(t *testing.T) OperatorContracts { } } -//go:embed singleword-spec-template.yml -var singleWordSpecTemplate string - -//go:embed multiword-spec-template.yml -var multiWordSpecTemplate string - -// Tests both single and multiple word responses - -// i.e. both fulfillOracleRequest2 and fulfillOracleRequest. -func TestIntegration_DirectRequest(t *testing.T) { - t.Parallel() - tests := []struct { - name string - eip1559 bool - }{ - {"legacy mode", false}, - {"eip1559 mode", true}, - } - - for _, tt := range tests { - test := tt - t.Run(test.name, func(t *testing.T) { - ctx := testutils.Context(t) - // Simulate a consumer contract calling to obtain ETH quotes in 3 different currencies - // in a single callback. - config := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - }) - operatorContracts := setupOperatorContracts(t) - b := operatorContracts.sim - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b) - - sendingKeys, err := app.KeyStore.Eth().EnabledKeysForChain(ctx, testutils.SimulatedChainID) - require.NoError(t, err) - authorizedSenders := []common.Address{sendingKeys[0].Address} - tx, err := operatorContracts.operator.SetAuthorizedSenders(operatorContracts.user, authorizedSenders) - require.NoError(t, err) - b.Commit() - cltest.RequireTxSuccessful(t, b.Client(), tx.Hash()) - - // Fund node account with ETH. - n, err := b.Client().NonceAt(testutils.Context(t), operatorContracts.user.From, nil) - require.NoError(t, err) - tx = evmtestutils.NewLegacyTransaction(n, sendingKeys[0].Address, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) - signedTx, err := operatorContracts.user.Signer(operatorContracts.user.From, tx) - require.NoError(t, err) - err = b.Client().SendTransaction(testutils.Context(t), signedTx) - require.NoError(t, err) - b.Commit() - - err = app.Start(testutils.Context(t)) - require.NoError(t, err) - - mockServerUSD := cltest.NewHTTPMockServer(t, 200, "GET", `{"USD": 614.64}`) - mockServerEUR := cltest.NewHTTPMockServer(t, 200, "GET", `{"EUR": 507.07}`) - mockServerJPY := cltest.NewHTTPMockServer(t, 200, "GET", `{"JPY": 63818.86}`) - - nameAndExternalJobID := uuid.New() - addr := operatorContracts.operatorAddress.Hex() - spec := fmt.Sprintf(multiWordSpecTemplate, nameAndExternalJobID, addr, nameAndExternalJobID, addr) - j := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: spec}))) - cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, 5*time.Second) - - var jobID [32]byte - copy(jobID[:], j.ExternalJobID[:]) - tx, err = operatorContracts.multiWord.SetSpecID(operatorContracts.user, jobID) - require.NoError(t, err) - b.Commit() - cltest.RequireTxSuccessful(t, b.Client(), tx.Hash()) - - operatorContracts.user.GasLimit = 1000000 - tx, err = operatorContracts.multiWord.RequestMultipleParametersWithCustomURLs(operatorContracts.user, - mockServerUSD.URL, "USD", - mockServerEUR.URL, "EUR", - mockServerJPY.URL, "JPY", - big.NewInt(1000), - ) - require.NoError(t, err) - b.Commit() - cltest.RequireTxSuccessful(t, b.Client(), tx.Hash()) - - empty := big.NewInt(0) - assertPricesUint256(t, empty, empty, empty, operatorContracts.multiWord) - - commit, stopBlocks := cltest.Mine(b, 100*time.Millisecond) - defer stopBlocks() - - pipelineRuns := cltest.WaitForPipelineComplete(t, 0, j.ID, 1, 14, app.JobORM(), testutils.WaitTimeout(t)/2, time.Second) - pipelineRun := pipelineRuns[0] - assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) - assertPricesUint256(t, big.NewInt(61464), big.NewInt(50707), big.NewInt(6381886), operatorContracts.multiWord) - - nameAndExternalJobID = uuid.New() - singleWordSpec := fmt.Sprintf(singleWordSpecTemplate, nameAndExternalJobID, addr, nameAndExternalJobID, addr) - jobSingleWord := cltest.CreateJobViaWeb(t, app, []byte(cltest.MustJSONMarshal(t, web.CreateJobRequest{TOML: singleWordSpec}))) - cltest.AwaitJobActive(t, app.JobSpawner(), jobSingleWord.ID, 5*time.Second) - - var jobIDSingleWord [32]byte - copy(jobIDSingleWord[:], jobSingleWord.ExternalJobID[:]) - tx, err = operatorContracts.singleWord.SetSpecID(operatorContracts.user, jobIDSingleWord) - require.NoError(t, err) - commit() - cltest.RequireTxSuccessful(t, b.Client(), tx.Hash()) - mockServerUSD2 := cltest.NewHTTPMockServer(t, 200, "GET", `{"USD": 614.64}`) - tx, err = operatorContracts.singleWord.RequestMultipleParametersWithCustomURLs(operatorContracts.user, - mockServerUSD2.URL, "USD", - big.NewInt(1000), - ) - require.NoError(t, err) - commit() - cltest.RequireTxSuccessful(t, b.Client(), tx.Hash()) - - pipelineRuns = cltest.WaitForPipelineComplete(t, 0, jobSingleWord.ID, 1, 8, app.JobORM(), testutils.WaitTimeout(t), time.Second) - pipelineRun = pipelineRuns[0] - assertPipelineTaskRunsSuccessful(t, pipelineRun.PipelineTaskRuns) - v, err := operatorContracts.singleWord.CurrentPriceInt(nil) - require.NoError(t, err) - assert.Equal(t, big.NewInt(61464), v) - }) - } -} func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *cltest.TestApplication, sendingAddress common.Address, o *observer.ObservedLogs) { b := operatorContracts.sim diff --git a/core/internal/features/multiword-spec-template.yml b/core/internal/features/multiword-spec-template.yml deleted file mode 100644 index 8479212f7d4..00000000000 --- a/core/internal/features/multiword-spec-template.yml +++ /dev/null @@ -1,49 +0,0 @@ -type = "directrequest" -schemaVersion = 1 -name = "%s" -contractAddress = "%s" -evmChainID = 1337 -externalJobID = "%s" -observationSource = """ - decode_log [type=ethabidecodelog - abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] - decode_cbor [type=cborparse data="$(decode_log.data)"] - decode_log -> decode_cbor - decode_cbor -> usd - decode_cbor -> eur - decode_cbor -> jpy - usd [type=http method=GET url="$(decode_cbor.urlUSD)" allowunrestrictednetworkaccess="true"] - usd_parse [type=jsonparse path="$(decode_cbor.pathUSD)"] - usd_multiply [type=multiply value="$(usd_parse)", times="100"] - usd -> usd_parse -> usd_multiply - eur [type=http method=GET url="$(decode_cbor.urlEUR)" allowunrestrictednetworkaccess="true"] - eur_parse [type=jsonparse path="$(decode_cbor.pathEUR)"] - eur_multiply [type=multiply value="$(eur_parse)", times="100"] - eur -> eur_parse -> eur_multiply - jpy [type=http method=GET url="$(decode_cbor.urlJPY)" allowunrestrictednetworkaccess="true"] - jpy_parse [type=jsonparse path="$(decode_cbor.pathJPY)"] - jpy_multiply [type=multiply value="$(jpy_parse)", times="100"] - jpy -> jpy_parse -> jpy_multiply - usd_multiply -> encode_mwr - eur_multiply -> encode_mwr - jpy_multiply -> encode_mwr - encode_mwr [type=ethabiencode - abi="(bytes32 requestId, uint256 usd, uint256 eur, uint256 jpy)" - data=<{ - "requestId": $(decode_log.requestId), - "usd": $(usd_multiply), - "eur": $(eur_multiply), - "jpy": $(jpy_multiply)}>] - encode_tx [type=ethabiencode - abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" - data=<{"requestId": $(decode_log.requestId), - "payment": $(decode_log.payment), - "callbackAddress": $(decode_log.callbackAddr), - "callbackFunctionId": $(decode_log.callbackFunctionId), - "expiration": $(decode_log.cancelExpiration), - "data": $(encode_mwr)}>] - submit_tx [type=ethtx to="%s" data="$(encode_tx)" minConfirmations="2"] - encode_mwr -> encode_tx -> submit_tx -""" diff --git a/core/internal/features/singleword-spec-template.yml b/core/internal/features/singleword-spec-template.yml deleted file mode 100644 index 4ceef574d91..00000000000 --- a/core/internal/features/singleword-spec-template.yml +++ /dev/null @@ -1,27 +0,0 @@ -type = "directrequest" -schemaVersion = 1 -name = "%s" -contractAddress = "%s" -externalJobID = "%s" -evmChainID = 1337 -observationSource = """ - decode_log [type=ethabidecodelog - abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" - data="$(jobRun.logData)" - topics="$(jobRun.logTopics)"] - decode_cbor [type=cborparse data="$(decode_log.data)"] - ds1 [type=http method=GET url="$(decode_cbor.urlUSD)" allowunrestrictednetworkaccess="true"]; - ds1_parse [type=jsonparse path="$(decode_cbor.pathUSD)"]; - ds1_multiply [type=multiply value="$(ds1_parse)" times=100]; - encode_data [type=ethabiencode abi="(uint256 value)" data=<{"value": $(ds1_multiply)}>] - encode_tx [type=ethabiencode - abi="fulfillOracleRequest(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data)" - data=<{"requestId": $(decode_log.requestId), - "payment": $(decode_log.payment), - "callbackAddress": $(decode_log.callbackAddr), - "callbackFunctionId": $(decode_log.callbackFunctionId), - "expiration": $(decode_log.cancelExpiration), - "data": $(encode_data)}>] - submit [type=ethtx to="%s" data="$(encode_tx)" minConfirmations="2"] - decode_log->decode_cbor->ds1 -> ds1_parse -> ds1_multiply->encode_data->encode_tx->submit; -""" diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go deleted file mode 100644 index b1c7502d704..00000000000 --- a/core/internal/mocks/flux_aggregator.go +++ /dev/null @@ -1,4687 +0,0 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. - -package mocks - -import ( - big "math/big" - - bind "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" - common "github.com/ethereum/go-ethereum/common" - types "github.com/ethereum/go-ethereum/core/types" - event "github.com/ethereum/go-ethereum/event" - generated "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated" - flux_aggregator_wrapper "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - mock "github.com/stretchr/testify/mock" -) - -// FluxAggregator is an autogenerated mock type for the FluxAggregatorInterface type -type FluxAggregator struct { - mock.Mock -} - -type FluxAggregator_Expecter struct { - mock *mock.Mock -} - -func (_m *FluxAggregator) EXPECT() *FluxAggregator_Expecter { - return &FluxAggregator_Expecter{mock: &_m.Mock} -} - -// AcceptAdmin provides a mock function with given fields: opts, _oracle -func (_m *FluxAggregator) AcceptAdmin(opts *bind.TransactOpts, _oracle common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, _oracle) - - if len(ret) == 0 { - panic("no return value specified for AcceptAdmin") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, _oracle) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, _oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, _oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_AcceptAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptAdmin' -type FluxAggregator_AcceptAdmin_Call struct { - *mock.Call -} - -// AcceptAdmin is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _oracle common.Address -func (_e *FluxAggregator_Expecter) AcceptAdmin(opts interface{}, _oracle interface{}) *FluxAggregator_AcceptAdmin_Call { - return &FluxAggregator_AcceptAdmin_Call{Call: _e.mock.On("AcceptAdmin", opts, _oracle)} -} - -func (_c *FluxAggregator_AcceptAdmin_Call) Run(run func(opts *bind.TransactOpts, _oracle common.Address)) *FluxAggregator_AcceptAdmin_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_AcceptAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_AcceptAdmin_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_AcceptAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *FluxAggregator_AcceptAdmin_Call { - _c.Call.Return(run) - return _c -} - -// AcceptOwnership provides a mock function with given fields: opts -func (_m *FluxAggregator) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for AcceptOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership' -type FluxAggregator_AcceptOwnership_Call struct { - *mock.Call -} - -// AcceptOwnership is a helper method to define mock.On call -// - opts *bind.TransactOpts -func (_e *FluxAggregator_Expecter) AcceptOwnership(opts interface{}) *FluxAggregator_AcceptOwnership_Call { - return &FluxAggregator_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)} -} - -func (_c *FluxAggregator_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *FluxAggregator_AcceptOwnership_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts)) - }) - return _c -} - -func (_c *FluxAggregator_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_AcceptOwnership_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *FluxAggregator_AcceptOwnership_Call { - _c.Call.Return(run) - return _c -} - -// Address provides a mock function with no fields -func (_m *FluxAggregator) Address() common.Address { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Address") - } - - var r0 common.Address - if rf, ok := ret.Get(0).(func() common.Address); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - return r0 -} - -// FluxAggregator_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' -type FluxAggregator_Address_Call struct { - *mock.Call -} - -// Address is a helper method to define mock.On call -func (_e *FluxAggregator_Expecter) Address() *FluxAggregator_Address_Call { - return &FluxAggregator_Address_Call{Call: _e.mock.On("Address")} -} - -func (_c *FluxAggregator_Address_Call) Run(run func()) *FluxAggregator_Address_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *FluxAggregator_Address_Call) Return(_a0 common.Address) *FluxAggregator_Address_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *FluxAggregator_Address_Call) RunAndReturn(run func() common.Address) *FluxAggregator_Address_Call { - _c.Call.Return(run) - return _c -} - -// AllocatedFunds provides a mock function with given fields: opts -func (_m *FluxAggregator) AllocatedFunds(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for AllocatedFunds") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_AllocatedFunds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllocatedFunds' -type FluxAggregator_AllocatedFunds_Call struct { - *mock.Call -} - -// AllocatedFunds is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) AllocatedFunds(opts interface{}) *FluxAggregator_AllocatedFunds_Call { - return &FluxAggregator_AllocatedFunds_Call{Call: _e.mock.On("AllocatedFunds", opts)} -} - -func (_c *FluxAggregator_AllocatedFunds_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_AllocatedFunds_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_AllocatedFunds_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_AllocatedFunds_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_AllocatedFunds_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_AllocatedFunds_Call { - _c.Call.Return(run) - return _c -} - -// AvailableFunds provides a mock function with given fields: opts -func (_m *FluxAggregator) AvailableFunds(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for AvailableFunds") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_AvailableFunds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AvailableFunds' -type FluxAggregator_AvailableFunds_Call struct { - *mock.Call -} - -// AvailableFunds is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) AvailableFunds(opts interface{}) *FluxAggregator_AvailableFunds_Call { - return &FluxAggregator_AvailableFunds_Call{Call: _e.mock.On("AvailableFunds", opts)} -} - -func (_c *FluxAggregator_AvailableFunds_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_AvailableFunds_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_AvailableFunds_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_AvailableFunds_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_AvailableFunds_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_AvailableFunds_Call { - _c.Call.Return(run) - return _c -} - -// ChangeOracles provides a mock function with given fields: opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay -func (_m *FluxAggregator) ChangeOracles(opts *bind.TransactOpts, _removed []common.Address, _added []common.Address, _addedAdmins []common.Address, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32) (*types.Transaction, error) { - ret := _m.Called(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) - - if len(ret) == 0 { - panic("no return value specified for ChangeOracles") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) (*types.Transaction, error)); ok { - return rf(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) *types.Transaction); ok { - r0 = rf(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) error); ok { - r1 = rf(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ChangeOracles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChangeOracles' -type FluxAggregator_ChangeOracles_Call struct { - *mock.Call -} - -// ChangeOracles is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _removed []common.Address -// - _added []common.Address -// - _addedAdmins []common.Address -// - _minSubmissions uint32 -// - _maxSubmissions uint32 -// - _restartDelay uint32 -func (_e *FluxAggregator_Expecter) ChangeOracles(opts interface{}, _removed interface{}, _added interface{}, _addedAdmins interface{}, _minSubmissions interface{}, _maxSubmissions interface{}, _restartDelay interface{}) *FluxAggregator_ChangeOracles_Call { - return &FluxAggregator_ChangeOracles_Call{Call: _e.mock.On("ChangeOracles", opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay)} -} - -func (_c *FluxAggregator_ChangeOracles_Call) Run(run func(opts *bind.TransactOpts, _removed []common.Address, _added []common.Address, _addedAdmins []common.Address, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32)) *FluxAggregator_ChangeOracles_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]common.Address), args[4].(uint32), args[5].(uint32), args[6].(uint32)) - }) - return _c -} - -func (_c *FluxAggregator_ChangeOracles_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_ChangeOracles_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ChangeOracles_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) (*types.Transaction, error)) *FluxAggregator_ChangeOracles_Call { - _c.Call.Return(run) - return _c -} - -// Decimals provides a mock function with given fields: opts -func (_m *FluxAggregator) Decimals(opts *bind.CallOpts) (uint8, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Decimals") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Decimals_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Decimals' -type FluxAggregator_Decimals_Call struct { - *mock.Call -} - -// Decimals is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Decimals(opts interface{}) *FluxAggregator_Decimals_Call { - return &FluxAggregator_Decimals_Call{Call: _e.mock.On("Decimals", opts)} -} - -func (_c *FluxAggregator_Decimals_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Decimals_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Decimals_Call) Return(_a0 uint8, _a1 error) *FluxAggregator_Decimals_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Decimals_Call) RunAndReturn(run func(*bind.CallOpts) (uint8, error)) *FluxAggregator_Decimals_Call { - _c.Call.Return(run) - return _c -} - -// Description provides a mock function with given fields: opts -func (_m *FluxAggregator) Description(opts *bind.CallOpts) (string, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Description") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Description_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Description' -type FluxAggregator_Description_Call struct { - *mock.Call -} - -// Description is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Description(opts interface{}) *FluxAggregator_Description_Call { - return &FluxAggregator_Description_Call{Call: _e.mock.On("Description", opts)} -} - -func (_c *FluxAggregator_Description_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Description_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Description_Call) Return(_a0 string, _a1 error) *FluxAggregator_Description_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Description_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *FluxAggregator_Description_Call { - _c.Call.Return(run) - return _c -} - -// FilterAnswerUpdated provides a mock function with given fields: opts, current, roundId -func (_m *FluxAggregator) FilterAnswerUpdated(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error) { - ret := _m.Called(opts, current, roundId) - - if len(ret) == 0 { - panic("no return value specified for FilterAnswerUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error)); ok { - return rf(opts, current, roundId) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []*big.Int) *flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator); ok { - r0 = rf(opts, current, roundId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []*big.Int) error); ok { - r1 = rf(opts, current, roundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterAnswerUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAnswerUpdated' -type FluxAggregator_FilterAnswerUpdated_Call struct { - *mock.Call -} - -// FilterAnswerUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - current []*big.Int -// - roundId []*big.Int -func (_e *FluxAggregator_Expecter) FilterAnswerUpdated(opts interface{}, current interface{}, roundId interface{}) *FluxAggregator_FilterAnswerUpdated_Call { - return &FluxAggregator_FilterAnswerUpdated_Call{Call: _e.mock.On("FilterAnswerUpdated", opts, current, roundId)} -} - -func (_c *FluxAggregator_FilterAnswerUpdated_Call) Run(run func(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int)) *FluxAggregator_FilterAnswerUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]*big.Int), args[2].([]*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_FilterAnswerUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, _a1 error) *FluxAggregator_FilterAnswerUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterAnswerUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error)) *FluxAggregator_FilterAnswerUpdated_Call { - _c.Call.Return(run) - return _c -} - -// FilterAvailableFundsUpdated provides a mock function with given fields: opts, amount -func (_m *FluxAggregator) FilterAvailableFundsUpdated(opts *bind.FilterOpts, amount []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error) { - ret := _m.Called(opts, amount) - - if len(ret) == 0 { - panic("no return value specified for FilterAvailableFundsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error)); ok { - return rf(opts, amount) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator); ok { - r0 = rf(opts, amount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok { - r1 = rf(opts, amount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterAvailableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAvailableFundsUpdated' -type FluxAggregator_FilterAvailableFundsUpdated_Call struct { - *mock.Call -} - -// FilterAvailableFundsUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - amount []*big.Int -func (_e *FluxAggregator_Expecter) FilterAvailableFundsUpdated(opts interface{}, amount interface{}) *FluxAggregator_FilterAvailableFundsUpdated_Call { - return &FluxAggregator_FilterAvailableFundsUpdated_Call{Call: _e.mock.On("FilterAvailableFundsUpdated", opts, amount)} -} - -func (_c *FluxAggregator_FilterAvailableFundsUpdated_Call) Run(run func(opts *bind.FilterOpts, amount []*big.Int)) *FluxAggregator_FilterAvailableFundsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_FilterAvailableFundsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, _a1 error) *FluxAggregator_FilterAvailableFundsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterAvailableFundsUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error)) *FluxAggregator_FilterAvailableFundsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// FilterNewRound provides a mock function with given fields: opts, roundId, startedBy -func (_m *FluxAggregator) FilterNewRound(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error) { - ret := _m.Called(opts, roundId, startedBy) - - if len(ret) == 0 { - panic("no return value specified for FilterNewRound") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorNewRoundIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error)); ok { - return rf(opts, roundId, startedBy) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) *flux_aggregator_wrapper.FluxAggregatorNewRoundIterator); ok { - r0 = rf(opts, roundId, startedBy) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, roundId, startedBy) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterNewRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNewRound' -type FluxAggregator_FilterNewRound_Call struct { - *mock.Call -} - -// FilterNewRound is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - roundId []*big.Int -// - startedBy []common.Address -func (_e *FluxAggregator_Expecter) FilterNewRound(opts interface{}, roundId interface{}, startedBy interface{}) *FluxAggregator_FilterNewRound_Call { - return &FluxAggregator_FilterNewRound_Call{Call: _e.mock.On("FilterNewRound", opts, roundId, startedBy)} -} - -func (_c *FluxAggregator_FilterNewRound_Call) Run(run func(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address)) *FluxAggregator_FilterNewRound_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]*big.Int), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterNewRound_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, _a1 error) *FluxAggregator_FilterNewRound_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterNewRound_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error)) *FluxAggregator_FilterNewRound_Call { - _c.Call.Return(run) - return _c -} - -// FilterOracleAdminUpdateRequested provides a mock function with given fields: opts, oracle -func (_m *FluxAggregator) FilterOracleAdminUpdateRequested(opts *bind.FilterOpts, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error) { - ret := _m.Called(opts, oracle) - - if len(ret) == 0 { - panic("no return value specified for FilterOracleAdminUpdateRequested") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error)); ok { - return rf(opts, oracle) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator); ok { - r0 = rf(opts, oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok { - r1 = rf(opts, oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterOracleAdminUpdateRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOracleAdminUpdateRequested' -type FluxAggregator_FilterOracleAdminUpdateRequested_Call struct { - *mock.Call -} - -// FilterOracleAdminUpdateRequested is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - oracle []common.Address -func (_e *FluxAggregator_Expecter) FilterOracleAdminUpdateRequested(opts interface{}, oracle interface{}) *FluxAggregator_FilterOracleAdminUpdateRequested_Call { - return &FluxAggregator_FilterOracleAdminUpdateRequested_Call{Call: _e.mock.On("FilterOracleAdminUpdateRequested", opts, oracle)} -} - -func (_c *FluxAggregator_FilterOracleAdminUpdateRequested_Call) Run(run func(opts *bind.FilterOpts, oracle []common.Address)) *FluxAggregator_FilterOracleAdminUpdateRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterOracleAdminUpdateRequested_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, _a1 error) *FluxAggregator_FilterOracleAdminUpdateRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterOracleAdminUpdateRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error)) *FluxAggregator_FilterOracleAdminUpdateRequested_Call { - _c.Call.Return(run) - return _c -} - -// FilterOracleAdminUpdated provides a mock function with given fields: opts, oracle, newAdmin -func (_m *FluxAggregator) FilterOracleAdminUpdated(opts *bind.FilterOpts, oracle []common.Address, newAdmin []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error) { - ret := _m.Called(opts, oracle, newAdmin) - - if len(ret) == 0 { - panic("no return value specified for FilterOracleAdminUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error)); ok { - return rf(opts, oracle, newAdmin) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator); ok { - r0 = rf(opts, oracle, newAdmin) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, oracle, newAdmin) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterOracleAdminUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOracleAdminUpdated' -type FluxAggregator_FilterOracleAdminUpdated_Call struct { - *mock.Call -} - -// FilterOracleAdminUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - oracle []common.Address -// - newAdmin []common.Address -func (_e *FluxAggregator_Expecter) FilterOracleAdminUpdated(opts interface{}, oracle interface{}, newAdmin interface{}) *FluxAggregator_FilterOracleAdminUpdated_Call { - return &FluxAggregator_FilterOracleAdminUpdated_Call{Call: _e.mock.On("FilterOracleAdminUpdated", opts, oracle, newAdmin)} -} - -func (_c *FluxAggregator_FilterOracleAdminUpdated_Call) Run(run func(opts *bind.FilterOpts, oracle []common.Address, newAdmin []common.Address)) *FluxAggregator_FilterOracleAdminUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterOracleAdminUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, _a1 error) *FluxAggregator_FilterOracleAdminUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterOracleAdminUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error)) *FluxAggregator_FilterOracleAdminUpdated_Call { - _c.Call.Return(run) - return _c -} - -// FilterOraclePermissionsUpdated provides a mock function with given fields: opts, oracle, whitelisted -func (_m *FluxAggregator) FilterOraclePermissionsUpdated(opts *bind.FilterOpts, oracle []common.Address, whitelisted []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error) { - ret := _m.Called(opts, oracle, whitelisted) - - if len(ret) == 0 { - panic("no return value specified for FilterOraclePermissionsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error)); ok { - return rf(opts, oracle, whitelisted) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []bool) *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator); ok { - r0 = rf(opts, oracle, whitelisted) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []bool) error); ok { - r1 = rf(opts, oracle, whitelisted) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterOraclePermissionsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOraclePermissionsUpdated' -type FluxAggregator_FilterOraclePermissionsUpdated_Call struct { - *mock.Call -} - -// FilterOraclePermissionsUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - oracle []common.Address -// - whitelisted []bool -func (_e *FluxAggregator_Expecter) FilterOraclePermissionsUpdated(opts interface{}, oracle interface{}, whitelisted interface{}) *FluxAggregator_FilterOraclePermissionsUpdated_Call { - return &FluxAggregator_FilterOraclePermissionsUpdated_Call{Call: _e.mock.On("FilterOraclePermissionsUpdated", opts, oracle, whitelisted)} -} - -func (_c *FluxAggregator_FilterOraclePermissionsUpdated_Call) Run(run func(opts *bind.FilterOpts, oracle []common.Address, whitelisted []bool)) *FluxAggregator_FilterOraclePermissionsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]bool)) - }) - return _c -} - -func (_c *FluxAggregator_FilterOraclePermissionsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, _a1 error) *FluxAggregator_FilterOraclePermissionsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterOraclePermissionsUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error)) *FluxAggregator_FilterOraclePermissionsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to -func (_m *FluxAggregator) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferRequested") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested' -type FluxAggregator_FilterOwnershipTransferRequested_Call struct { - *mock.Call -} - -// FilterOwnershipTransferRequested is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - from []common.Address -// - to []common.Address -func (_e *FluxAggregator_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *FluxAggregator_FilterOwnershipTransferRequested_Call { - return &FluxAggregator_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)} -} - -func (_c *FluxAggregator_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *FluxAggregator_FilterOwnershipTransferRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterOwnershipTransferRequested_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, _a1 error) *FluxAggregator_FilterOwnershipTransferRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error)) *FluxAggregator_FilterOwnershipTransferRequested_Call { - _c.Call.Return(run) - return _c -} - -// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to -func (_m *FluxAggregator) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error) { - ret := _m.Called(opts, from, to) - - if len(ret) == 0 { - panic("no return value specified for FilterOwnershipTransferred") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error)); ok { - return rf(opts, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator); ok { - r0 = rf(opts, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred' -type FluxAggregator_FilterOwnershipTransferred_Call struct { - *mock.Call -} - -// FilterOwnershipTransferred is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - from []common.Address -// - to []common.Address -func (_e *FluxAggregator_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *FluxAggregator_FilterOwnershipTransferred_Call { - return &FluxAggregator_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)} -} - -func (_c *FluxAggregator_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *FluxAggregator_FilterOwnershipTransferred_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterOwnershipTransferred_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, _a1 error) *FluxAggregator_FilterOwnershipTransferred_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error)) *FluxAggregator_FilterOwnershipTransferred_Call { - _c.Call.Return(run) - return _c -} - -// FilterRequesterPermissionsSet provides a mock function with given fields: opts, requester -func (_m *FluxAggregator) FilterRequesterPermissionsSet(opts *bind.FilterOpts, requester []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error) { - ret := _m.Called(opts, requester) - - if len(ret) == 0 { - panic("no return value specified for FilterRequesterPermissionsSet") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error)); ok { - return rf(opts, requester) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator); ok { - r0 = rf(opts, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok { - r1 = rf(opts, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterRequesterPermissionsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterRequesterPermissionsSet' -type FluxAggregator_FilterRequesterPermissionsSet_Call struct { - *mock.Call -} - -// FilterRequesterPermissionsSet is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - requester []common.Address -func (_e *FluxAggregator_Expecter) FilterRequesterPermissionsSet(opts interface{}, requester interface{}) *FluxAggregator_FilterRequesterPermissionsSet_Call { - return &FluxAggregator_FilterRequesterPermissionsSet_Call{Call: _e.mock.On("FilterRequesterPermissionsSet", opts, requester)} -} - -func (_c *FluxAggregator_FilterRequesterPermissionsSet_Call) Run(run func(opts *bind.FilterOpts, requester []common.Address)) *FluxAggregator_FilterRequesterPermissionsSet_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterRequesterPermissionsSet_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, _a1 error) *FluxAggregator_FilterRequesterPermissionsSet_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterRequesterPermissionsSet_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error)) *FluxAggregator_FilterRequesterPermissionsSet_Call { - _c.Call.Return(run) - return _c -} - -// FilterRoundDetailsUpdated provides a mock function with given fields: opts, paymentAmount, minSubmissionCount, maxSubmissionCount -func (_m *FluxAggregator) FilterRoundDetailsUpdated(opts *bind.FilterOpts, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error) { - ret := _m.Called(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) - - if len(ret) == 0 { - panic("no return value specified for FilterRoundDetailsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error)); ok { - return rf(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator); ok { - r0 = rf(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) error); ok { - r1 = rf(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterRoundDetailsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterRoundDetailsUpdated' -type FluxAggregator_FilterRoundDetailsUpdated_Call struct { - *mock.Call -} - -// FilterRoundDetailsUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - paymentAmount []*big.Int -// - minSubmissionCount []uint32 -// - maxSubmissionCount []uint32 -func (_e *FluxAggregator_Expecter) FilterRoundDetailsUpdated(opts interface{}, paymentAmount interface{}, minSubmissionCount interface{}, maxSubmissionCount interface{}) *FluxAggregator_FilterRoundDetailsUpdated_Call { - return &FluxAggregator_FilterRoundDetailsUpdated_Call{Call: _e.mock.On("FilterRoundDetailsUpdated", opts, paymentAmount, minSubmissionCount, maxSubmissionCount)} -} - -func (_c *FluxAggregator_FilterRoundDetailsUpdated_Call) Run(run func(opts *bind.FilterOpts, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32)) *FluxAggregator_FilterRoundDetailsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]*big.Int), args[2].([]uint32), args[3].([]uint32)) - }) - return _c -} - -func (_c *FluxAggregator_FilterRoundDetailsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, _a1 error) *FluxAggregator_FilterRoundDetailsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterRoundDetailsUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error)) *FluxAggregator_FilterRoundDetailsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// FilterSubmissionReceived provides a mock function with given fields: opts, submission, round, oracle -func (_m *FluxAggregator) FilterSubmissionReceived(opts *bind.FilterOpts, submission []*big.Int, round []uint32, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error) { - ret := _m.Called(opts, submission, round, oracle) - - if len(ret) == 0 { - panic("no return value specified for FilterSubmissionReceived") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error)); ok { - return rf(opts, submission, round, oracle) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) *flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator); ok { - r0 = rf(opts, submission, round, oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) error); ok { - r1 = rf(opts, submission, round, oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterSubmissionReceived_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSubmissionReceived' -type FluxAggregator_FilterSubmissionReceived_Call struct { - *mock.Call -} - -// FilterSubmissionReceived is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - submission []*big.Int -// - round []uint32 -// - oracle []common.Address -func (_e *FluxAggregator_Expecter) FilterSubmissionReceived(opts interface{}, submission interface{}, round interface{}, oracle interface{}) *FluxAggregator_FilterSubmissionReceived_Call { - return &FluxAggregator_FilterSubmissionReceived_Call{Call: _e.mock.On("FilterSubmissionReceived", opts, submission, round, oracle)} -} - -func (_c *FluxAggregator_FilterSubmissionReceived_Call) Run(run func(opts *bind.FilterOpts, submission []*big.Int, round []uint32, oracle []common.Address)) *FluxAggregator_FilterSubmissionReceived_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]*big.Int), args[2].([]uint32), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterSubmissionReceived_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, _a1 error) *FluxAggregator_FilterSubmissionReceived_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterSubmissionReceived_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error)) *FluxAggregator_FilterSubmissionReceived_Call { - _c.Call.Return(run) - return _c -} - -// FilterValidatorUpdated provides a mock function with given fields: opts, previous, current -func (_m *FluxAggregator) FilterValidatorUpdated(opts *bind.FilterOpts, previous []common.Address, current []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error) { - ret := _m.Called(opts, previous, current) - - if len(ret) == 0 { - panic("no return value specified for FilterValidatorUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator - var r1 error - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error)); ok { - return rf(opts, previous, current) - } - if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator); ok { - r0 = rf(opts, previous, current) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator) - } - } - - if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok { - r1 = rf(opts, previous, current) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_FilterValidatorUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterValidatorUpdated' -type FluxAggregator_FilterValidatorUpdated_Call struct { - *mock.Call -} - -// FilterValidatorUpdated is a helper method to define mock.On call -// - opts *bind.FilterOpts -// - previous []common.Address -// - current []common.Address -func (_e *FluxAggregator_Expecter) FilterValidatorUpdated(opts interface{}, previous interface{}, current interface{}) *FluxAggregator_FilterValidatorUpdated_Call { - return &FluxAggregator_FilterValidatorUpdated_Call{Call: _e.mock.On("FilterValidatorUpdated", opts, previous, current)} -} - -func (_c *FluxAggregator_FilterValidatorUpdated_Call) Run(run func(opts *bind.FilterOpts, previous []common.Address, current []common.Address)) *FluxAggregator_FilterValidatorUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_FilterValidatorUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, _a1 error) *FluxAggregator_FilterValidatorUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_FilterValidatorUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error)) *FluxAggregator_FilterValidatorUpdated_Call { - _c.Call.Return(run) - return _c -} - -// GetAdmin provides a mock function with given fields: opts, _oracle -func (_m *FluxAggregator) GetAdmin(opts *bind.CallOpts, _oracle common.Address) (common.Address, error) { - ret := _m.Called(opts, _oracle) - - if len(ret) == 0 { - panic("no return value specified for GetAdmin") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { - return rf(opts, _oracle) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok { - r0 = rf(opts, _oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok { - r1 = rf(opts, _oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_GetAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAdmin' -type FluxAggregator_GetAdmin_Call struct { - *mock.Call -} - -// GetAdmin is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _oracle common.Address -func (_e *FluxAggregator_Expecter) GetAdmin(opts interface{}, _oracle interface{}) *FluxAggregator_GetAdmin_Call { - return &FluxAggregator_GetAdmin_Call{Call: _e.mock.On("GetAdmin", opts, _oracle)} -} - -func (_c *FluxAggregator_GetAdmin_Call) Run(run func(opts *bind.CallOpts, _oracle common.Address)) *FluxAggregator_GetAdmin_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_GetAdmin_Call) Return(_a0 common.Address, _a1 error) *FluxAggregator_GetAdmin_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_GetAdmin_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *FluxAggregator_GetAdmin_Call { - _c.Call.Return(run) - return _c -} - -// GetAnswer provides a mock function with given fields: opts, _roundId -func (_m *FluxAggregator) GetAnswer(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { - ret := _m.Called(opts, _roundId) - - if len(ret) == 0 { - panic("no return value specified for GetAnswer") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { - return rf(opts, _roundId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) *big.Int); ok { - r0 = rf(opts, _roundId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, _roundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_GetAnswer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAnswer' -type FluxAggregator_GetAnswer_Call struct { - *mock.Call -} - -// GetAnswer is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _roundId *big.Int -func (_e *FluxAggregator_Expecter) GetAnswer(opts interface{}, _roundId interface{}) *FluxAggregator_GetAnswer_Call { - return &FluxAggregator_GetAnswer_Call{Call: _e.mock.On("GetAnswer", opts, _roundId)} -} - -func (_c *FluxAggregator_GetAnswer_Call) Run(run func(opts *bind.CallOpts, _roundId *big.Int)) *FluxAggregator_GetAnswer_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_GetAnswer_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_GetAnswer_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_GetAnswer_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (*big.Int, error)) *FluxAggregator_GetAnswer_Call { - _c.Call.Return(run) - return _c -} - -// GetOracles provides a mock function with given fields: opts -func (_m *FluxAggregator) GetOracles(opts *bind.CallOpts) ([]common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for GetOracles") - } - - var r0 []common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_GetOracles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOracles' -type FluxAggregator_GetOracles_Call struct { - *mock.Call -} - -// GetOracles is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) GetOracles(opts interface{}) *FluxAggregator_GetOracles_Call { - return &FluxAggregator_GetOracles_Call{Call: _e.mock.On("GetOracles", opts)} -} - -func (_c *FluxAggregator_GetOracles_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_GetOracles_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_GetOracles_Call) Return(_a0 []common.Address, _a1 error) *FluxAggregator_GetOracles_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_GetOracles_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *FluxAggregator_GetOracles_Call { - _c.Call.Return(run) - return _c -} - -// GetRoundData provides a mock function with given fields: opts, _roundId -func (_m *FluxAggregator) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (flux_aggregator_wrapper.GetRoundData, error) { - ret := _m.Called(opts, _roundId) - - if len(ret) == 0 { - panic("no return value specified for GetRoundData") - } - - var r0 flux_aggregator_wrapper.GetRoundData - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (flux_aggregator_wrapper.GetRoundData, error)); ok { - return rf(opts, _roundId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) flux_aggregator_wrapper.GetRoundData); ok { - r0 = rf(opts, _roundId) - } else { - r0 = ret.Get(0).(flux_aggregator_wrapper.GetRoundData) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, _roundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_GetRoundData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRoundData' -type FluxAggregator_GetRoundData_Call struct { - *mock.Call -} - -// GetRoundData is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _roundId *big.Int -func (_e *FluxAggregator_Expecter) GetRoundData(opts interface{}, _roundId interface{}) *FluxAggregator_GetRoundData_Call { - return &FluxAggregator_GetRoundData_Call{Call: _e.mock.On("GetRoundData", opts, _roundId)} -} - -func (_c *FluxAggregator_GetRoundData_Call) Run(run func(opts *bind.CallOpts, _roundId *big.Int)) *FluxAggregator_GetRoundData_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_GetRoundData_Call) Return(_a0 flux_aggregator_wrapper.GetRoundData, _a1 error) *FluxAggregator_GetRoundData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_GetRoundData_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (flux_aggregator_wrapper.GetRoundData, error)) *FluxAggregator_GetRoundData_Call { - _c.Call.Return(run) - return _c -} - -// GetTimestamp provides a mock function with given fields: opts, _roundId -func (_m *FluxAggregator) GetTimestamp(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { - ret := _m.Called(opts, _roundId) - - if len(ret) == 0 { - panic("no return value specified for GetTimestamp") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { - return rf(opts, _roundId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) *big.Int); ok { - r0 = rf(opts, _roundId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok { - r1 = rf(opts, _roundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_GetTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTimestamp' -type FluxAggregator_GetTimestamp_Call struct { - *mock.Call -} - -// GetTimestamp is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _roundId *big.Int -func (_e *FluxAggregator_Expecter) GetTimestamp(opts interface{}, _roundId interface{}) *FluxAggregator_GetTimestamp_Call { - return &FluxAggregator_GetTimestamp_Call{Call: _e.mock.On("GetTimestamp", opts, _roundId)} -} - -func (_c *FluxAggregator_GetTimestamp_Call) Run(run func(opts *bind.CallOpts, _roundId *big.Int)) *FluxAggregator_GetTimestamp_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_GetTimestamp_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_GetTimestamp_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_GetTimestamp_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (*big.Int, error)) *FluxAggregator_GetTimestamp_Call { - _c.Call.Return(run) - return _c -} - -// LatestAnswer provides a mock function with given fields: opts -func (_m *FluxAggregator) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestAnswer") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_LatestAnswer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestAnswer' -type FluxAggregator_LatestAnswer_Call struct { - *mock.Call -} - -// LatestAnswer is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) LatestAnswer(opts interface{}) *FluxAggregator_LatestAnswer_Call { - return &FluxAggregator_LatestAnswer_Call{Call: _e.mock.On("LatestAnswer", opts)} -} - -func (_c *FluxAggregator_LatestAnswer_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_LatestAnswer_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_LatestAnswer_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_LatestAnswer_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_LatestAnswer_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_LatestAnswer_Call { - _c.Call.Return(run) - return _c -} - -// LatestRound provides a mock function with given fields: opts -func (_m *FluxAggregator) LatestRound(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestRound") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_LatestRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestRound' -type FluxAggregator_LatestRound_Call struct { - *mock.Call -} - -// LatestRound is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) LatestRound(opts interface{}) *FluxAggregator_LatestRound_Call { - return &FluxAggregator_LatestRound_Call{Call: _e.mock.On("LatestRound", opts)} -} - -func (_c *FluxAggregator_LatestRound_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_LatestRound_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_LatestRound_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_LatestRound_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_LatestRound_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_LatestRound_Call { - _c.Call.Return(run) - return _c -} - -// LatestRoundData provides a mock function with given fields: opts -func (_m *FluxAggregator) LatestRoundData(opts *bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestRoundData") - } - - var r0 flux_aggregator_wrapper.LatestRoundData - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) flux_aggregator_wrapper.LatestRoundData); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(flux_aggregator_wrapper.LatestRoundData) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_LatestRoundData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestRoundData' -type FluxAggregator_LatestRoundData_Call struct { - *mock.Call -} - -// LatestRoundData is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) LatestRoundData(opts interface{}) *FluxAggregator_LatestRoundData_Call { - return &FluxAggregator_LatestRoundData_Call{Call: _e.mock.On("LatestRoundData", opts)} -} - -func (_c *FluxAggregator_LatestRoundData_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_LatestRoundData_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_LatestRoundData_Call) Return(_a0 flux_aggregator_wrapper.LatestRoundData, _a1 error) *FluxAggregator_LatestRoundData_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_LatestRoundData_Call) RunAndReturn(run func(*bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error)) *FluxAggregator_LatestRoundData_Call { - _c.Call.Return(run) - return _c -} - -// LatestTimestamp provides a mock function with given fields: opts -func (_m *FluxAggregator) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LatestTimestamp") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_LatestTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestTimestamp' -type FluxAggregator_LatestTimestamp_Call struct { - *mock.Call -} - -// LatestTimestamp is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) LatestTimestamp(opts interface{}) *FluxAggregator_LatestTimestamp_Call { - return &FluxAggregator_LatestTimestamp_Call{Call: _e.mock.On("LatestTimestamp", opts)} -} - -func (_c *FluxAggregator_LatestTimestamp_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_LatestTimestamp_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_LatestTimestamp_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_LatestTimestamp_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_LatestTimestamp_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_LatestTimestamp_Call { - _c.Call.Return(run) - return _c -} - -// LinkToken provides a mock function with given fields: opts -func (_m *FluxAggregator) LinkToken(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for LinkToken") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_LinkToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LinkToken' -type FluxAggregator_LinkToken_Call struct { - *mock.Call -} - -// LinkToken is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) LinkToken(opts interface{}) *FluxAggregator_LinkToken_Call { - return &FluxAggregator_LinkToken_Call{Call: _e.mock.On("LinkToken", opts)} -} - -func (_c *FluxAggregator_LinkToken_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_LinkToken_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_LinkToken_Call) Return(_a0 common.Address, _a1 error) *FluxAggregator_LinkToken_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_LinkToken_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *FluxAggregator_LinkToken_Call { - _c.Call.Return(run) - return _c -} - -// MaxSubmissionCount provides a mock function with given fields: opts -func (_m *FluxAggregator) MaxSubmissionCount(opts *bind.CallOpts) (uint32, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MaxSubmissionCount") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint32); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_MaxSubmissionCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxSubmissionCount' -type FluxAggregator_MaxSubmissionCount_Call struct { - *mock.Call -} - -// MaxSubmissionCount is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) MaxSubmissionCount(opts interface{}) *FluxAggregator_MaxSubmissionCount_Call { - return &FluxAggregator_MaxSubmissionCount_Call{Call: _e.mock.On("MaxSubmissionCount", opts)} -} - -func (_c *FluxAggregator_MaxSubmissionCount_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_MaxSubmissionCount_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_MaxSubmissionCount_Call) Return(_a0 uint32, _a1 error) *FluxAggregator_MaxSubmissionCount_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_MaxSubmissionCount_Call) RunAndReturn(run func(*bind.CallOpts) (uint32, error)) *FluxAggregator_MaxSubmissionCount_Call { - _c.Call.Return(run) - return _c -} - -// MaxSubmissionValue provides a mock function with given fields: opts -func (_m *FluxAggregator) MaxSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MaxSubmissionValue") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_MaxSubmissionValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxSubmissionValue' -type FluxAggregator_MaxSubmissionValue_Call struct { - *mock.Call -} - -// MaxSubmissionValue is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) MaxSubmissionValue(opts interface{}) *FluxAggregator_MaxSubmissionValue_Call { - return &FluxAggregator_MaxSubmissionValue_Call{Call: _e.mock.On("MaxSubmissionValue", opts)} -} - -func (_c *FluxAggregator_MaxSubmissionValue_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_MaxSubmissionValue_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_MaxSubmissionValue_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_MaxSubmissionValue_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_MaxSubmissionValue_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_MaxSubmissionValue_Call { - _c.Call.Return(run) - return _c -} - -// MinSubmissionCount provides a mock function with given fields: opts -func (_m *FluxAggregator) MinSubmissionCount(opts *bind.CallOpts) (uint32, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MinSubmissionCount") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint32); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_MinSubmissionCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MinSubmissionCount' -type FluxAggregator_MinSubmissionCount_Call struct { - *mock.Call -} - -// MinSubmissionCount is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) MinSubmissionCount(opts interface{}) *FluxAggregator_MinSubmissionCount_Call { - return &FluxAggregator_MinSubmissionCount_Call{Call: _e.mock.On("MinSubmissionCount", opts)} -} - -func (_c *FluxAggregator_MinSubmissionCount_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_MinSubmissionCount_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_MinSubmissionCount_Call) Return(_a0 uint32, _a1 error) *FluxAggregator_MinSubmissionCount_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_MinSubmissionCount_Call) RunAndReturn(run func(*bind.CallOpts) (uint32, error)) *FluxAggregator_MinSubmissionCount_Call { - _c.Call.Return(run) - return _c -} - -// MinSubmissionValue provides a mock function with given fields: opts -func (_m *FluxAggregator) MinSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for MinSubmissionValue") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_MinSubmissionValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MinSubmissionValue' -type FluxAggregator_MinSubmissionValue_Call struct { - *mock.Call -} - -// MinSubmissionValue is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) MinSubmissionValue(opts interface{}) *FluxAggregator_MinSubmissionValue_Call { - return &FluxAggregator_MinSubmissionValue_Call{Call: _e.mock.On("MinSubmissionValue", opts)} -} - -func (_c *FluxAggregator_MinSubmissionValue_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_MinSubmissionValue_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_MinSubmissionValue_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_MinSubmissionValue_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_MinSubmissionValue_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_MinSubmissionValue_Call { - _c.Call.Return(run) - return _c -} - -// OnTokenTransfer provides a mock function with given fields: opts, arg0, arg1, _data -func (_m *FluxAggregator) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, _data []byte) (*types.Transaction, error) { - ret := _m.Called(opts, arg0, arg1, _data) - - if len(ret) == 0 { - panic("no return value specified for OnTokenTransfer") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { - return rf(opts, arg0, arg1, _data) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) *types.Transaction); ok { - r0 = rf(opts, arg0, arg1, _data) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) error); ok { - r1 = rf(opts, arg0, arg1, _data) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_OnTokenTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnTokenTransfer' -type FluxAggregator_OnTokenTransfer_Call struct { - *mock.Call -} - -// OnTokenTransfer is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - arg0 common.Address -// - arg1 *big.Int -// - _data []byte -func (_e *FluxAggregator_Expecter) OnTokenTransfer(opts interface{}, arg0 interface{}, arg1 interface{}, _data interface{}) *FluxAggregator_OnTokenTransfer_Call { - return &FluxAggregator_OnTokenTransfer_Call{Call: _e.mock.On("OnTokenTransfer", opts, arg0, arg1, _data)} -} - -func (_c *FluxAggregator_OnTokenTransfer_Call) Run(run func(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, _data []byte)) *FluxAggregator_OnTokenTransfer_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int), args[3].([]byte)) - }) - return _c -} - -func (_c *FluxAggregator_OnTokenTransfer_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_OnTokenTransfer_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_OnTokenTransfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)) *FluxAggregator_OnTokenTransfer_Call { - _c.Call.Return(run) - return _c -} - -// OracleCount provides a mock function with given fields: opts -func (_m *FluxAggregator) OracleCount(opts *bind.CallOpts) (uint8, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for OracleCount") - } - - var r0 uint8 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint8) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_OracleCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OracleCount' -type FluxAggregator_OracleCount_Call struct { - *mock.Call -} - -// OracleCount is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) OracleCount(opts interface{}) *FluxAggregator_OracleCount_Call { - return &FluxAggregator_OracleCount_Call{Call: _e.mock.On("OracleCount", opts)} -} - -func (_c *FluxAggregator_OracleCount_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_OracleCount_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_OracleCount_Call) Return(_a0 uint8, _a1 error) *FluxAggregator_OracleCount_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_OracleCount_Call) RunAndReturn(run func(*bind.CallOpts) (uint8, error)) *FluxAggregator_OracleCount_Call { - _c.Call.Return(run) - return _c -} - -// OracleRoundState provides a mock function with given fields: opts, _oracle, _queriedRoundId -func (_m *FluxAggregator) OracleRoundState(opts *bind.CallOpts, _oracle common.Address, _queriedRoundId uint32) (flux_aggregator_wrapper.OracleRoundState, error) { - ret := _m.Called(opts, _oracle, _queriedRoundId) - - if len(ret) == 0 { - panic("no return value specified for OracleRoundState") - } - - var r0 flux_aggregator_wrapper.OracleRoundState - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint32) (flux_aggregator_wrapper.OracleRoundState, error)); ok { - return rf(opts, _oracle, _queriedRoundId) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint32) flux_aggregator_wrapper.OracleRoundState); ok { - r0 = rf(opts, _oracle, _queriedRoundId) - } else { - r0 = ret.Get(0).(flux_aggregator_wrapper.OracleRoundState) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, uint32) error); ok { - r1 = rf(opts, _oracle, _queriedRoundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_OracleRoundState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OracleRoundState' -type FluxAggregator_OracleRoundState_Call struct { - *mock.Call -} - -// OracleRoundState is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _oracle common.Address -// - _queriedRoundId uint32 -func (_e *FluxAggregator_Expecter) OracleRoundState(opts interface{}, _oracle interface{}, _queriedRoundId interface{}) *FluxAggregator_OracleRoundState_Call { - return &FluxAggregator_OracleRoundState_Call{Call: _e.mock.On("OracleRoundState", opts, _oracle, _queriedRoundId)} -} - -func (_c *FluxAggregator_OracleRoundState_Call) Run(run func(opts *bind.CallOpts, _oracle common.Address, _queriedRoundId uint32)) *FluxAggregator_OracleRoundState_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(uint32)) - }) - return _c -} - -func (_c *FluxAggregator_OracleRoundState_Call) Return(_a0 flux_aggregator_wrapper.OracleRoundState, _a1 error) *FluxAggregator_OracleRoundState_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_OracleRoundState_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, uint32) (flux_aggregator_wrapper.OracleRoundState, error)) *FluxAggregator_OracleRoundState_Call { - _c.Call.Return(run) - return _c -} - -// Owner provides a mock function with given fields: opts -func (_m *FluxAggregator) Owner(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Owner") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner' -type FluxAggregator_Owner_Call struct { - *mock.Call -} - -// Owner is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Owner(opts interface{}) *FluxAggregator_Owner_Call { - return &FluxAggregator_Owner_Call{Call: _e.mock.On("Owner", opts)} -} - -func (_c *FluxAggregator_Owner_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Owner_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Owner_Call) Return(_a0 common.Address, _a1 error) *FluxAggregator_Owner_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *FluxAggregator_Owner_Call { - _c.Call.Return(run) - return _c -} - -// ParseAnswerUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseAnswerUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseAnswerUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseAnswerUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAnswerUpdated' -type FluxAggregator_ParseAnswerUpdated_Call struct { - *mock.Call -} - -// ParseAnswerUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseAnswerUpdated(log interface{}) *FluxAggregator_ParseAnswerUpdated_Call { - return &FluxAggregator_ParseAnswerUpdated_Call{Call: _e.mock.On("ParseAnswerUpdated", log)} -} - -func (_c *FluxAggregator_ParseAnswerUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseAnswerUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseAnswerUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, _a1 error) *FluxAggregator_ParseAnswerUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseAnswerUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error)) *FluxAggregator_ParseAnswerUpdated_Call { - _c.Call.Return(run) - return _c -} - -// ParseAvailableFundsUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseAvailableFundsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseAvailableFundsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseAvailableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAvailableFundsUpdated' -type FluxAggregator_ParseAvailableFundsUpdated_Call struct { - *mock.Call -} - -// ParseAvailableFundsUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseAvailableFundsUpdated(log interface{}) *FluxAggregator_ParseAvailableFundsUpdated_Call { - return &FluxAggregator_ParseAvailableFundsUpdated_Call{Call: _e.mock.On("ParseAvailableFundsUpdated", log)} -} - -func (_c *FluxAggregator_ParseAvailableFundsUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseAvailableFundsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseAvailableFundsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, _a1 error) *FluxAggregator_ParseAvailableFundsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseAvailableFundsUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error)) *FluxAggregator_ParseAvailableFundsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// ParseLog provides a mock function with given fields: log -func (_m *FluxAggregator) ParseLog(log types.Log) (generated.AbigenLog, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseLog") - } - - var r0 generated.AbigenLog - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(generated.AbigenLog) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog' -type FluxAggregator_ParseLog_Call struct { - *mock.Call -} - -// ParseLog is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseLog(log interface{}) *FluxAggregator_ParseLog_Call { - return &FluxAggregator_ParseLog_Call{Call: _e.mock.On("ParseLog", log)} -} - -func (_c *FluxAggregator_ParseLog_Call) Run(run func(log types.Log)) *FluxAggregator_ParseLog_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *FluxAggregator_ParseLog_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *FluxAggregator_ParseLog_Call { - _c.Call.Return(run) - return _c -} - -// ParseNewRound provides a mock function with given fields: log -func (_m *FluxAggregator) ParseNewRound(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseNewRound") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorNewRound - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorNewRound); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorNewRound) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseNewRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNewRound' -type FluxAggregator_ParseNewRound_Call struct { - *mock.Call -} - -// ParseNewRound is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseNewRound(log interface{}) *FluxAggregator_ParseNewRound_Call { - return &FluxAggregator_ParseNewRound_Call{Call: _e.mock.On("ParseNewRound", log)} -} - -func (_c *FluxAggregator_ParseNewRound_Call) Run(run func(log types.Log)) *FluxAggregator_ParseNewRound_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseNewRound_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorNewRound, _a1 error) *FluxAggregator_ParseNewRound_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseNewRound_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error)) *FluxAggregator_ParseNewRound_Call { - _c.Call.Return(run) - return _c -} - -// ParseOracleAdminUpdateRequested provides a mock function with given fields: log -func (_m *FluxAggregator) ParseOracleAdminUpdateRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOracleAdminUpdateRequested") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseOracleAdminUpdateRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOracleAdminUpdateRequested' -type FluxAggregator_ParseOracleAdminUpdateRequested_Call struct { - *mock.Call -} - -// ParseOracleAdminUpdateRequested is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseOracleAdminUpdateRequested(log interface{}) *FluxAggregator_ParseOracleAdminUpdateRequested_Call { - return &FluxAggregator_ParseOracleAdminUpdateRequested_Call{Call: _e.mock.On("ParseOracleAdminUpdateRequested", log)} -} - -func (_c *FluxAggregator_ParseOracleAdminUpdateRequested_Call) Run(run func(log types.Log)) *FluxAggregator_ParseOracleAdminUpdateRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseOracleAdminUpdateRequested_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, _a1 error) *FluxAggregator_ParseOracleAdminUpdateRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseOracleAdminUpdateRequested_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error)) *FluxAggregator_ParseOracleAdminUpdateRequested_Call { - _c.Call.Return(run) - return _c -} - -// ParseOracleAdminUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseOracleAdminUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOracleAdminUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseOracleAdminUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOracleAdminUpdated' -type FluxAggregator_ParseOracleAdminUpdated_Call struct { - *mock.Call -} - -// ParseOracleAdminUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseOracleAdminUpdated(log interface{}) *FluxAggregator_ParseOracleAdminUpdated_Call { - return &FluxAggregator_ParseOracleAdminUpdated_Call{Call: _e.mock.On("ParseOracleAdminUpdated", log)} -} - -func (_c *FluxAggregator_ParseOracleAdminUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseOracleAdminUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseOracleAdminUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, _a1 error) *FluxAggregator_ParseOracleAdminUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseOracleAdminUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error)) *FluxAggregator_ParseOracleAdminUpdated_Call { - _c.Call.Return(run) - return _c -} - -// ParseOraclePermissionsUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseOraclePermissionsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOraclePermissionsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseOraclePermissionsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOraclePermissionsUpdated' -type FluxAggregator_ParseOraclePermissionsUpdated_Call struct { - *mock.Call -} - -// ParseOraclePermissionsUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseOraclePermissionsUpdated(log interface{}) *FluxAggregator_ParseOraclePermissionsUpdated_Call { - return &FluxAggregator_ParseOraclePermissionsUpdated_Call{Call: _e.mock.On("ParseOraclePermissionsUpdated", log)} -} - -func (_c *FluxAggregator_ParseOraclePermissionsUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseOraclePermissionsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseOraclePermissionsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, _a1 error) *FluxAggregator_ParseOraclePermissionsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseOraclePermissionsUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error)) *FluxAggregator_ParseOraclePermissionsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// ParseOwnershipTransferRequested provides a mock function with given fields: log -func (_m *FluxAggregator) ParseOwnershipTransferRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferRequested") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested' -type FluxAggregator_ParseOwnershipTransferRequested_Call struct { - *mock.Call -} - -// ParseOwnershipTransferRequested is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseOwnershipTransferRequested(log interface{}) *FluxAggregator_ParseOwnershipTransferRequested_Call { - return &FluxAggregator_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)} -} - -func (_c *FluxAggregator_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *FluxAggregator_ParseOwnershipTransferRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseOwnershipTransferRequested_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, _a1 error) *FluxAggregator_ParseOwnershipTransferRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error)) *FluxAggregator_ParseOwnershipTransferRequested_Call { - _c.Call.Return(run) - return _c -} - -// ParseOwnershipTransferred provides a mock function with given fields: log -func (_m *FluxAggregator) ParseOwnershipTransferred(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseOwnershipTransferred") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred' -type FluxAggregator_ParseOwnershipTransferred_Call struct { - *mock.Call -} - -// ParseOwnershipTransferred is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseOwnershipTransferred(log interface{}) *FluxAggregator_ParseOwnershipTransferred_Call { - return &FluxAggregator_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)} -} - -func (_c *FluxAggregator_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *FluxAggregator_ParseOwnershipTransferred_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseOwnershipTransferred_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, _a1 error) *FluxAggregator_ParseOwnershipTransferred_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error)) *FluxAggregator_ParseOwnershipTransferred_Call { - _c.Call.Return(run) - return _c -} - -// ParseRequesterPermissionsSet provides a mock function with given fields: log -func (_m *FluxAggregator) ParseRequesterPermissionsSet(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRequesterPermissionsSet") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseRequesterPermissionsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseRequesterPermissionsSet' -type FluxAggregator_ParseRequesterPermissionsSet_Call struct { - *mock.Call -} - -// ParseRequesterPermissionsSet is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseRequesterPermissionsSet(log interface{}) *FluxAggregator_ParseRequesterPermissionsSet_Call { - return &FluxAggregator_ParseRequesterPermissionsSet_Call{Call: _e.mock.On("ParseRequesterPermissionsSet", log)} -} - -func (_c *FluxAggregator_ParseRequesterPermissionsSet_Call) Run(run func(log types.Log)) *FluxAggregator_ParseRequesterPermissionsSet_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseRequesterPermissionsSet_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, _a1 error) *FluxAggregator_ParseRequesterPermissionsSet_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseRequesterPermissionsSet_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error)) *FluxAggregator_ParseRequesterPermissionsSet_Call { - _c.Call.Return(run) - return _c -} - -// ParseRoundDetailsUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseRoundDetailsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseRoundDetailsUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseRoundDetailsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseRoundDetailsUpdated' -type FluxAggregator_ParseRoundDetailsUpdated_Call struct { - *mock.Call -} - -// ParseRoundDetailsUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseRoundDetailsUpdated(log interface{}) *FluxAggregator_ParseRoundDetailsUpdated_Call { - return &FluxAggregator_ParseRoundDetailsUpdated_Call{Call: _e.mock.On("ParseRoundDetailsUpdated", log)} -} - -func (_c *FluxAggregator_ParseRoundDetailsUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseRoundDetailsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseRoundDetailsUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, _a1 error) *FluxAggregator_ParseRoundDetailsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseRoundDetailsUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error)) *FluxAggregator_ParseRoundDetailsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// ParseSubmissionReceived provides a mock function with given fields: log -func (_m *FluxAggregator) ParseSubmissionReceived(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseSubmissionReceived") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseSubmissionReceived_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSubmissionReceived' -type FluxAggregator_ParseSubmissionReceived_Call struct { - *mock.Call -} - -// ParseSubmissionReceived is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseSubmissionReceived(log interface{}) *FluxAggregator_ParseSubmissionReceived_Call { - return &FluxAggregator_ParseSubmissionReceived_Call{Call: _e.mock.On("ParseSubmissionReceived", log)} -} - -func (_c *FluxAggregator_ParseSubmissionReceived_Call) Run(run func(log types.Log)) *FluxAggregator_ParseSubmissionReceived_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseSubmissionReceived_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, _a1 error) *FluxAggregator_ParseSubmissionReceived_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseSubmissionReceived_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error)) *FluxAggregator_ParseSubmissionReceived_Call { - _c.Call.Return(run) - return _c -} - -// ParseValidatorUpdated provides a mock function with given fields: log -func (_m *FluxAggregator) ParseValidatorUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseValidatorUpdated") - } - - var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_ParseValidatorUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseValidatorUpdated' -type FluxAggregator_ParseValidatorUpdated_Call struct { - *mock.Call -} - -// ParseValidatorUpdated is a helper method to define mock.On call -// - log types.Log -func (_e *FluxAggregator_Expecter) ParseValidatorUpdated(log interface{}) *FluxAggregator_ParseValidatorUpdated_Call { - return &FluxAggregator_ParseValidatorUpdated_Call{Call: _e.mock.On("ParseValidatorUpdated", log)} -} - -func (_c *FluxAggregator_ParseValidatorUpdated_Call) Run(run func(log types.Log)) *FluxAggregator_ParseValidatorUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *FluxAggregator_ParseValidatorUpdated_Call) Return(_a0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, _a1 error) *FluxAggregator_ParseValidatorUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_ParseValidatorUpdated_Call) RunAndReturn(run func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error)) *FluxAggregator_ParseValidatorUpdated_Call { - _c.Call.Return(run) - return _c -} - -// PaymentAmount provides a mock function with given fields: opts -func (_m *FluxAggregator) PaymentAmount(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for PaymentAmount") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_PaymentAmount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PaymentAmount' -type FluxAggregator_PaymentAmount_Call struct { - *mock.Call -} - -// PaymentAmount is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) PaymentAmount(opts interface{}) *FluxAggregator_PaymentAmount_Call { - return &FluxAggregator_PaymentAmount_Call{Call: _e.mock.On("PaymentAmount", opts)} -} - -func (_c *FluxAggregator_PaymentAmount_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_PaymentAmount_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_PaymentAmount_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_PaymentAmount_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_PaymentAmount_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_PaymentAmount_Call { - _c.Call.Return(run) - return _c -} - -// RequestNewRound provides a mock function with given fields: opts -func (_m *FluxAggregator) RequestNewRound(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for RequestNewRound") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_RequestNewRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestNewRound' -type FluxAggregator_RequestNewRound_Call struct { - *mock.Call -} - -// RequestNewRound is a helper method to define mock.On call -// - opts *bind.TransactOpts -func (_e *FluxAggregator_Expecter) RequestNewRound(opts interface{}) *FluxAggregator_RequestNewRound_Call { - return &FluxAggregator_RequestNewRound_Call{Call: _e.mock.On("RequestNewRound", opts)} -} - -func (_c *FluxAggregator_RequestNewRound_Call) Run(run func(opts *bind.TransactOpts)) *FluxAggregator_RequestNewRound_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts)) - }) - return _c -} - -func (_c *FluxAggregator_RequestNewRound_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_RequestNewRound_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_RequestNewRound_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *FluxAggregator_RequestNewRound_Call { - _c.Call.Return(run) - return _c -} - -// RestartDelay provides a mock function with given fields: opts -func (_m *FluxAggregator) RestartDelay(opts *bind.CallOpts) (uint32, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for RestartDelay") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint32); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_RestartDelay_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestartDelay' -type FluxAggregator_RestartDelay_Call struct { - *mock.Call -} - -// RestartDelay is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) RestartDelay(opts interface{}) *FluxAggregator_RestartDelay_Call { - return &FluxAggregator_RestartDelay_Call{Call: _e.mock.On("RestartDelay", opts)} -} - -func (_c *FluxAggregator_RestartDelay_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_RestartDelay_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_RestartDelay_Call) Return(_a0 uint32, _a1 error) *FluxAggregator_RestartDelay_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_RestartDelay_Call) RunAndReturn(run func(*bind.CallOpts) (uint32, error)) *FluxAggregator_RestartDelay_Call { - _c.Call.Return(run) - return _c -} - -// SetRequesterPermissions provides a mock function with given fields: opts, _requester, _authorized, _delay -func (_m *FluxAggregator) SetRequesterPermissions(opts *bind.TransactOpts, _requester common.Address, _authorized bool, _delay uint32) (*types.Transaction, error) { - ret := _m.Called(opts, _requester, _authorized, _delay) - - if len(ret) == 0 { - panic("no return value specified for SetRequesterPermissions") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, uint32) (*types.Transaction, error)); ok { - return rf(opts, _requester, _authorized, _delay) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, uint32) *types.Transaction); ok { - r0 = rf(opts, _requester, _authorized, _delay) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, bool, uint32) error); ok { - r1 = rf(opts, _requester, _authorized, _delay) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_SetRequesterPermissions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRequesterPermissions' -type FluxAggregator_SetRequesterPermissions_Call struct { - *mock.Call -} - -// SetRequesterPermissions is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _requester common.Address -// - _authorized bool -// - _delay uint32 -func (_e *FluxAggregator_Expecter) SetRequesterPermissions(opts interface{}, _requester interface{}, _authorized interface{}, _delay interface{}) *FluxAggregator_SetRequesterPermissions_Call { - return &FluxAggregator_SetRequesterPermissions_Call{Call: _e.mock.On("SetRequesterPermissions", opts, _requester, _authorized, _delay)} -} - -func (_c *FluxAggregator_SetRequesterPermissions_Call) Run(run func(opts *bind.TransactOpts, _requester common.Address, _authorized bool, _delay uint32)) *FluxAggregator_SetRequesterPermissions_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(bool), args[3].(uint32)) - }) - return _c -} - -func (_c *FluxAggregator_SetRequesterPermissions_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_SetRequesterPermissions_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_SetRequesterPermissions_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, bool, uint32) (*types.Transaction, error)) *FluxAggregator_SetRequesterPermissions_Call { - _c.Call.Return(run) - return _c -} - -// SetValidator provides a mock function with given fields: opts, _newValidator -func (_m *FluxAggregator) SetValidator(opts *bind.TransactOpts, _newValidator common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, _newValidator) - - if len(ret) == 0 { - panic("no return value specified for SetValidator") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, _newValidator) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, _newValidator) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, _newValidator) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_SetValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetValidator' -type FluxAggregator_SetValidator_Call struct { - *mock.Call -} - -// SetValidator is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _newValidator common.Address -func (_e *FluxAggregator_Expecter) SetValidator(opts interface{}, _newValidator interface{}) *FluxAggregator_SetValidator_Call { - return &FluxAggregator_SetValidator_Call{Call: _e.mock.On("SetValidator", opts, _newValidator)} -} - -func (_c *FluxAggregator_SetValidator_Call) Run(run func(opts *bind.TransactOpts, _newValidator common.Address)) *FluxAggregator_SetValidator_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_SetValidator_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_SetValidator_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_SetValidator_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *FluxAggregator_SetValidator_Call { - _c.Call.Return(run) - return _c -} - -// Submit provides a mock function with given fields: opts, _roundId, _submission -func (_m *FluxAggregator) Submit(opts *bind.TransactOpts, _roundId *big.Int, _submission *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, _roundId, _submission) - - if len(ret) == 0 { - panic("no return value specified for Submit") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, _roundId, _submission) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int) *types.Transaction); ok { - r0 = rf(opts, _roundId, _submission) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, *big.Int) error); ok { - r1 = rf(opts, _roundId, _submission) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Submit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Submit' -type FluxAggregator_Submit_Call struct { - *mock.Call -} - -// Submit is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _roundId *big.Int -// - _submission *big.Int -func (_e *FluxAggregator_Expecter) Submit(opts interface{}, _roundId interface{}, _submission interface{}) *FluxAggregator_Submit_Call { - return &FluxAggregator_Submit_Call{Call: _e.mock.On("Submit", opts, _roundId, _submission)} -} - -func (_c *FluxAggregator_Submit_Call) Run(run func(opts *bind.TransactOpts, _roundId *big.Int, _submission *big.Int)) *FluxAggregator_Submit_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(*big.Int), args[2].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_Submit_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_Submit_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Submit_Call) RunAndReturn(run func(*bind.TransactOpts, *big.Int, *big.Int) (*types.Transaction, error)) *FluxAggregator_Submit_Call { - _c.Call.Return(run) - return _c -} - -// Timeout provides a mock function with given fields: opts -func (_m *FluxAggregator) Timeout(opts *bind.CallOpts) (uint32, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Timeout") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint32); ok { - r0 = rf(opts) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Timeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Timeout' -type FluxAggregator_Timeout_Call struct { - *mock.Call -} - -// Timeout is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Timeout(opts interface{}) *FluxAggregator_Timeout_Call { - return &FluxAggregator_Timeout_Call{Call: _e.mock.On("Timeout", opts)} -} - -func (_c *FluxAggregator_Timeout_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Timeout_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Timeout_Call) Return(_a0 uint32, _a1 error) *FluxAggregator_Timeout_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Timeout_Call) RunAndReturn(run func(*bind.CallOpts) (uint32, error)) *FluxAggregator_Timeout_Call { - _c.Call.Return(run) - return _c -} - -// TransferAdmin provides a mock function with given fields: opts, _oracle, _newAdmin -func (_m *FluxAggregator) TransferAdmin(opts *bind.TransactOpts, _oracle common.Address, _newAdmin common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, _oracle, _newAdmin) - - if len(ret) == 0 { - panic("no return value specified for TransferAdmin") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { - return rf(opts, _oracle, _newAdmin) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) *types.Transaction); ok { - r0 = rf(opts, _oracle, _newAdmin) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address) error); ok { - r1 = rf(opts, _oracle, _newAdmin) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_TransferAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferAdmin' -type FluxAggregator_TransferAdmin_Call struct { - *mock.Call -} - -// TransferAdmin is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _oracle common.Address -// - _newAdmin common.Address -func (_e *FluxAggregator_Expecter) TransferAdmin(opts interface{}, _oracle interface{}, _newAdmin interface{}) *FluxAggregator_TransferAdmin_Call { - return &FluxAggregator_TransferAdmin_Call{Call: _e.mock.On("TransferAdmin", opts, _oracle, _newAdmin)} -} - -func (_c *FluxAggregator_TransferAdmin_Call) Run(run func(opts *bind.TransactOpts, _oracle common.Address, _newAdmin common.Address)) *FluxAggregator_TransferAdmin_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_TransferAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_TransferAdmin_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_TransferAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)) *FluxAggregator_TransferAdmin_Call { - _c.Call.Return(run) - return _c -} - -// TransferOwnership provides a mock function with given fields: opts, _to -func (_m *FluxAggregator) TransferOwnership(opts *bind.TransactOpts, _to common.Address) (*types.Transaction, error) { - ret := _m.Called(opts, _to) - - if len(ret) == 0 { - panic("no return value specified for TransferOwnership") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { - return rf(opts, _to) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok { - r0 = rf(opts, _to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok { - r1 = rf(opts, _to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership' -type FluxAggregator_TransferOwnership_Call struct { - *mock.Call -} - -// TransferOwnership is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _to common.Address -func (_e *FluxAggregator_Expecter) TransferOwnership(opts interface{}, _to interface{}) *FluxAggregator_TransferOwnership_Call { - return &FluxAggregator_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, _to)} -} - -func (_c *FluxAggregator_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, _to common.Address)) *FluxAggregator_TransferOwnership_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_TransferOwnership_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *FluxAggregator_TransferOwnership_Call { - _c.Call.Return(run) - return _c -} - -// UpdateAvailableFunds provides a mock function with given fields: opts -func (_m *FluxAggregator) UpdateAvailableFunds(opts *bind.TransactOpts) (*types.Transaction, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for UpdateAvailableFunds") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_UpdateAvailableFunds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateAvailableFunds' -type FluxAggregator_UpdateAvailableFunds_Call struct { - *mock.Call -} - -// UpdateAvailableFunds is a helper method to define mock.On call -// - opts *bind.TransactOpts -func (_e *FluxAggregator_Expecter) UpdateAvailableFunds(opts interface{}) *FluxAggregator_UpdateAvailableFunds_Call { - return &FluxAggregator_UpdateAvailableFunds_Call{Call: _e.mock.On("UpdateAvailableFunds", opts)} -} - -func (_c *FluxAggregator_UpdateAvailableFunds_Call) Run(run func(opts *bind.TransactOpts)) *FluxAggregator_UpdateAvailableFunds_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts)) - }) - return _c -} - -func (_c *FluxAggregator_UpdateAvailableFunds_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_UpdateAvailableFunds_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_UpdateAvailableFunds_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *FluxAggregator_UpdateAvailableFunds_Call { - _c.Call.Return(run) - return _c -} - -// UpdateFutureRounds provides a mock function with given fields: opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout -func (_m *FluxAggregator) UpdateFutureRounds(opts *bind.TransactOpts, _paymentAmount *big.Int, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32, _timeout uint32) (*types.Transaction, error) { - ret := _m.Called(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) - - if len(ret) == 0 { - panic("no return value specified for UpdateFutureRounds") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) (*types.Transaction, error)); ok { - return rf(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) *types.Transaction); ok { - r0 = rf(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) error); ok { - r1 = rf(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_UpdateFutureRounds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateFutureRounds' -type FluxAggregator_UpdateFutureRounds_Call struct { - *mock.Call -} - -// UpdateFutureRounds is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _paymentAmount *big.Int -// - _minSubmissions uint32 -// - _maxSubmissions uint32 -// - _restartDelay uint32 -// - _timeout uint32 -func (_e *FluxAggregator_Expecter) UpdateFutureRounds(opts interface{}, _paymentAmount interface{}, _minSubmissions interface{}, _maxSubmissions interface{}, _restartDelay interface{}, _timeout interface{}) *FluxAggregator_UpdateFutureRounds_Call { - return &FluxAggregator_UpdateFutureRounds_Call{Call: _e.mock.On("UpdateFutureRounds", opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout)} -} - -func (_c *FluxAggregator_UpdateFutureRounds_Call) Run(run func(opts *bind.TransactOpts, _paymentAmount *big.Int, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32, _timeout uint32)) *FluxAggregator_UpdateFutureRounds_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(*big.Int), args[2].(uint32), args[3].(uint32), args[4].(uint32), args[5].(uint32)) - }) - return _c -} - -func (_c *FluxAggregator_UpdateFutureRounds_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_UpdateFutureRounds_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_UpdateFutureRounds_Call) RunAndReturn(run func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) (*types.Transaction, error)) *FluxAggregator_UpdateFutureRounds_Call { - _c.Call.Return(run) - return _c -} - -// Validator provides a mock function with given fields: opts -func (_m *FluxAggregator) Validator(opts *bind.CallOpts) (common.Address, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Validator") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Validator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validator' -type FluxAggregator_Validator_Call struct { - *mock.Call -} - -// Validator is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Validator(opts interface{}) *FluxAggregator_Validator_Call { - return &FluxAggregator_Validator_Call{Call: _e.mock.On("Validator", opts)} -} - -func (_c *FluxAggregator_Validator_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Validator_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Validator_Call) Return(_a0 common.Address, _a1 error) *FluxAggregator_Validator_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Validator_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *FluxAggregator_Validator_Call { - _c.Call.Return(run) - return _c -} - -// Version provides a mock function with given fields: opts -func (_m *FluxAggregator) Version(opts *bind.CallOpts) (*big.Int, error) { - ret := _m.Called(opts) - - if len(ret) == 0 { - panic("no return value specified for Version") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { - return rf(opts) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok { - r0 = rf(opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok { - r1 = rf(opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_Version_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Version' -type FluxAggregator_Version_Call struct { - *mock.Call -} - -// Version is a helper method to define mock.On call -// - opts *bind.CallOpts -func (_e *FluxAggregator_Expecter) Version(opts interface{}) *FluxAggregator_Version_Call { - return &FluxAggregator_Version_Call{Call: _e.mock.On("Version", opts)} -} - -func (_c *FluxAggregator_Version_Call) Run(run func(opts *bind.CallOpts)) *FluxAggregator_Version_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts)) - }) - return _c -} - -func (_c *FluxAggregator_Version_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_Version_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_Version_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *FluxAggregator_Version_Call { - _c.Call.Return(run) - return _c -} - -// WatchAnswerUpdated provides a mock function with given fields: opts, sink, current, roundId -func (_m *FluxAggregator) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, current, roundId) - - if len(ret) == 0 { - panic("no return value specified for WatchAnswerUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, current, roundId) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, current, roundId) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) error); ok { - r1 = rf(opts, sink, current, roundId) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchAnswerUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAnswerUpdated' -type FluxAggregator_WatchAnswerUpdated_Call struct { - *mock.Call -} - -// WatchAnswerUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated -// - current []*big.Int -// - roundId []*big.Int -func (_e *FluxAggregator_Expecter) WatchAnswerUpdated(opts interface{}, sink interface{}, current interface{}, roundId interface{}) *FluxAggregator_WatchAnswerUpdated_Call { - return &FluxAggregator_WatchAnswerUpdated_Call{Call: _e.mock.On("WatchAnswerUpdated", opts, sink, current, roundId)} -} - -func (_c *FluxAggregator_WatchAnswerUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int)) *FluxAggregator_WatchAnswerUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated), args[2].([]*big.Int), args[3].([]*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_WatchAnswerUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchAnswerUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchAnswerUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) (event.Subscription, error)) *FluxAggregator_WatchAnswerUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WatchAvailableFundsUpdated provides a mock function with given fields: opts, sink, amount -func (_m *FluxAggregator) WatchAvailableFundsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, amount []*big.Int) (event.Subscription, error) { - ret := _m.Called(opts, sink, amount) - - if len(ret) == 0 { - panic("no return value specified for WatchAvailableFundsUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) (event.Subscription, error)); ok { - return rf(opts, sink, amount) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) event.Subscription); ok { - r0 = rf(opts, sink, amount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) error); ok { - r1 = rf(opts, sink, amount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchAvailableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAvailableFundsUpdated' -type FluxAggregator_WatchAvailableFundsUpdated_Call struct { - *mock.Call -} - -// WatchAvailableFundsUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated -// - amount []*big.Int -func (_e *FluxAggregator_Expecter) WatchAvailableFundsUpdated(opts interface{}, sink interface{}, amount interface{}) *FluxAggregator_WatchAvailableFundsUpdated_Call { - return &FluxAggregator_WatchAvailableFundsUpdated_Call{Call: _e.mock.On("WatchAvailableFundsUpdated", opts, sink, amount)} -} - -func (_c *FluxAggregator_WatchAvailableFundsUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, amount []*big.Int)) *FluxAggregator_WatchAvailableFundsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated), args[2].([]*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_WatchAvailableFundsUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchAvailableFundsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchAvailableFundsUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) (event.Subscription, error)) *FluxAggregator_WatchAvailableFundsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WatchNewRound provides a mock function with given fields: opts, sink, roundId, startedBy -func (_m *FluxAggregator) WatchNewRound(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, roundId []*big.Int, startedBy []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, roundId, startedBy) - - if len(ret) == 0 { - panic("no return value specified for WatchNewRound") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, roundId, startedBy) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, roundId, startedBy) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) error); ok { - r1 = rf(opts, sink, roundId, startedBy) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchNewRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNewRound' -type FluxAggregator_WatchNewRound_Call struct { - *mock.Call -} - -// WatchNewRound is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound -// - roundId []*big.Int -// - startedBy []common.Address -func (_e *FluxAggregator_Expecter) WatchNewRound(opts interface{}, sink interface{}, roundId interface{}, startedBy interface{}) *FluxAggregator_WatchNewRound_Call { - return &FluxAggregator_WatchNewRound_Call{Call: _e.mock.On("WatchNewRound", opts, sink, roundId, startedBy)} -} - -func (_c *FluxAggregator_WatchNewRound_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, roundId []*big.Int, startedBy []common.Address)) *FluxAggregator_WatchNewRound_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound), args[2].([]*big.Int), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchNewRound_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchNewRound_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchNewRound_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchNewRound_Call { - _c.Call.Return(run) - return _c -} - -// WatchOracleAdminUpdateRequested provides a mock function with given fields: opts, sink, oracle -func (_m *FluxAggregator) WatchOracleAdminUpdateRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, oracle []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, oracle) - - if len(ret) == 0 { - panic("no return value specified for WatchOracleAdminUpdateRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, oracle) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) error); ok { - r1 = rf(opts, sink, oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchOracleAdminUpdateRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOracleAdminUpdateRequested' -type FluxAggregator_WatchOracleAdminUpdateRequested_Call struct { - *mock.Call -} - -// WatchOracleAdminUpdateRequested is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested -// - oracle []common.Address -func (_e *FluxAggregator_Expecter) WatchOracleAdminUpdateRequested(opts interface{}, sink interface{}, oracle interface{}) *FluxAggregator_WatchOracleAdminUpdateRequested_Call { - return &FluxAggregator_WatchOracleAdminUpdateRequested_Call{Call: _e.mock.On("WatchOracleAdminUpdateRequested", opts, sink, oracle)} -} - -func (_c *FluxAggregator_WatchOracleAdminUpdateRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, oracle []common.Address)) *FluxAggregator_WatchOracleAdminUpdateRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchOracleAdminUpdateRequested_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchOracleAdminUpdateRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchOracleAdminUpdateRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchOracleAdminUpdateRequested_Call { - _c.Call.Return(run) - return _c -} - -// WatchOracleAdminUpdated provides a mock function with given fields: opts, sink, oracle, newAdmin -func (_m *FluxAggregator) WatchOracleAdminUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, oracle []common.Address, newAdmin []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, oracle, newAdmin) - - if len(ret) == 0 { - panic("no return value specified for WatchOracleAdminUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, oracle, newAdmin) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, oracle, newAdmin) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, oracle, newAdmin) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchOracleAdminUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOracleAdminUpdated' -type FluxAggregator_WatchOracleAdminUpdated_Call struct { - *mock.Call -} - -// WatchOracleAdminUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated -// - oracle []common.Address -// - newAdmin []common.Address -func (_e *FluxAggregator_Expecter) WatchOracleAdminUpdated(opts interface{}, sink interface{}, oracle interface{}, newAdmin interface{}) *FluxAggregator_WatchOracleAdminUpdated_Call { - return &FluxAggregator_WatchOracleAdminUpdated_Call{Call: _e.mock.On("WatchOracleAdminUpdated", opts, sink, oracle, newAdmin)} -} - -func (_c *FluxAggregator_WatchOracleAdminUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, oracle []common.Address, newAdmin []common.Address)) *FluxAggregator_WatchOracleAdminUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated), args[2].([]common.Address), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchOracleAdminUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchOracleAdminUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchOracleAdminUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchOracleAdminUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WatchOraclePermissionsUpdated provides a mock function with given fields: opts, sink, oracle, whitelisted -func (_m *FluxAggregator) WatchOraclePermissionsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, oracle []common.Address, whitelisted []bool) (event.Subscription, error) { - ret := _m.Called(opts, sink, oracle, whitelisted) - - if len(ret) == 0 { - panic("no return value specified for WatchOraclePermissionsUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) (event.Subscription, error)); ok { - return rf(opts, sink, oracle, whitelisted) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) event.Subscription); ok { - r0 = rf(opts, sink, oracle, whitelisted) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) error); ok { - r1 = rf(opts, sink, oracle, whitelisted) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchOraclePermissionsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOraclePermissionsUpdated' -type FluxAggregator_WatchOraclePermissionsUpdated_Call struct { - *mock.Call -} - -// WatchOraclePermissionsUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated -// - oracle []common.Address -// - whitelisted []bool -func (_e *FluxAggregator_Expecter) WatchOraclePermissionsUpdated(opts interface{}, sink interface{}, oracle interface{}, whitelisted interface{}) *FluxAggregator_WatchOraclePermissionsUpdated_Call { - return &FluxAggregator_WatchOraclePermissionsUpdated_Call{Call: _e.mock.On("WatchOraclePermissionsUpdated", opts, sink, oracle, whitelisted)} -} - -func (_c *FluxAggregator_WatchOraclePermissionsUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, oracle []common.Address, whitelisted []bool)) *FluxAggregator_WatchOraclePermissionsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated), args[2].([]common.Address), args[3].([]bool)) - }) - return _c -} - -func (_c *FluxAggregator_WatchOraclePermissionsUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchOraclePermissionsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchOraclePermissionsUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) (event.Subscription, error)) *FluxAggregator_WatchOraclePermissionsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to -func (_m *FluxAggregator) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferRequested") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested' -type FluxAggregator_WatchOwnershipTransferRequested_Call struct { - *mock.Call -} - -// WatchOwnershipTransferRequested is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested -// - from []common.Address -// - to []common.Address -func (_e *FluxAggregator_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *FluxAggregator_WatchOwnershipTransferRequested_Call { - return &FluxAggregator_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)} -} - -func (_c *FluxAggregator_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, from []common.Address, to []common.Address)) *FluxAggregator_WatchOwnershipTransferRequested_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchOwnershipTransferRequested_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchOwnershipTransferRequested_Call { - _c.Call.Return(run) - return _c -} - -// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to -func (_m *FluxAggregator) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, from, to) - - if len(ret) == 0 { - panic("no return value specified for WatchOwnershipTransferred") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, from, to) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, from, to) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, from, to) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred' -type FluxAggregator_WatchOwnershipTransferred_Call struct { - *mock.Call -} - -// WatchOwnershipTransferred is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred -// - from []common.Address -// - to []common.Address -func (_e *FluxAggregator_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *FluxAggregator_WatchOwnershipTransferred_Call { - return &FluxAggregator_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)} -} - -func (_c *FluxAggregator_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, from []common.Address, to []common.Address)) *FluxAggregator_WatchOwnershipTransferred_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchOwnershipTransferred_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchOwnershipTransferred_Call { - _c.Call.Return(run) - return _c -} - -// WatchRequesterPermissionsSet provides a mock function with given fields: opts, sink, requester -func (_m *FluxAggregator) WatchRequesterPermissionsSet(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, requester []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, requester) - - if len(ret) == 0 { - panic("no return value specified for WatchRequesterPermissionsSet") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, requester) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, requester) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) error); ok { - r1 = rf(opts, sink, requester) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchRequesterPermissionsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchRequesterPermissionsSet' -type FluxAggregator_WatchRequesterPermissionsSet_Call struct { - *mock.Call -} - -// WatchRequesterPermissionsSet is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet -// - requester []common.Address -func (_e *FluxAggregator_Expecter) WatchRequesterPermissionsSet(opts interface{}, sink interface{}, requester interface{}) *FluxAggregator_WatchRequesterPermissionsSet_Call { - return &FluxAggregator_WatchRequesterPermissionsSet_Call{Call: _e.mock.On("WatchRequesterPermissionsSet", opts, sink, requester)} -} - -func (_c *FluxAggregator_WatchRequesterPermissionsSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, requester []common.Address)) *FluxAggregator_WatchRequesterPermissionsSet_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet), args[2].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchRequesterPermissionsSet_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchRequesterPermissionsSet_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchRequesterPermissionsSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchRequesterPermissionsSet_Call { - _c.Call.Return(run) - return _c -} - -// WatchRoundDetailsUpdated provides a mock function with given fields: opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount -func (_m *FluxAggregator) WatchRoundDetailsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (event.Subscription, error) { - ret := _m.Called(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) - - if len(ret) == 0 { - panic("no return value specified for WatchRoundDetailsUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) (event.Subscription, error)); ok { - return rf(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) event.Subscription); ok { - r0 = rf(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) error); ok { - r1 = rf(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchRoundDetailsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchRoundDetailsUpdated' -type FluxAggregator_WatchRoundDetailsUpdated_Call struct { - *mock.Call -} - -// WatchRoundDetailsUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated -// - paymentAmount []*big.Int -// - minSubmissionCount []uint32 -// - maxSubmissionCount []uint32 -func (_e *FluxAggregator_Expecter) WatchRoundDetailsUpdated(opts interface{}, sink interface{}, paymentAmount interface{}, minSubmissionCount interface{}, maxSubmissionCount interface{}) *FluxAggregator_WatchRoundDetailsUpdated_Call { - return &FluxAggregator_WatchRoundDetailsUpdated_Call{Call: _e.mock.On("WatchRoundDetailsUpdated", opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount)} -} - -func (_c *FluxAggregator_WatchRoundDetailsUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32)) *FluxAggregator_WatchRoundDetailsUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated), args[2].([]*big.Int), args[3].([]uint32), args[4].([]uint32)) - }) - return _c -} - -func (_c *FluxAggregator_WatchRoundDetailsUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchRoundDetailsUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchRoundDetailsUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) (event.Subscription, error)) *FluxAggregator_WatchRoundDetailsUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WatchSubmissionReceived provides a mock function with given fields: opts, sink, submission, round, oracle -func (_m *FluxAggregator) WatchSubmissionReceived(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, submission []*big.Int, round []uint32, oracle []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, submission, round, oracle) - - if len(ret) == 0 { - panic("no return value specified for WatchSubmissionReceived") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, submission, round, oracle) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, submission, round, oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) error); ok { - r1 = rf(opts, sink, submission, round, oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchSubmissionReceived_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSubmissionReceived' -type FluxAggregator_WatchSubmissionReceived_Call struct { - *mock.Call -} - -// WatchSubmissionReceived is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived -// - submission []*big.Int -// - round []uint32 -// - oracle []common.Address -func (_e *FluxAggregator_Expecter) WatchSubmissionReceived(opts interface{}, sink interface{}, submission interface{}, round interface{}, oracle interface{}) *FluxAggregator_WatchSubmissionReceived_Call { - return &FluxAggregator_WatchSubmissionReceived_Call{Call: _e.mock.On("WatchSubmissionReceived", opts, sink, submission, round, oracle)} -} - -func (_c *FluxAggregator_WatchSubmissionReceived_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, submission []*big.Int, round []uint32, oracle []common.Address)) *FluxAggregator_WatchSubmissionReceived_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived), args[2].([]*big.Int), args[3].([]uint32), args[4].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchSubmissionReceived_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchSubmissionReceived_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchSubmissionReceived_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchSubmissionReceived_Call { - _c.Call.Return(run) - return _c -} - -// WatchValidatorUpdated provides a mock function with given fields: opts, sink, previous, current -func (_m *FluxAggregator) WatchValidatorUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, previous []common.Address, current []common.Address) (event.Subscription, error) { - ret := _m.Called(opts, sink, previous, current) - - if len(ret) == 0 { - panic("no return value specified for WatchValidatorUpdated") - } - - var r0 event.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { - return rf(opts, sink, previous, current) - } - if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) event.Subscription); ok { - r0 = rf(opts, sink, previous, current) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(event.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) error); ok { - r1 = rf(opts, sink, previous, current) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WatchValidatorUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchValidatorUpdated' -type FluxAggregator_WatchValidatorUpdated_Call struct { - *mock.Call -} - -// WatchValidatorUpdated is a helper method to define mock.On call -// - opts *bind.WatchOpts -// - sink chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated -// - previous []common.Address -// - current []common.Address -func (_e *FluxAggregator_Expecter) WatchValidatorUpdated(opts interface{}, sink interface{}, previous interface{}, current interface{}) *FluxAggregator_WatchValidatorUpdated_Call { - return &FluxAggregator_WatchValidatorUpdated_Call{Call: _e.mock.On("WatchValidatorUpdated", opts, sink, previous, current)} -} - -func (_c *FluxAggregator_WatchValidatorUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, previous []common.Address, current []common.Address)) *FluxAggregator_WatchValidatorUpdated_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.WatchOpts), args[1].(chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated), args[2].([]common.Address), args[3].([]common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WatchValidatorUpdated_Call) Return(_a0 event.Subscription, _a1 error) *FluxAggregator_WatchValidatorUpdated_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WatchValidatorUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) (event.Subscription, error)) *FluxAggregator_WatchValidatorUpdated_Call { - _c.Call.Return(run) - return _c -} - -// WithdrawFunds provides a mock function with given fields: opts, _recipient, _amount -func (_m *FluxAggregator) WithdrawFunds(opts *bind.TransactOpts, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, _recipient, _amount) - - if len(ret) == 0 { - panic("no return value specified for WithdrawFunds") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, _recipient, _amount) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok { - r0 = rf(opts, _recipient, _amount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok { - r1 = rf(opts, _recipient, _amount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WithdrawFunds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawFunds' -type FluxAggregator_WithdrawFunds_Call struct { - *mock.Call -} - -// WithdrawFunds is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _recipient common.Address -// - _amount *big.Int -func (_e *FluxAggregator_Expecter) WithdrawFunds(opts interface{}, _recipient interface{}, _amount interface{}) *FluxAggregator_WithdrawFunds_Call { - return &FluxAggregator_WithdrawFunds_Call{Call: _e.mock.On("WithdrawFunds", opts, _recipient, _amount)} -} - -func (_c *FluxAggregator_WithdrawFunds_Call) Run(run func(opts *bind.TransactOpts, _recipient common.Address, _amount *big.Int)) *FluxAggregator_WithdrawFunds_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_WithdrawFunds_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_WithdrawFunds_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WithdrawFunds_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)) *FluxAggregator_WithdrawFunds_Call { - _c.Call.Return(run) - return _c -} - -// WithdrawPayment provides a mock function with given fields: opts, _oracle, _recipient, _amount -func (_m *FluxAggregator) WithdrawPayment(opts *bind.TransactOpts, _oracle common.Address, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { - ret := _m.Called(opts, _oracle, _recipient, _amount) - - if len(ret) == 0 { - panic("no return value specified for WithdrawPayment") - } - - var r0 *types.Transaction - var r1 error - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)); ok { - return rf(opts, _oracle, _recipient, _amount) - } - if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) *types.Transaction); ok { - r0 = rf(opts, _oracle, _recipient, _amount) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Transaction) - } - } - - if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) error); ok { - r1 = rf(opts, _oracle, _recipient, _amount) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WithdrawPayment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawPayment' -type FluxAggregator_WithdrawPayment_Call struct { - *mock.Call -} - -// WithdrawPayment is a helper method to define mock.On call -// - opts *bind.TransactOpts -// - _oracle common.Address -// - _recipient common.Address -// - _amount *big.Int -func (_e *FluxAggregator_Expecter) WithdrawPayment(opts interface{}, _oracle interface{}, _recipient interface{}, _amount interface{}) *FluxAggregator_WithdrawPayment_Call { - return &FluxAggregator_WithdrawPayment_Call{Call: _e.mock.On("WithdrawPayment", opts, _oracle, _recipient, _amount)} -} - -func (_c *FluxAggregator_WithdrawPayment_Call) Run(run func(opts *bind.TransactOpts, _oracle common.Address, _recipient common.Address, _amount *big.Int)) *FluxAggregator_WithdrawPayment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(*big.Int)) - }) - return _c -} - -func (_c *FluxAggregator_WithdrawPayment_Call) Return(_a0 *types.Transaction, _a1 error) *FluxAggregator_WithdrawPayment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WithdrawPayment_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)) *FluxAggregator_WithdrawPayment_Call { - _c.Call.Return(run) - return _c -} - -// WithdrawablePayment provides a mock function with given fields: opts, _oracle -func (_m *FluxAggregator) WithdrawablePayment(opts *bind.CallOpts, _oracle common.Address) (*big.Int, error) { - ret := _m.Called(opts, _oracle) - - if len(ret) == 0 { - panic("no return value specified for WithdrawablePayment") - } - - var r0 *big.Int - var r1 error - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { - return rf(opts, _oracle) - } - if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok { - r0 = rf(opts, _oracle) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*big.Int) - } - } - - if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok { - r1 = rf(opts, _oracle) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FluxAggregator_WithdrawablePayment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawablePayment' -type FluxAggregator_WithdrawablePayment_Call struct { - *mock.Call -} - -// WithdrawablePayment is a helper method to define mock.On call -// - opts *bind.CallOpts -// - _oracle common.Address -func (_e *FluxAggregator_Expecter) WithdrawablePayment(opts interface{}, _oracle interface{}) *FluxAggregator_WithdrawablePayment_Call { - return &FluxAggregator_WithdrawablePayment_Call{Call: _e.mock.On("WithdrawablePayment", opts, _oracle)} -} - -func (_c *FluxAggregator_WithdrawablePayment_Call) Run(run func(opts *bind.CallOpts, _oracle common.Address)) *FluxAggregator_WithdrawablePayment_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*bind.CallOpts), args[1].(common.Address)) - }) - return _c -} - -func (_c *FluxAggregator_WithdrawablePayment_Call) Return(_a0 *big.Int, _a1 error) *FluxAggregator_WithdrawablePayment_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *FluxAggregator_WithdrawablePayment_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (*big.Int, error)) *FluxAggregator_WithdrawablePayment_Call { - _c.Call.Return(run) - return _c -} - -// NewFluxAggregator creates a new instance of FluxAggregator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewFluxAggregator(t interface { - mock.TestingT - Cleanup(func()) -}) *FluxAggregator { - mock := &FluxAggregator{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 83922a84f5b..cbec9fb63c8 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -61,9 +61,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/cre" "github.com/smartcontractkit/chainlink/v2/core/services/cresettings" "github.com/smartcontractkit/chainlink/v2/core/services/cron" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" "github.com/smartcontractkit/chainlink/v2/core/services/feeds" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/headreporter" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -556,12 +554,7 @@ func NewApplication(ctx context.Context, opts ApplicationOpts) (Application, err var ( delegates = map[job.Type]job.Delegate{ - job.DirectRequest: directrequest.NewDelegate( - globalLogger, - pipelineRunner, - pipelineORM, - legacyEVMChains, - mailMon), + job.DirectRequest: &job.DeprecatedDelegate{Type: job.DirectRequest}, job.VRF: vrf.NewDelegate( opts.DS, keyStore, @@ -630,21 +623,9 @@ func NewApplication(ctx context.Context, opts ApplicationOpts) (Application, err workflows.WithWorkflowRegistry(cfg.Capabilities().WorkflowRegistry().Address(), cfg.Capabilities().WorkflowRegistry().ChainID()), ) - // Flux monitor requires ethereum just to boot, silence errors with a null delegate - if !cfg.EVMConfigs().RPCEnabled() { - delegates[job.FluxMonitor] = &job.NullDelegate{Type: job.FluxMonitor} - } else { - delegates[job.FluxMonitor] = fluxmonitorv2.NewDelegate( - cfg, - keyStore.Eth(), - jobORM, - pipelineORM, - pipelineRunner, - opts.DS, - legacyEVMChains, - globalLogger, - ) - } + // FluxMonitor has been removed; use a deprecated delegate so existing jobs + // surface a visible error in the UI rather than silently doing nothing. + delegates[job.FluxMonitor] = &job.DeprecatedDelegate{Type: job.FluxMonitor} delegates[job.CRESettings] = cresettings.NewDelegate(globalLogger, atomicSettings) diff --git a/core/services/chainlink/config_flux_monitor.go b/core/services/chainlink/config_flux_monitor.go deleted file mode 100644 index ccf72c93b34..00000000000 --- a/core/services/chainlink/config_flux_monitor.go +++ /dev/null @@ -1,15 +0,0 @@ -package chainlink - -import "github.com/smartcontractkit/chainlink/v2/core/config/toml" - -type fluxMonitorConfig struct { - c toml.FluxMonitor -} - -func (f *fluxMonitorConfig) DefaultTransactionQueueDepth() uint32 { - return *f.c.DefaultTransactionQueueDepth -} - -func (f *fluxMonitorConfig) SimulateTransactions() bool { - return *f.c.SimulateTransactions -} diff --git a/core/services/chainlink/config_flux_monitor_test.go b/core/services/chainlink/config_flux_monitor_test.go deleted file mode 100644 index 673c4465db7..00000000000 --- a/core/services/chainlink/config_flux_monitor_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package chainlink - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestFluxMonitorConfig(t *testing.T) { - opts := GeneralConfigOpts{ - ConfigStrings: []string{fullTOML}, - } - cfg, err := opts.New() - require.NoError(t, err) - - fm := cfg.FluxMonitor() - - assert.Equal(t, uint32(100), fm.DefaultTransactionQueueDepth()) - assert.True(t, fm.SimulateTransactions()) -} diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 3eb77367607..b4f829fd863 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -18,7 +18,6 @@ import ( "github.com/smartcontractkit/chainlink-common/keystore/corekeys" "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/config/parse" @@ -294,7 +293,7 @@ func (g *generalConfig) FeatureFeedsManager() bool { return *g.c.Feature.FeedsManager } -func (g *generalConfig) OCR() config.OCR { +func (g *generalConfig) OCR() coreconfig.OCR { return &ocrConfig{c: g.c.OCR} } @@ -310,7 +309,7 @@ func (g *generalConfig) FeatureUICSAKeys() bool { return *g.c.Feature.UICSAKeys } -func (g *generalConfig) AutoPprof() config.AutoPprof { +func (g *generalConfig) AutoPprof() coreconfig.AutoPprof { return &autoPprofConfig{c: g.c.AutoPprof, rootDir: g.RootDir} } @@ -381,7 +380,7 @@ func (g *generalConfig) SuiEnabled() bool { return false } -func (g *generalConfig) WebServer() config.WebServer { +func (g *generalConfig) WebServer() coreconfig.WebServer { return &webServerConfig{c: g.c.WebServer, s: g.secrets.WebServer, rootDir: g.RootDir} } @@ -433,11 +432,11 @@ func (g *generalConfig) AutoPprofProfileRoot() string { return s } -func (g *generalConfig) Capabilities() config.Capabilities { +func (g *generalConfig) Capabilities() coreconfig.Capabilities { return &capabilitiesConfig{c: g.c.Capabilities} } -func (g *generalConfig) Workflows() config.Workflows { +func (g *generalConfig) Workflows() coreconfig.Workflows { return &workflowsConfig{c: g.c.Workflows} } @@ -449,10 +448,6 @@ func (g *generalConfig) ShutdownGracePeriod() time.Duration { return g.c.ShutdownGracePeriod.Duration() } -func (g *generalConfig) FluxMonitor() config.FluxMonitor { - return &fluxMonitorConfig{c: g.c.FluxMonitor} -} - func (g *generalConfig) InsecureFastScrypt() bool { return *g.c.InsecureFastScrypt } @@ -469,15 +464,15 @@ func (g *generalConfig) JobPipeline() coreconfig.JobPipeline { return &jobPipelineConfig{c: g.c.JobPipeline} } -func (g *generalConfig) Log() config.Log { +func (g *generalConfig) Log() coreconfig.Log { return &logConfig{c: g.c.Log, rootDir: g.RootDir, level: g.logLevel, defaultLevel: g.logLevelDefault} } -func (g *generalConfig) OCR2() config.OCR2 { +func (g *generalConfig) OCR2() coreconfig.OCR2 { return &ocr2Config{c: g.c.OCR2} } -func (g *generalConfig) P2P() config.P2P { +func (g *generalConfig) P2P() coreconfig.P2P { return &p2p{c: g.c.P2P} } @@ -497,7 +492,7 @@ func (g *generalConfig) P2POutgoingMessageBufferSize() int { return int(*g.c.P2P.OutgoingMessageBufferSize) } -func (g *generalConfig) Pyroscope() config.Pyroscope { +func (g *generalConfig) Pyroscope() coreconfig.Pyroscope { return &pyroscopeConfig{c: g.c.Pyroscope, s: g.secrets.Pyroscope} } @@ -520,7 +515,7 @@ func (g *generalConfig) AuditLogger() coreconfig.AuditLogger { return auditLoggerConfig{c: g.c.AuditLogger} } -func (g *generalConfig) Insecure() config.Insecure { +func (g *generalConfig) Insecure() coreconfig.Insecure { return &insecureConfig{c: g.c.Insecure} } diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index e15be99bcb2..38226092c68 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -45,10 +45,6 @@ var ( //go:embed testdata/config-multi-chain.toml multiChainTOML string - second = *commoncfg.MustNewDuration(time.Second) - minute = *commoncfg.MustNewDuration(time.Minute) - selectionMode = multinode.NodeSelectionModeHighestHead - multiChain = Config{ Core: toml.Core{ RootDir: ptr("my/root/dir"), @@ -352,9 +348,9 @@ func TestConfig_Marshal(t *testing.T) { DefaultTimeout: commoncfg.MustNewDuration(time.Minute), }, } - full.FluxMonitor = toml.FluxMonitor{ - DefaultTransactionQueueDepth: ptr[uint32](100), - SimulateTransactions: ptr(true), + full.FluxMonitor = toml.FluxMonitor{ //nolint:staticcheck // deprecated config surface must match embedded config-full.toml + DefaultTransactionQueueDepth: ptr[uint32](1), + SimulateTransactions: ptr(false), } full.OCR2 = toml.OCR2{ Enabled: ptr(true), @@ -975,10 +971,6 @@ Host = 'tls-host' HTTPSPort = 6789 KeyPath = 'tls/key/path' ListenIP = '192.158.1.38' -`}, - {"FluxMonitor", Config{Core: toml.Core{FluxMonitor: full.FluxMonitor}}, `[FluxMonitor] -DefaultTransactionQueueDepth = 100 -SimulateTransactions = true `}, {"JobPipeline", Config{Core: toml.Core{JobPipeline: full.JobPipeline}}, `[JobPipeline] ExternalInitiatorsEnabled = true @@ -1608,10 +1600,10 @@ Dev = true` func TestNewGeneralConfig_SecretsOverrides(t *testing.T) { // Provide a keystore password file and an env var with DB URL - const PWD_OVERRIDE = "great_password" - const DBURL_OVERRIDE = "http://user@db" + const pwdOverride = "great_password" + const dbURLOverride = "http://user@db" - t.Setenv("CL_DATABASE_URL", DBURL_OVERRIDE) + t.Setenv("CL_DATABASE_URL", dbURLOverride) // Check for two overrides opts := GeneralConfigOpts{ @@ -1619,11 +1611,11 @@ func TestNewGeneralConfig_SecretsOverrides(t *testing.T) { SecretsStrings: []string{secretsFullTOML}, } c, err := opts.New() - assert.NoError(t, err) - c.SetPasswords(ptr(PWD_OVERRIDE), nil) - assert.Equal(t, PWD_OVERRIDE, c.Password().Keystore()) + require.NoError(t, err) + c.SetPasswords(ptr(pwdOverride), nil) + assert.Equal(t, pwdOverride, c.Password().Keystore()) dbURL := c.Database().URL() - assert.Equal(t, DBURL_OVERRIDE, (&dbURL).String()) + assert.Equal(t, dbURLOverride, (&dbURL).String()) } func TestSecrets_Validate(t *testing.T) { @@ -1698,22 +1690,23 @@ func TestConfig_setDefaults(t *testing.T) { c.Starknet = RawConfigs{{"ChainID": ptr("unknown starknet chain")}} c.setDefaults() - if s, err := c.TOMLString(); assert.NoError(t, err) { - t.Log(s, err) - } + s, err := c.TOMLString() + require.NoError(t, err) + t.Log(s) + configtest.AssertFieldsNotNil(t, c.Core) } func Test_validateEnv(t *testing.T) { t.Setenv("LOG_LEVEL", "warn") t.Setenv("DATABASE_URL", "foo") - assert.ErrorContains(t, validateEnv(), `invalid environment: 2 errors: + require.ErrorContains(t, validateEnv(), `invalid environment: 2 errors: - environment variable DATABASE_URL must not be set: unsupported with config v2 - environment variable LOG_LEVEL must not be set: unsupported with config v2`) t.Setenv("GAS_UPDATER_ENABLED", "true") t.Setenv("ETH_GAS_BUMP_TX_DEPTH", "7") - assert.ErrorContains(t, validateEnv(), `invalid environment: 4 errors: + require.ErrorContains(t, validateEnv(), `invalid environment: 4 errors: - environment variable DATABASE_URL must not be set: unsupported with config v2 - environment variable LOG_LEVEL must not be set: unsupported with config v2 - environment variable ETH_GAS_BUMP_TX_DEPTH must not be set: unsupported with config v2 diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index a7fbb69d415..78be444b126 100644 --- a/core/services/chainlink/mocks/general_config.go +++ b/core/services/chainlink/mocks/general_config.go @@ -827,53 +827,6 @@ func (_c *GeneralConfig_Feature_Call) RunAndReturn(run func() config.Feature) *G return _c } -// FluxMonitor provides a mock function with no fields -func (_m *GeneralConfig) FluxMonitor() config.FluxMonitor { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for FluxMonitor") - } - - var r0 config.FluxMonitor - if rf, ok := ret.Get(0).(func() config.FluxMonitor); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(config.FluxMonitor) - } - } - - return r0 -} - -// GeneralConfig_FluxMonitor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FluxMonitor' -type GeneralConfig_FluxMonitor_Call struct { - *mock.Call -} - -// FluxMonitor is a helper method to define mock.On call -func (_e *GeneralConfig_Expecter) FluxMonitor() *GeneralConfig_FluxMonitor_Call { - return &GeneralConfig_FluxMonitor_Call{Call: _e.mock.On("FluxMonitor")} -} - -func (_c *GeneralConfig_FluxMonitor_Call) Run(run func()) *GeneralConfig_FluxMonitor_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *GeneralConfig_FluxMonitor_Call) Return(_a0 config.FluxMonitor) *GeneralConfig_FluxMonitor_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *GeneralConfig_FluxMonitor_Call) RunAndReturn(run func() config.FluxMonitor) *GeneralConfig_FluxMonitor_Call { - _c.Call.Return(run) - return _c -} - // ImportedAptosKeys provides a mock function with no fields func (_m *GeneralConfig) ImportedAptosKeys() config.ImportableChainKeyLister { ret := _m.Called() diff --git a/core/services/chainlink/node_platform_test.go b/core/services/chainlink/node_platform_test.go index 324f1933178..635bc920661 100644 --- a/core/services/chainlink/node_platform_test.go +++ b/core/services/chainlink/node_platform_test.go @@ -194,17 +194,6 @@ func TestNodePlatformJobInfo_EmitsSubmitterAddressesFromJobFields(t *testing.T) }, }, }, - { - Type: job.DirectRequest, - DirectRequestSpec: &job.DirectRequestSpec{ - EVMChainID: sqlutil.NewI(9), - }, - Pipeline: pipeline.Pipeline{Tasks: []pipeline.Task{ - &pipeline.ETHTxTask{ - From: "[\"0xcccccccccccccccccccccccccccccccccccccccc\", \"0xdddddddddddddddddddddddddddddddddddddddd\"]", - }, - }}, - }, }, }, })) @@ -285,15 +274,6 @@ func TestNodePlatformJobInfo_EmitsSubmitterAddressesFromJobFields(t *testing.T) FieldPath: "oracle_factory.transmitter_id", Addresses: []string{"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, }, - { - ChainId: "9", - JobType: "directrequest", - FieldPath: "observationSource.ethtx.from", - Addresses: []string{ - "0xcccccccccccccccccccccccccccccccccccccccc", - "0xdddddddddddddddddddddddddddddddddddddddd", - }, - }, }, } require.Truef(t, proto.Equal(expected, &payload), "expected:\n%sgot:\n%s", prototext.Format(expected), prototext.Format(&payload)) @@ -304,8 +284,8 @@ func TestNodePlatformJobInfo_PaginatesSubmitterAddressJobs(t *testing.T) { jobs := make([]job.Job, 1001) jobs[1000] = job.Job{ - Type: job.DirectRequest, - DirectRequestSpec: &job.DirectRequestSpec{ + Type: job.VRF, + VRFSpec: &job.VRFSpec{ EVMChainID: sqlutil.NewI(10), }, Pipeline: pipeline.Pipeline{Tasks: []pipeline.Task{ @@ -334,7 +314,7 @@ func TestNodePlatformJobInfo_PaginatesSubmitterAddressJobs(t *testing.T) { for _, submitterAddress := range payload.SubmitterAddresses { if submitterAddress.ChainId == "10" && - submitterAddress.JobType == "directrequest" && + submitterAddress.JobType == "vrf" && submitterAddress.FieldPath == "observationSource.ethtx.from" && len(submitterAddress.Addresses) == 1 && submitterAddress.Addresses[0] == "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" { diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 7583f0ec595..f2bd2b9ea47 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -149,8 +149,8 @@ DefaultTimeout = '1m0s' MaxSize = '100.00mb' [FluxMonitor] -DefaultTransactionQueueDepth = 100 -SimulateTransactions = true +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false [OCR2] Enabled = true diff --git a/core/services/chainlink/types.go b/core/services/chainlink/types.go index ea7f196461c..c10be813ee9 100644 --- a/core/services/chainlink/types.go +++ b/core/services/chainlink/types.go @@ -2,12 +2,11 @@ package chainlink import ( "github.com/smartcontractkit/chainlink-evm/pkg/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" ) type GeneralConfig interface { - config.AppConfig + coreconfig.AppConfig toml.HasEVMConfigs CosmosConfigs() RawConfigs SolanaConfigs() RawConfigs diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go deleted file mode 100644 index d842302c98d..00000000000 --- a/core/services/directrequest/delegate.go +++ /dev/null @@ -1,426 +0,0 @@ -package directrequest - -import ( - "context" - stderrors "errors" - "fmt" - "reflect" - "slices" - "strconv" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/operatorforwarder/generated/operator" - "github.com/smartcontractkit/chainlink-evm/pkg/chains/legacyevm" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - evmtypes "github.com/smartcontractkit/chainlink-evm/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -type ( - Delegate struct { - logger logger.Logger - pipelineRunner pipeline.Runner - pipelineORM pipeline.ORM - chHeads chan *evmtypes.Head - legacyChains legacyevm.LegacyChainContainer - mailMon *mailbox.Monitor - } - - Config interface { - MinIncomingConfirmations() uint32 - MinContractPayment() *assets.Link - } -) - -var _ job.Delegate = (*Delegate)(nil) - -func NewDelegate( - logger logger.Logger, - pipelineRunner pipeline.Runner, - pipelineORM pipeline.ORM, - legacyChains legacyevm.LegacyChainContainer, - mailMon *mailbox.Monitor, -) *Delegate { - return &Delegate{ - logger: logger.Named("DirectRequest"), - pipelineRunner: pipelineRunner, - pipelineORM: pipelineORM, - chHeads: make(chan *evmtypes.Head, 1), - legacyChains: legacyChains, - mailMon: mailMon, - } -} - -func (d *Delegate) JobType() job.Type { - return job.DirectRequest -} - -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } - -// ServicesForSpec returns the log listener service for a direct request job -func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.ServiceCtx, error) { - if jb.DirectRequestSpec == nil { - return nil, errors.Errorf("DirectRequest: directrequest.Delegate expects a *job.DirectRequestSpec to be present, got %v", jb) - } - chainService, err := d.legacyChains.Get(jb.DirectRequestSpec.EVMChainID.String()) - if err != nil { - return nil, err - } - chain, ok := chainService.(legacyevm.Chain) - if !ok { - return nil, fmt.Errorf("directrequest is not available in LOOP Plugin mode: %w", stderrors.ErrUnsupported) - } - - concreteSpec := job.SetDRMinIncomingConfirmations(chain.Config().EVM().MinIncomingConfirmations(), *jb.DirectRequestSpec) - - oracle, err := operator.NewOperator(concreteSpec.ContractAddress.Address(), chain.Client()) - if err != nil { - return nil, errors.Wrapf(err, "DirectRequest: failed to create an operator wrapper for address: %v", concreteSpec.ContractAddress.Address().String()) - } - - svcLogger := d.logger.Named(jb.ExternalJobID.String()). - With( - "contract", concreteSpec.ContractAddress.Address().String(), - "jobName", jb.PipelineSpec.JobName, - "jobID", jb.PipelineSpec.JobID, - "externalJobID", jb.ExternalJobID, - ) - - logListener := &listener{ - logger: svcLogger.Named("Listener"), - config: chain.Config().EVM(), - logBroadcaster: chain.LogBroadcaster(), - oracle: oracle, - pipelineRunner: d.pipelineRunner, - pipelineORM: d.pipelineORM, - mailMon: d.mailMon, - job: jb, - mbOracleRequests: mailbox.NewHighCapacity[log.Broadcast](), - mbOracleCancelRequests: mailbox.NewHighCapacity[log.Broadcast](), - minIncomingConfirmations: concreteSpec.MinIncomingConfirmations.Uint32, - requesters: concreteSpec.Requesters, - minContractPayment: concreteSpec.MinContractPayment, - chStop: make(chan struct{}), - } - var services []job.ServiceCtx - services = append(services, logListener) - - return services, nil -} - -var ( - _ log.Listener = &listener{} - _ job.ServiceCtx = &listener{} -) - -type listener struct { - services.StateMachine - logger logger.Logger - config Config - logBroadcaster log.Broadcaster - oracle operator.OperatorInterface - pipelineRunner pipeline.Runner - pipelineORM pipeline.ORM - mailMon *mailbox.Monitor - job job.Job - runs sync.Map // map[string]services.StopChan - shutdownWaitGroup sync.WaitGroup - mbOracleRequests *mailbox.Mailbox[log.Broadcast] - mbOracleCancelRequests *mailbox.Mailbox[log.Broadcast] - minIncomingConfirmations uint32 - requesters models.AddressCollection - minContractPayment *assets.Link - chStop services.StopChan -} - -func (l *listener) HealthReport() map[string]error { - return map[string]error{l.Name(): l.Healthy()} -} - -func (l *listener) Name() string { return l.logger.Name() } - -// Start complies with job.Service -func (l *listener) Start(context.Context) error { - return l.StartOnce("DirectRequestListener", func() error { - unsubscribeLogs := l.logBroadcaster.Register(l, log.ListenerOpts{ - Contract: l.oracle.Address(), - ParseLog: l.oracle.ParseLog, - LogsWithTopics: map[common.Hash][][]log.Topic{ - operator.OperatorOracleRequest{}.Topic(): {{log.Topic(l.job.ExternalIDEncodeBytesToTopic()), log.Topic(l.job.ExternalIDEncodeStringToTopic())}}, - operator.OperatorCancelOracleRequest{}.Topic(): {{log.Topic(l.job.ExternalIDEncodeBytesToTopic()), log.Topic(l.job.ExternalIDEncodeStringToTopic())}}, - }, - MinIncomingConfirmations: l.minIncomingConfirmations, - }) - l.shutdownWaitGroup.Add(3) - go l.processOracleRequests() - go l.processCancelOracleRequests() - - go func() { - <-l.chStop - unsubscribeLogs() - l.shutdownWaitGroup.Done() - }() - - l.mailMon.Monitor(l.mbOracleRequests, "DirectRequest", "Requests", strconv.Itoa(int(l.job.PipelineSpec.JobID))) - l.mailMon.Monitor(l.mbOracleCancelRequests, "DirectRequest", "Cancel", strconv.Itoa(int(l.job.PipelineSpec.JobID))) - - return nil - }) -} - -// Close complies with job.Service -func (l *listener) Close() error { - return l.StopOnce("DirectRequestListener", func() error { - l.runs.Range(func(key, runCloserChannelIf any) bool { - runCloserChannel := runCloserChannelIf.(services.StopChan) - close(runCloserChannel) - return true - }) - l.runs = sync.Map{} - - close(l.chStop) - l.shutdownWaitGroup.Wait() - - return services.CloseAll(l.mbOracleRequests, l.mbOracleCancelRequests) - }) -} - -func (l *listener) HandleLog(ctx context.Context, lb log.Broadcast) { - log := lb.DecodedLog() - if log == nil || reflect.ValueOf(log).IsNil() { - l.logger.Error("HandleLog: ignoring nil value") - return - } - - switch log := log.(type) { - case *operator.OperatorOracleRequest: - wasOverCapacity := l.mbOracleRequests.Deliver(lb) - if wasOverCapacity { - l.logger.Error("OracleRequest log mailbox is over capacity - dropped the oldest log") - } - case *operator.OperatorCancelOracleRequest: - wasOverCapacity := l.mbOracleCancelRequests.Deliver(lb) - if wasOverCapacity { - l.logger.Error("CancelOracleRequest log mailbox is over capacity - dropped the oldest log") - } - default: - l.logger.Warnf("Unexpected log type %T", log) - } -} - -func (l *listener) processOracleRequests() { - ctx, cancel := l.chStop.NewCtx() - defer cancel() - for { - select { - case <-l.chStop: - l.shutdownWaitGroup.Done() - return - case <-l.mbOracleRequests.Notify(): - l.handleReceivedLogs(ctx, l.mbOracleRequests) - } - } -} - -func (l *listener) processCancelOracleRequests() { - ctx, cancel := l.chStop.NewCtx() - defer cancel() - for { - select { - case <-l.chStop: - l.shutdownWaitGroup.Done() - return - case <-l.mbOracleCancelRequests.Notify(): - l.handleReceivedLogs(ctx, l.mbOracleCancelRequests) - } - } -} - -func (l *listener) handleReceivedLogs(ctx context.Context, mailbox *mailbox.Mailbox[log.Broadcast]) { - for { - select { - case <-ctx.Done(): - return - default: - } - lb, exists := mailbox.Retrieve() - if !exists { - return - } - was, err := l.logBroadcaster.WasAlreadyConsumed(ctx, lb) - if err != nil { - l.logger.Errorw("Could not determine if log was already consumed", "err", err) - continue - } else if was { - continue - } - - logJobSpecID := lb.RawLog().Topics[1] - if logJobSpecID == (common.Hash{}) || (logJobSpecID != l.job.ExternalIDEncodeStringToTopic() && logJobSpecID != l.job.ExternalIDEncodeBytesToTopic()) { - l.logger.Debugw("Skipping Run for Log with wrong Job ID", "logJobSpecID", logJobSpecID) - l.markLogConsumed(ctx, nil, lb) - continue - } - - log := lb.DecodedLog() - if log == nil || reflect.ValueOf(log).IsNil() { - l.logger.Error("HandleLog: ignoring nil value") - continue - } - - switch log := log.(type) { - case *operator.OperatorOracleRequest: - l.handleOracleRequest(ctx, log, lb) - case *operator.OperatorCancelOracleRequest: - l.handleCancelOracleRequest(ctx, nil, log, lb) - default: - l.logger.Warnf("Unexpected log type %T", log) - } - } -} - -func oracleRequestToMap(request *operator.OperatorOracleRequest) map[string]any { - result := make(map[string]any) - result["specId"] = fmt.Sprintf("0x%x", request.SpecId) - result["requester"] = request.Requester.Hex() - result["requestId"] = formatRequestId(request.RequestId) - result["payment"] = fmt.Sprintf("%v", request.Payment) - result["callbackAddr"] = request.CallbackAddr.Hex() - result["callbackFunctionId"] = fmt.Sprintf("0x%x", request.CallbackFunctionId) - result["cancelExpiration"] = fmt.Sprintf("%v", request.CancelExpiration) - result["dataVersion"] = fmt.Sprintf("%v", request.DataVersion) - result["data"] = fmt.Sprintf("0x%x", request.Data) - return result -} - -func (l *listener) handleOracleRequest(ctx context.Context, request *operator.OperatorOracleRequest, lb log.Broadcast) { - l.logger.Infow("Oracle request received", - "specId", fmt.Sprintf("%0x", request.SpecId), - "requester", request.Requester, - "requestId", fmt.Sprintf("%0x", request.RequestId), - "payment", request.Payment, - "callbackAddr", request.CallbackAddr, - "callbackFunctionId", fmt.Sprintf("%0x", request.CallbackFunctionId), - "cancelExpiration", request.CancelExpiration, - "dataVersion", request.DataVersion, - "data", fmt.Sprintf("%0x", request.Data), - ) - - if !l.allowRequester(request.Requester) { - l.logger.Infow("Rejected run for invalid requester", - "requester", request.Requester, - "allowedRequesters", l.requesters.ToStrings(), - ) - l.markLogConsumed(ctx, nil, lb) - return - } - - var minContractPayment *assets.Link - if l.minContractPayment != nil { - minContractPayment = l.minContractPayment - } else { - minContractPayment = l.config.MinContractPayment() - } - if minContractPayment != nil && request.Payment != nil { - requestPayment := assets.Link(*request.Payment) - if minContractPayment.Cmp(&requestPayment) > 0 { - l.logger.Warnw("Rejected run for insufficient payment", - "minContractPayment", minContractPayment.String(), - "requestPayment", requestPayment.String(), - ) - l.markLogConsumed(ctx, nil, lb) - return - } - } - - meta := make(map[string]any) - meta["oracleRequest"] = oracleRequestToMap(request) - - runCloserChannel := make(services.StopChan) - runCloserChannelIf, loaded := l.runs.LoadOrStore(formatRequestId(request.RequestId), runCloserChannel) - if loaded { - runCloserChannel = runCloserChannelIf.(services.StopChan) - } - ctx, cancel := runCloserChannel.NewCtx() - defer cancel() - - evmChainID := lb.EVMChainID() - vars := pipeline.NewVarsFrom(map[string]any{ - "jobSpec": map[string]any{ - "databaseID": l.job.ID, - "externalJobID": l.job.ExternalJobID, - "name": l.job.Name.ValueOrZero(), - "pipelineSpec": &pipeline.Spec{ - ForwardingAllowed: l.job.ForwardingAllowed, - }, - "evmChainID": evmChainID.String(), - }, - "jobRun": map[string]any{ - "meta": meta, - "logBlockHash": request.Raw.BlockHash, - "logBlockNumber": request.Raw.BlockNumber, - "logTxHash": request.Raw.TxHash, - "logAddress": request.Raw.Address, - "logTopics": request.Raw.Topics, - "logData": request.Raw.Data, - "blockReceiptsRoot": lb.ReceiptsRoot(), - "blockTransactionsRoot": lb.TransactionsRoot(), - "blockStateRoot": lb.StateRoot(), - }, - }) - run := pipeline.NewRun(*l.job.PipelineSpec, vars) - _, err := l.pipelineRunner.Run(ctx, run, true, func(tx sqlutil.DataSource) error { - l.markLogConsumed(ctx, tx, lb) - return nil - }) - if ctx.Err() != nil { - return - } else if err != nil { - l.logger.Errorw("Failed executing run", "err", err) - } -} - -func (l *listener) allowRequester(requester common.Address) bool { - if len(l.requesters) == 0 { - return true - } - return slices.Contains(l.requesters, requester) -} - -// Cancels runs that haven't been started yet, with the given request ID -func (l *listener) handleCancelOracleRequest(ctx context.Context, ds sqlutil.DataSource, request *operator.OperatorCancelOracleRequest, lb log.Broadcast) { - runCloserChannelIf, loaded := l.runs.LoadAndDelete(formatRequestId(request.RequestId)) - if loaded { - close(runCloserChannelIf.(services.StopChan)) - } - l.markLogConsumed(ctx, ds, lb) -} - -func (l *listener) markLogConsumed(ctx context.Context, ds sqlutil.DataSource, lb log.Broadcast) { - if err := l.logBroadcaster.MarkConsumed(ctx, ds, lb); err != nil { - l.logger.Errorw("Unable to mark log consumed", "err", err, "log", lb.String()) - } -} - -// JobID - Job complies with log.Listener -func (l *listener) JobID() int32 { - return l.job.ID -} - -func formatRequestId(requestId [32]byte) string { - return fmt.Sprintf("0x%x", requestId) -} diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go deleted file mode 100644 index 4fa3eb3e968..00000000000 --- a/core/services/directrequest/delegate_test.go +++ /dev/null @@ -1,582 +0,0 @@ -package directrequest_test - -import ( - "context" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/quarantine" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" - "github.com/smartcontractkit/chainlink-evm/pkg/client" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/operatorforwarder/generated/operator" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - log_mocks "github.com/smartcontractkit/chainlink/v2/common/log/mocks" - "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - pipeline_mocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" -) - -func TestDelegate_ServicesForSpec(t *testing.T) { - ethClient := client.NewNullClient(big.NewInt(evmtest.NullClientChainID), logger.TestLogger(t)) - runner := pipeline_mocks.NewRunner(t) - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - }) - keyStore := cltest.NewKeyStore(t, db) - mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - FeatureConfig: cfg.Feature(), - ListenerConfig: cfg.Database().Listener(), - DB: db, - Client: ethClient, - MailMon: mailMon, - KeyStore: keyStore.Eth(), - }) - - lggr := logger.TestLogger(t) - delegate := directrequest.NewDelegate(lggr, runner, nil, legacyChains, mailMon) - - t.Run("Spec without DirectRequestSpec", func(t *testing.T) { - spec := job.Job{} - _, err := delegate.ServicesForSpec(testutils.Context(t), spec) - assert.Error(t, err, "expects a *job.DirectRequestSpec to be present") - }) - - t.Run("Spec with DirectRequestSpec", func(t *testing.T) { - spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*sqlutil.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} - services, err := delegate.ServicesForSpec(testutils.Context(t), spec) - require.NoError(t, err) - assert.Len(t, services, 1) - }) -} - -type DirectRequestUniverse struct { - spec *job.Job - runner *pipeline_mocks.Runner - service job.ServiceCtx - jobORM job.ORM - listener log.Listener - logBroadcaster *log_mocks.Broadcaster - cleanup func() -} - -func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfig, specF func(spec *job.Job)) *DirectRequestUniverse { - ethClient := client.NewNullClient(big.NewInt(evmtest.NullClientChainID), logger.TestLogger(t)) - runner := pipeline_mocks.NewRunner(t) - broadcaster := log_mocks.NewBroadcaster(t) - servicetest.SetupNoOpMock(broadcaster) - broadcaster.On("AddDependents", 1) - - mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - - db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db) - legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - FeatureConfig: cfg.Feature(), - ListenerConfig: cfg.Database().Listener(), - DB: db, - Client: ethClient, - LogBroadcaster: broadcaster, - MailMon: mailMon, - KeyStore: keyStore.Eth(), - }) - lggr := logger.TestLogger(t) - orm := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) - btORM := bridges.NewORM(db) - jobORM := job.NewORM(db, orm, btORM, keyStore, lggr) - delegate := directrequest.NewDelegate(lggr, runner, orm, legacyChains, mailMon) - - jb := cltest.MakeDirectRequestJobSpec(t) - jb.ExternalJobID = uuid.New() - if specF != nil { - specF(jb) - } - ctx := testutils.Context(t) - require.NoError(t, jobORM.CreateJob(ctx, jb)) - serviceArray, err := delegate.ServicesForSpec(ctx, *jb) - require.NoError(t, err) - assert.Len(t, serviceArray, 1) - service := serviceArray[0] - - uni := &DirectRequestUniverse{ - spec: jb, - runner: runner, - service: service, - jobORM: jobORM, - listener: nil, - logBroadcaster: broadcaster, - cleanup: func() { jobORM.Close() }, - } - - broadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}).Run(func(args mock.Arguments) { - uni.listener = args.Get(0).(log.Listener) - }) - - return uni -} - -func NewDirectRequestUniverse(t *testing.T) *DirectRequestUniverse { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - }) - return NewDirectRequestUniverseWithConfig(t, cfg, nil) -} - -func (uni *DirectRequestUniverse) Cleanup() { - uni.cleanup() -} - -func TestDelegate_ServicesListenerHandleLog(t *testing.T) { - quarantine.Flaky(t, "DX-1909") - testutils.SkipShortDB(t) - t.Parallel() - - t.Run("Log is an OracleRequest", func(t *testing.T) { - uni := NewDirectRequestUniverse(t) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - log.On("ReceiptsRoot").Return(common.Hash{}) - log.On("TransactionsRoot").Return(common.Hash{}) - log.On("StateRoot").Return(common.Hash{}) - log.On("EVMChainID").Return(*big.NewInt(0)) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - runBeganAwaiter := cltest.NewAwaiter() - uni.runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything). - Return(false, nil). - Run(func(args mock.Arguments) { - runBeganAwaiter.ItHappened() - fn := args.Get(3).(func(source sqlutil.DataSource) error) - require.NoError(t, fn(nil)) - }).Once() - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - require.NotNil(t, uni.listener, "listener was nil; expected broadcaster.Register to have been called") - // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) - require.NoError(t, jErr) - require.Equal(t, drJob.ID, uni.listener.JobID()) - require.NotNil(t, drJob.DirectRequestSpec) - - uni.listener.HandleLog(ctx, log) - - runBeganAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) - - t.Run("Log is not consumed, as it's too young", func(t *testing.T) { - uni := NewDirectRequestUniverse(t) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Maybe() - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - BlockNumber: 0, - }).Maybe() - log.On("DecodedLog").Return(&logOracleRequest).Maybe() - log.On("String").Return("") - log.On("EVMChainID").Return(*big.NewInt(0)) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe() - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - uni.listener.HandleLog(ctx, log) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - - log.On("ReceiptsRoot").Return(common.Hash{}) - log.On("TransactionsRoot").Return(common.Hash{}) - log.On("StateRoot").Return(common.Hash{}) - - runBeganAwaiter := cltest.NewAwaiter() - uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Run(func(args mock.Arguments) { - runBeganAwaiter.ItHappened() - fn := args.Get(3).(func(sqlutil.DataSource) error) - require.NoError(t, fn(nil)) - }).Once().Return(false, nil) - - // but should after this one, as the head Number is larger - runBeganAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) - - t.Run("Log has wrong jobID", func(t *testing.T) { - uni := NewDirectRequestUniverse(t) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - lbAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) - - logCancelOracleRequest := operator.OperatorCancelOracleRequest{RequestId: uni.spec.ExternalIDEncodeStringToTopic()} - logAwaiter := cltest.NewAwaiter() - log.On("DecodedLog").Run(func(args mock.Arguments) { logAwaiter.ItHappened() }).Return(&logCancelOracleRequest) - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{{}, {}}, - }) - log.On("String").Return("") - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - uni.listener.HandleLog(ctx, log) - - logAwaiter.AwaitOrFail(t) - lbAwaiter.AwaitOrFail(t) - - uni.service.Close() - }) - - t.Run("Log is a CancelOracleRequest with no matching run", func(t *testing.T) { - uni := NewDirectRequestUniverse(t) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logCancelOracleRequest := operator.OperatorCancelOracleRequest{RequestId: uni.spec.ExternalIDEncodeStringToTopic()} - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("String").Return("") - log.On("DecodedLog").Return(&logCancelOracleRequest) - lbAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { lbAwaiter.ItHappened() }).Return(nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - uni.listener.HandleLog(ctx, log) - - lbAwaiter.AwaitOrFail(t) - - uni.service.Close() - }) - - t.Run("Log is a CancelOracleRequest with a matching run", func(t *testing.T) { - uni := NewDirectRequestUniverse(t) - defer uni.Cleanup() - - runLog := log_mocks.NewBroadcast(t) - runLog.On("ReceiptsRoot").Return(common.Hash{}) - runLog.On("TransactionsRoot").Return(common.Hash{}) - runLog.On("StateRoot").Return(common.Hash{}) - runLog.On("EVMChainID").Return(*big.NewInt(0)) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - RequestId: uni.spec.ExternalIDEncodeStringToTopic(), - } - runLog.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - runLog.On("DecodedLog").Return(&logOracleRequest) - runLog.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - cancelLog := log_mocks.NewBroadcast(t) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logCancelOracleRequest := operator.OperatorCancelOracleRequest{RequestId: uni.spec.ExternalIDEncodeStringToTopic()} - cancelLog.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - cancelLog.On("DecodedLog").Return(&logCancelOracleRequest) - cancelLog.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - timeout := 5 * time.Second - runBeganAwaiter := cltest.NewAwaiter() - runCancelledAwaiter := cltest.NewAwaiter() - uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - runBeganAwaiter.ItHappened() - ctx := args[0].(context.Context) - select { - case <-time.After(timeout): - t.Fatalf("Timed out waiting for Run to be canceled (%v)", timeout) - case <-ctx.Done(): - runCancelledAwaiter.ItHappened() - } - }).Once().Return(false, nil) - uni.listener.HandleLog(ctx, runLog) - - runBeganAwaiter.AwaitOrFail(t, timeout) - - uni.listener.HandleLog(ctx, cancelLog) - - runCancelledAwaiter.AwaitOrFail(t, timeout) - - uni.service.Close() - }) - - t.Run("Log has sufficient funds", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = assets.NewLinkFromJuels(100) - }) - uni := NewDirectRequestUniverseWithConfig(t, cfg, nil) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - log.On("ReceiptsRoot").Return(common.Hash{}) - log.On("TransactionsRoot").Return(common.Hash{}) - log.On("StateRoot").Return(common.Hash{}) - log.On("EVMChainID").Return(*big.NewInt(0)) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - Payment: big.NewInt(100), - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - - runBeganAwaiter := cltest.NewAwaiter() - uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - runBeganAwaiter.ItHappened() - fn := args.Get(3).(func(sqlutil.DataSource) error) - require.NoError(t, fn(nil)) - }).Once().Return(false, nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) - require.NoError(t, jErr) - require.Equal(t, drJob.ID, uni.listener.JobID()) - require.NotNil(t, drJob.DirectRequestSpec) - - uni.listener.HandleLog(ctx, log) - - runBeganAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) - - t.Run("Log has insufficient funds", func(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = assets.NewLinkFromJuels(100) - }) - uni := NewDirectRequestUniverseWithConfig(t, cfg, nil) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - Payment: big.NewInt(99), - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - markConsumedLogAwaiter.ItHappened() - }).Return(nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - uni.listener.HandleLog(ctx, log) - - markConsumedLogAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) - - t.Run("requesters is specified and log is requested by a whitelisted address", func(t *testing.T) { - requester := testutils.NewAddress() - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = assets.NewLinkFromJuels(100) - }) - uni := NewDirectRequestUniverseWithConfig(t, cfg, func(jb *job.Job) { - jb.DirectRequestSpec.Requesters = []common.Address{testutils.NewAddress(), requester} - }) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - log.On("ReceiptsRoot").Return(common.Hash{}) - log.On("TransactionsRoot").Return(common.Hash{}) - log.On("StateRoot").Return(common.Hash{}) - log.On("EVMChainID").Return(*big.NewInt(0)) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - Payment: big.NewInt(100), - Requester: requester, - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - markConsumedLogAwaiter.ItHappened() - }).Return(nil) - - runBeganAwaiter := cltest.NewAwaiter() - uni.runner.On("Run", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - runBeganAwaiter.ItHappened() - fn := args.Get(3).(func(sqlutil.DataSource) error) - require.NoError(t, fn(nil)) - }).Once().Return(false, nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - // check if the job exists under the correct ID - drJob, jErr := uni.jobORM.FindJob(ctx, uni.listener.JobID()) - require.NoError(t, jErr) - require.Equal(t, drJob.ID, uni.listener.JobID()) - require.NotNil(t, drJob.DirectRequestSpec) - - uni.listener.HandleLog(ctx, log) - - runBeganAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) - - t.Run("requesters is specified and log is requested by a non-whitelisted address", func(t *testing.T) { - requester := testutils.NewAddress() - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) - c.EVM[0].MinContractPayment = assets.NewLinkFromJuels(100) - }) - uni := NewDirectRequestUniverseWithConfig(t, cfg, func(jb *job.Job) { - jb.DirectRequestSpec.Requesters = []common.Address{testutils.NewAddress(), testutils.NewAddress()} - }) - defer uni.Cleanup() - - log := log_mocks.NewBroadcast(t) - - uni.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - logOracleRequest := operator.OperatorOracleRequest{ - CancelExpiration: big.NewInt(0), - Payment: big.NewInt(100), - Requester: requester, - } - log.On("RawLog").Return(types.Log{ - Topics: []common.Hash{ - {}, - uni.spec.ExternalIDEncodeStringToTopic(), - }, - }) - log.On("DecodedLog").Return(&logOracleRequest) - log.On("String").Return("") - markConsumedLogAwaiter := cltest.NewAwaiter() - uni.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - markConsumedLogAwaiter.ItHappened() - }).Return(nil) - - ctx := testutils.Context(t) - err := uni.service.Start(ctx) - require.NoError(t, err) - - uni.listener.HandleLog(ctx, log) - - markConsumedLogAwaiter.AwaitOrFail(t, 5*time.Second) - - uni.service.Close() - }) -} - -func ptr[T any](t T) *T { return &t } diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go deleted file mode 100644 index be08f9d294f..00000000000 --- a/core/services/directrequest/validate.go +++ /dev/null @@ -1,50 +0,0 @@ -package directrequest - -import ( - "github.com/pelletier/go-toml" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-evm/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -type DirectRequestToml struct { - ContractAddress types.EIP55Address `toml:"contractAddress"` - Requesters models.AddressCollection `toml:"requesters"` - MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *sqlutil.Big `toml:"evmChainID"` - MinIncomingConfirmations null.Uint32 `toml:"minIncomingConfirmations"` -} - -func ValidatedDirectRequestSpec(tomlString string) (job.Job, error) { - var jb = job.Job{} - tree, err := toml.Load(tomlString) - if err != nil { - return jb, err - } - err = tree.Unmarshal(&jb) - if err != nil { - return jb, err - } - var spec DirectRequestToml - err = tree.Unmarshal(&spec) - if err != nil { - return jb, err - } - jb.DirectRequestSpec = &job.DirectRequestSpec{ - ContractAddress: spec.ContractAddress, - Requesters: spec.Requesters, - MinContractPayment: spec.MinContractPayment, - EVMChainID: spec.EVMChainID, - MinIncomingConfirmations: spec.MinIncomingConfirmations, - } - - if jb.Type != job.DirectRequest { - return jb, errors.Errorf("unsupported type %s", jb.Type) - } - return jb, nil -} diff --git a/core/services/directrequest/validate_test.go b/core/services/directrequest/validate_test.go deleted file mode 100644 index 91cd7ece712..00000000000 --- a/core/services/directrequest/validate_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package directrequest - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestValidatedDirectRequestSpec(t *testing.T) { - t.Parallel() - - toml := ` -type = "directrequest" -schemaVersion = 1 -name = "example eth request event spec" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "A5AC14E8-7629-4726-B1F1-1AE053FC829E" -observationSource = """ - ds1 [type=http method=GET url="example.com" allowunrestrictednetworkaccess="true"]; - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; -""" -` - - s, err := ValidatedDirectRequestSpec(toml) - require.NoError(t, err) - - assert.Equal(t, int32(0), s.ID) - assert.Equal(t, "0x613a38AC1659769640aaE063C651F48E0250454C", s.DirectRequestSpec.ContractAddress.Hex()) - assert.Equal(t, "0x6135616331346538373632393437323662316631316165303533666338323965", s.ExternalIDEncodeStringToTopic().String()) - assert.Equal(t, "0xa5ac14e876294726b1f11ae053fc829e00000000000000000000000000000000", s.ExternalIDEncodeBytesToTopic().String()) - assert.NotZero(t, s.ExternalJobID[:]) - assert.Equal(t, time.Time{}, s.DirectRequestSpec.CreatedAt) - assert.Equal(t, time.Time{}, s.DirectRequestSpec.UpdatedAt) -} - -func TestValidatedDirectRequestSpec_MinIncomingConfirmations(t *testing.T) { - t.Parallel() - - t.Run("no minIncomingConfirmations specified", func(t *testing.T) { - t.Parallel() - - toml := ` - type = "directrequest" - schemaVersion = 1 - name = "example eth request event spec" - ` - - s, err := ValidatedDirectRequestSpec(toml) - require.NoError(t, err) - - assert.False(t, s.DirectRequestSpec.MinIncomingConfirmations.Valid) - }) - - t.Run("minIncomingConfirmations set to 100", func(t *testing.T) { - t.Parallel() - - toml := ` - type = "directrequest" - schemaVersion = 1 - name = "example eth request event spec" - minIncomingConfirmations = 100 - ` - - s, err := ValidatedDirectRequestSpec(toml) - require.NoError(t, err) - - assert.True(t, s.DirectRequestSpec.MinIncomingConfirmations.Valid) - assert.Equal(t, uint32(100), s.DirectRequestSpec.MinIncomingConfirmations.Uint32) - }) -} diff --git a/core/services/feeds/models_test.go b/core/services/feeds/models_test.go index 908751d6d8e..bb0bcb8e7fd 100644 --- a/core/services/feeds/models_test.go +++ b/core/services/feeds/models_test.go @@ -98,36 +98,6 @@ func Test_FromPluginType(t *testing.T) { assert.Equal(t, "unknown", FromPluginTypeInput(PluginTypeUnknown)) } -func Test_FluxMonitorConfig_Value(t *testing.T) { - t.Parallel() - - cfg := FluxMonitorConfig{Enabled: true} - want := `{"enabled":true}` - - val, err := cfg.Value() - require.NoError(t, err) - - actual, ok := val.([]byte) - require.True(t, ok) - - assert.Equal(t, want, string(actual)) -} - -func Test_FluxMonitorConfig_Scan(t *testing.T) { - t.Parallel() - - var ( - give = `{"enabled":true}` - want = FluxMonitorConfig{Enabled: true} - ) - - var actual FluxMonitorConfig - err := actual.Scan([]byte(give)) - require.NoError(t, err) - - assert.Equal(t, want, actual) -} - func Test_OCR1Config_Value(t *testing.T) { t.Parallel() diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index 54e999159b3..55a73b4b705 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -35,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ccv/ccvcommitteeverifier" "github.com/smartcontractkit/chainlink/v2/core/services/ccv/ccvexecutor" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -1473,7 +1472,7 @@ func (s *service) generateJob(ctx context.Context, spec string) (*job.Job, error } js, err = ocrbootstrap.ValidatedBootstrapSpecToml(spec) case job.FluxMonitor: - js, err = fluxmonitorv2.ValidatedFluxMonitorSpec(s.jobCfg, spec) + return nil, errors.New("job type fluxmonitor has been removed and is no longer supported") case job.Workflow: js, err = workflows.ValidatedWorkflowJobSpec(ctx, spec) case job.CCIP: diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 4486deda640..fb39a81426d 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -27,12 +27,10 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" proto "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" "github.com/smartcontractkit/chainlink-evm/pkg/chains/legacyevm" "github.com/smartcontractkit/chainlink-evm/pkg/heads" - "github.com/smartcontractkit/chainlink-evm/pkg/types" "github.com/smartcontractkit/chainlink-common/keystore/corekeys/csakey" "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" @@ -864,29 +862,6 @@ func Test_Service_ProposeJob(t *testing.T) { t.Parallel() var ( - idFluxMonitor = int64(1) - remoteUUIDFluxMonitor = uuid.New() - nameAndExternalJobID = uuid.New() - spec = fmt.Sprintf(FluxMonitorTestSpecTemplate, nameAndExternalJobID, nameAndExternalJobID) - argsFluxMonitor = &feeds.ProposeJobArgs{ - FeedsManagerID: 1, - RemoteUUID: remoteUUIDFluxMonitor, - Spec: spec, - Version: 1, - } - jpFluxMonitor = feeds.JobProposal{ - FeedsManagerID: 1, - Name: null.StringFrom(nameAndExternalJobID.String()), - RemoteUUID: remoteUUIDFluxMonitor, - Status: feeds.JobProposalStatusPending, - } - specFluxMonitor = feeds.JobProposalSpec{ - Definition: spec, - Status: feeds.SpecStatusPending, - Version: argsFluxMonitor.Version, - JobProposalID: idFluxMonitor, - } - idOCR1 = int64(2) remoteUUIDOCR1 = uuid.New() ocr1NameAndExternalJobID = uuid.New() @@ -1156,20 +1131,11 @@ func Test_Service_ProposeJob(t *testing.T) { }, { - name: "Create success (Flux Monitor)", + name: "Create success (Flux Monitor) - rejected", before: func(svc *TestService) { - svc.orm.On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID).Return(new(feeds.JobProposal), sql.ErrNoRows) - svc.orm.On("UpsertJobProposal", mock.Anything, &jpFluxMonitor).Return(idFluxMonitor, nil) - svc.orm.On("CreateSpec", mock.Anything, specFluxMonitor).Return(int64(100), nil) - svc.orm.On("CountJobProposalsByStatus", mock.Anything).Return(&feeds.JobProposalCounts{}, nil) - transactCall := svc.orm.On("Transact", mock.Anything, mock.Anything) - transactCall.Run(func(args mock.Arguments) { - fn := args[1].(func(orm feeds.ORM) error) - transactCall.ReturnArguments = mock.Arguments{fn(svc.orm)} - }) }, - args: argsFluxMonitor, - wantID: idFluxMonitor, + args: &feeds.ProposeJobArgs{FeedsManagerID: 1, RemoteUUID: uuid.New(), Spec: fmt.Sprintf(FluxMonitorTestSpecTemplate, uuid.New(), uuid.New()), Version: 1}, + wantErr: "job type fluxmonitor has been removed", }, { name: "Create success (OCR1)", @@ -1223,15 +1189,15 @@ func Test_Service_ProposeJob(t *testing.T) { name: "Update success", before: func(svc *TestService) { svc.orm. - On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID). + On("GetJobProposalByRemoteUUID", mock.Anything, jpOCR1.RemoteUUID). Return(&feeds.JobProposal{ - FeedsManagerID: jpFluxMonitor.FeedsManagerID, - RemoteUUID: jpFluxMonitor.RemoteUUID, + FeedsManagerID: jpOCR1.FeedsManagerID, + RemoteUUID: jpOCR1.RemoteUUID, Status: feeds.JobProposalStatusPending, }, nil) - svc.orm.On("ExistsSpecByJobProposalIDAndVersion", mock.Anything, jpFluxMonitor.ID, argsFluxMonitor.Version).Return(false, nil) - svc.orm.On("UpsertJobProposal", mock.Anything, &jpFluxMonitor).Return(idFluxMonitor, nil) - svc.orm.On("CreateSpec", mock.Anything, specFluxMonitor).Return(int64(100), nil) + svc.orm.On("ExistsSpecByJobProposalIDAndVersion", mock.Anything, jpOCR1.ID, argsOCR1.Version).Return(false, nil) + svc.orm.On("UpsertJobProposal", mock.Anything, &jpOCR1).Return(idOCR1, nil) + svc.orm.On("CreateSpec", mock.Anything, specOCR1).Return(int64(100), nil) svc.orm.On("CountJobProposalsByStatus", mock.Anything).Return(&feeds.JobProposalCounts{}, nil) transactCall := svc.orm.On("Transact", mock.Anything, mock.Anything) transactCall.Run(func(args mock.Arguments) { @@ -1239,8 +1205,8 @@ func Test_Service_ProposeJob(t *testing.T) { transactCall.ReturnArguments = mock.Arguments{fn(svc.orm)} }) }, - args: argsFluxMonitor, - wantID: idFluxMonitor, + args: argsOCR1, + wantID: idOCR1, }, { name: "contains invalid job spec", @@ -1251,7 +1217,7 @@ func Test_Service_ProposeJob(t *testing.T) { name: "must be an ocr job to include bootstraps", before: func(svc *TestService) {}, args: &feeds.ProposeJobArgs{ - Spec: spec, + Spec: bootstrapSpec, Multiaddrs: pq.StringArray{"/dns4/example.com"}, }, wantErr: "only OCR job type supports multiaddr", @@ -1260,57 +1226,57 @@ func Test_Service_ProposeJob(t *testing.T) { name: "ensure an upsert validates the job proposal belongs to the feeds manager", before: func(svc *TestService) { svc.orm. - On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID). + On("GetJobProposalByRemoteUUID", mock.Anything, jpOCR1.RemoteUUID). Return(&feeds.JobProposal{ FeedsManagerID: 2, - RemoteUUID: jpFluxMonitor.RemoteUUID, + RemoteUUID: jpOCR1.RemoteUUID, }, nil) }, - args: argsFluxMonitor, + args: argsOCR1, wantErr: "cannot update a job proposal belonging to another feeds manager", }, { name: "spec version already exists", before: func(svc *TestService) { svc.orm. - On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID). + On("GetJobProposalByRemoteUUID", mock.Anything, jpOCR1.RemoteUUID). Return(&feeds.JobProposal{ - FeedsManagerID: jpFluxMonitor.FeedsManagerID, - RemoteUUID: jpFluxMonitor.RemoteUUID, + FeedsManagerID: jpOCR1.FeedsManagerID, + RemoteUUID: jpOCR1.RemoteUUID, Status: feeds.JobProposalStatusPending, }, nil) - svc.orm.On("ExistsSpecByJobProposalIDAndVersion", mock.Anything, jpFluxMonitor.ID, argsFluxMonitor.Version).Return(true, nil) + svc.orm.On("ExistsSpecByJobProposalIDAndVersion", mock.Anything, jpOCR1.ID, argsOCR1.Version).Return(true, nil) }, - args: argsFluxMonitor, + args: argsOCR1, wantErr: "version conflict", }, { name: "upsert error", before: func(svc *TestService) { - svc.orm.On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID).Return(new(feeds.JobProposal), sql.ErrNoRows) - svc.orm.On("UpsertJobProposal", mock.Anything, &jpFluxMonitor).Return(int64(0), errors.New("orm error")) + svc.orm.On("GetJobProposalByRemoteUUID", mock.Anything, jpOCR1.RemoteUUID).Return(new(feeds.JobProposal), sql.ErrNoRows) + svc.orm.On("UpsertJobProposal", mock.Anything, &jpOCR1).Return(int64(0), errors.New("orm error")) transactCall := svc.orm.On("Transact", mock.Anything, mock.Anything) transactCall.Run(func(args mock.Arguments) { fn := args[1].(func(orm feeds.ORM) error) transactCall.ReturnArguments = mock.Arguments{fn(svc.orm)} }) }, - args: argsFluxMonitor, + args: argsOCR1, wantErr: "failed to upsert job proposal", }, { name: "Create spec error", before: func(svc *TestService) { - svc.orm.On("GetJobProposalByRemoteUUID", mock.Anything, jpFluxMonitor.RemoteUUID).Return(new(feeds.JobProposal), sql.ErrNoRows) - svc.orm.On("UpsertJobProposal", mock.Anything, &jpFluxMonitor).Return(idFluxMonitor, nil) - svc.orm.On("CreateSpec", mock.Anything, specFluxMonitor).Return(int64(0), errors.New("orm error")) + svc.orm.On("GetJobProposalByRemoteUUID", mock.Anything, jpOCR1.RemoteUUID).Return(new(feeds.JobProposal), sql.ErrNoRows) + svc.orm.On("UpsertJobProposal", mock.Anything, &jpOCR1).Return(idOCR1, nil) + svc.orm.On("CreateSpec", mock.Anything, specOCR1).Return(int64(0), errors.New("orm error")) transactCall := svc.orm.On("Transact", mock.Anything, mock.Anything) transactCall.Run(func(args mock.Arguments) { fn := args[1].(func(orm feeds.ORM) error) transactCall.ReturnArguments = mock.Arguments{fn(svc.orm)} }) }, - args: argsFluxMonitor, + args: argsOCR1, wantErr: "failed to create spec", }, } @@ -2538,8 +2504,11 @@ func Test_Service_ListSpecsByJobProposalIDs(t *testing.T) { } func Test_Service_ApproveSpec(t *testing.T) { - var evmChainID *sqlutil.Big - address := types.EIP55AddressFromAddress(common.Address{}) + const ( + approveSpecContractID = "0x613a38AC1659769640aaE063C651F48E0250454C" + approveSpecRelay = "evm" + approveSpecChainID = int64(0) + ) externalJobID := uuid.New() now := time.Now() @@ -2547,17 +2516,13 @@ func Test_Service_ApproveSpec(t *testing.T) { ctx = testutils.Context(t) defn = ` name = 'LINK / ETH | version 3 | contract 0x0000000000000000000000000000000000000000' -schemaVersion = 1 -contractAddress = '0x0000000000000000000000000000000000000000' -externalJobID = '%s' -type = 'fluxmonitor' -threshold = 1.0 -idleTimerPeriod = '4h' -idleTimerDisabled = false -pollingTimerPeriod = '1m' -pollingTimerDisabled = false -observationSource = """ -// data source 1 +type = "offchainreporting2" +pluginType = "median" +schemaVersion = 1 +relay = "evm" +contractID = "0x613a38AC1659769640aaE063C651F48E0250454C" +externalJobID = '%s' +observationSource = """ ds1 [type=bridge name=\"bridge-api0\" requestData="{\\\"data\\": {\\\"from\\\":\\\"LINK\\\",\\\"to\\\":\\\"ETH\\\"}}"]; ds1_parse [type=jsonparse path="result"]; ds1_multiply [type=multiply times=1000000000000000000]; @@ -2565,6 +2530,25 @@ ds1 -> ds1_parse -> ds1_multiply -> answer1; answer1 [type=median index=0]; """ +[relayConfig] +chainID = 0 +[pluginConfig] +juelsPerFeeCoinSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +gasPriceSubunitsSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +[pluginConfig.juelsPerFeeCoinCache] +updateInterval = "30s" ` jp = &feeds.JobProposal{ ID: 1, @@ -2622,7 +2606,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -2673,7 +2657,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -2724,7 +2708,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -2784,7 +2768,7 @@ answer1 [type=median index=0]; Status: feeds.SpecStatusApproved, JobProposalID: jp.ID, Version: 2, - Definition: fmt.Sprintf(defn, jp.ID), + Definition: fmt.Sprintf(defn, uuid.New()), } svc.orm.On("GetSpec", mock.Anything, cancelledSpec.ID).Return(cancelledSpec, nil) @@ -2886,7 +2870,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(j.ID, nil) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(j.ID, nil) svc.orm.On("WithDataSource", mock.Anything).Return(feeds.ORM(svc.orm)) svc.jobORM.On("WithDataSource", mock.Anything).Return(job.ORM(svc.jobORM)) }, @@ -2945,7 +2929,7 @@ answer1 [type=median index=0]; svc.orm.EXPECT().GetJobProposal(mock.Anything, jp.ID).Return(jp, nil) svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(j.ID, nil) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(j.ID, nil) svc.orm.EXPECT().GetApprovedSpec(mock.Anything, jp.ID).Return(nil, sql.ErrNoRows) svc.spawner.On("DeleteJob", mock.Anything, mock.Anything, j.ID).Return(nil) @@ -2988,7 +2972,7 @@ answer1 [type=median index=0]; svc.orm.EXPECT().GetJobProposal(mock.Anything, jp.ID).Return(jp, nil) svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(j.ID, nil) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(j.ID, nil) svc.orm.EXPECT().GetApprovedSpec(mock.Anything, jp.ID).Return(&feeds.JobProposalSpec{ID: 100}, nil) svc.orm.EXPECT().CancelSpec(mock.Anything, int64(100)).Return(nil) @@ -3090,7 +3074,7 @@ answer1 [type=median index=0]; svc.orm.EXPECT().GetJobProposal(mock.Anything, jp.ID).Return(jp, nil) svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(j.ID, nil) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(j.ID, nil) svc.orm.EXPECT().GetApprovedSpec(mock.Anything, jp.ID).Return(nil, errors.New("failure")) svc.orm.On("WithDataSource", mock.Anything).Return(feeds.ORM(svc.orm)) svc.jobORM.On("WithDataSource", mock.Anything).Return(job.ORM(svc.jobORM)) @@ -3126,7 +3110,7 @@ answer1 [type=median index=0]; svc.orm.EXPECT().GetJobProposal(mock.Anything, jp.ID).Return(jp, nil) svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(j.ID, nil) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(j.ID, nil) svc.orm.EXPECT().GetApprovedSpec(mock.Anything, jp.ID).Return(&feeds.JobProposalSpec{ID: 100}, nil) svc.orm.EXPECT().CancelSpec(mock.Anything, int64(100)).Return(errors.New("failure")) svc.orm.On("WithDataSource", mock.Anything).Return(feeds.ORM(svc.orm)) @@ -3146,7 +3130,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -3174,7 +3158,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -3208,7 +3192,7 @@ answer1 [type=median index=0]; svc.jobORM.On("AssertBridgesExist", mock.Anything, mock.IsType(pipeline.Pipeline{})).Return(nil) svc.jobORM.On("FindJobByExternalJobID", mock.Anything, externalJobID).Return(job.Job{}, sql.ErrNoRows) - svc.jobORM.On("FindJobIDByAddress", mock.Anything, address, evmChainID, mock.Anything).Return(int32(0), sql.ErrNoRows) + svc.jobORM.On("FindOCR2JobIDByAddress", mock.Anything, approveSpecRelay, approveSpecChainID, approveSpecContractID, (*common.Hash)(nil)).Return(int32(0), sql.ErrNoRows) svc.spawner. On("CreateJob", @@ -5269,7 +5253,7 @@ func Test_Service_GetJobRuns(t *testing.T) { ID: jobID, ExternalJobID: remoteUUID, Name: null.StringFrom("test job"), - Type: "directrequest", + Type: job.Cron, } run1 = pipeline.Run{ diff --git a/core/services/fluxmonitorv2/config.go b/core/services/fluxmonitorv2/config.go deleted file mode 100644 index 9acd870491e..00000000000 --- a/core/services/fluxmonitorv2/config.go +++ /dev/null @@ -1,37 +0,0 @@ -package fluxmonitorv2 - -import ( - "time" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-evm/pkg/config" -) - -// Config defines the Flux Monitor configuration. -type Config interface { - FlagsContractAddress() string // Evm - MinContractPayment() *assets.Link // Evm -} - -type EvmFeeConfig interface { - LimitDefault() uint64 // Evm - LimitJobType() config.LimitJobType -} - -type EvmTransactionsConfig interface { - MaxQueued() uint64 // Evm -} - -type FluxMonitorConfig interface { - DefaultTransactionQueueDepth() uint32 -} - -type JobPipelineConfig interface { - DefaultHTTPTimeout() commonconfig.Duration -} - -// MinimumPollingInterval returns the minimum duration between polling ticks -func MinimumPollingInterval(c JobPipelineConfig) time.Duration { - return c.DefaultHTTPTimeout().Duration() -} diff --git a/core/services/fluxmonitorv2/contract_submitter.go b/core/services/fluxmonitorv2/contract_submitter.go deleted file mode 100644 index fe5b6b884d9..00000000000 --- a/core/services/fluxmonitorv2/contract_submitter.go +++ /dev/null @@ -1,67 +0,0 @@ -package fluxmonitorv2 - -import ( - "context" - "math/big" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - evmtypes "github.com/smartcontractkit/chainlink-evm/pkg/types" -) - -// FluxAggregatorABI initializes the Flux Aggregator ABI -var FluxAggregatorABI = evmtypes.MustGetABI(flux_aggregator_wrapper.FluxAggregatorABI) - -// ContractSubmitter defines an interface to submit an eth tx. -type ContractSubmitter interface { - Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error -} - -// FluxAggregatorContractSubmitter submits the polled answer in an eth tx. -type FluxAggregatorContractSubmitter struct { - flux_aggregator_wrapper.FluxAggregatorInterface - orm ORM - keyStore KeyStoreInterface - gasLimit uint64 - forwardingAllowed bool - chainID *big.Int -} - -// NewFluxAggregatorContractSubmitter constructs a new NewFluxAggregatorContractSubmitter -func NewFluxAggregatorContractSubmitter( - contract flux_aggregator_wrapper.FluxAggregatorInterface, - orm ORM, - keyStore KeyStoreInterface, - gasLimit uint64, - forwardingAllowed bool, - chainID *big.Int, -) *FluxAggregatorContractSubmitter { - return &FluxAggregatorContractSubmitter{ - FluxAggregatorInterface: contract, - orm: orm, - keyStore: keyStore, - gasLimit: gasLimit, - forwardingAllowed: forwardingAllowed, - chainID: chainID, - } -} - -// Submit submits the answer by writing a EthTx for the txmgr to -// pick up -func (c *FluxAggregatorContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { - fromAddress, err := c.keyStore.GetRoundRobinAddress(ctx, c.chainID) - if err != nil { - return err - } - - payload, err := FluxAggregatorABI.Pack("submit", roundID, submission) - if err != nil { - return errors.Wrap(err, "abi.Pack failed") - } - - return errors.Wrap( - c.orm.CreateEthTransaction(ctx, fromAddress, c.Address(), payload, c.gasLimit, idempotencyKey), - "failed to send Eth transaction", - ) -} diff --git a/core/services/fluxmonitorv2/contract_submitter_test.go b/core/services/fluxmonitorv2/contract_submitter_test.go deleted file mode 100644 index 7dfd92e5acd..00000000000 --- a/core/services/fluxmonitorv2/contract_submitter_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package fluxmonitorv2_test - -import ( - "math/big" - "testing" - - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - - "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - fmmocks "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2/mocks" -) - -func TestFluxAggregatorContractSubmitter_Submit(t *testing.T) { - t.Parallel() - var ( - fluxAggregator = mocks.NewFluxAggregator(t) - orm = fmmocks.NewORM(t) - keyStore = fmmocks.NewKeyStoreInterface(t) - gasLimit = uint64(2100) - forwardingAllowed = false - submitter = fluxmonitorv2.NewFluxAggregatorContractSubmitter(fluxAggregator, orm, keyStore, gasLimit, forwardingAllowed, testutils.FixtureChainID) - - toAddress = testutils.NewAddress() - fromAddress = testutils.NewAddress() - roundID = big.NewInt(1) - submission = big.NewInt(2) - ) - - payload, err := fluxmonitorv2.FluxAggregatorABI.Pack("submit", roundID, submission) - assert.NoError(t, err) - - keyStore.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID).Return(fromAddress, nil) - fluxAggregator.On("Address").Return(toAddress) - - idempotencyKey := uuid.New().String() - orm.On("CreateEthTransaction", mock.Anything, fromAddress, toAddress, payload, gasLimit, &idempotencyKey).Return(nil) - - err = submitter.Submit(testutils.Context(t), roundID, submission, &idempotencyKey) - assert.NoError(t, err) -} diff --git a/core/services/fluxmonitorv2/delegate.go b/core/services/fluxmonitorv2/delegate.go deleted file mode 100644 index f2628afffce..00000000000 --- a/core/services/fluxmonitorv2/delegate.go +++ /dev/null @@ -1,113 +0,0 @@ -package fluxmonitorv2 - -import ( - "context" - stderrors "errors" - "fmt" - - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-evm/pkg/chains/legacyevm" - "github.com/smartcontractkit/chainlink-evm/pkg/txmgr" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" -) - -type DelegateConfig interface { - FluxMonitor() config.FluxMonitor - JobPipeline() config.JobPipeline -} - -// Delegate represents a Flux Monitor delegate -type Delegate struct { - cfg DelegateConfig - ds sqlutil.DataSource - ethKeyStore keystore.Eth - jobORM job.ORM - pipelineORM pipeline.ORM - pipelineRunner pipeline.Runner - legacyChains legacyevm.LegacyChainContainer - lggr logger.Logger -} - -var _ job.Delegate = (*Delegate)(nil) - -// NewDelegate constructs a new delegate -func NewDelegate( - cfg DelegateConfig, - ethKeyStore keystore.Eth, - jobORM job.ORM, - pipelineORM pipeline.ORM, - pipelineRunner pipeline.Runner, - ds sqlutil.DataSource, - legacyChains legacyevm.LegacyChainContainer, - lggr logger.Logger, -) *Delegate { - return &Delegate{ - cfg: cfg, - ds: ds, - ethKeyStore: ethKeyStore, - jobORM: jobORM, - pipelineORM: pipelineORM, - pipelineRunner: pipelineRunner, - legacyChains: legacyChains, - lggr: lggr.Named("FluxMonitor"), - } -} - -// JobType implements the job.Delegate interface -func (d *Delegate) JobType() job.Type { - return job.FluxMonitor -} - -func (d *Delegate) BeforeJobCreated(spec job.Job) {} -func (d *Delegate) AfterJobCreated(spec job.Job) {} -func (d *Delegate) BeforeJobDeleted(spec job.Job) {} -func (d *Delegate) OnDeleteJob(context.Context, job.Job) error { return nil } - -// ServicesForSpec returns the flux monitor service for the job spec -func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services []job.ServiceCtx, err error) { - if jb.FluxMonitorSpec == nil { - return nil, errors.Errorf("Delegate expects a *job.FluxMonitorSpec to be present, got %v", jb) - } - chainService, err := d.legacyChains.Get(jb.FluxMonitorSpec.EVMChainID.String()) - if err != nil { - return nil, err - } - chain, ok := chainService.(legacyevm.Chain) - if !ok { - return nil, fmt.Errorf("fluxmonitor is not available in LOOP Plugin mode: %w", stderrors.ErrUnsupported) - } - - strategy := txmgrcommon.NewQueueingTxStrategy(jb.ExternalJobID, d.cfg.FluxMonitor().DefaultTransactionQueueDepth()) - var checker txmgr.TransmitCheckerSpec - if d.cfg.FluxMonitor().SimulateTransactions() { - checker.CheckerType = txmgr.TransmitCheckerTypeSimulate - } - - fm, err := NewFromJobSpec( - jb, - d.ds, - NewORM(d.ds, d.lggr, chain.TxManager(), strategy, checker), - d.jobORM, - d.pipelineORM, - NewKeyStore(d.ethKeyStore), - chain.Client(), - chain.LogBroadcaster(), - d.pipelineRunner, - chain.Config().EVM(), - chain.Config().EVM().GasEstimator(), - d.cfg.JobPipeline(), - d.lggr, - ) - if err != nil { - return nil, err - } - - return []job.ServiceCtx{fm}, nil -} diff --git a/core/services/fluxmonitorv2/deviation_checker.go b/core/services/fluxmonitorv2/deviation_checker.go deleted file mode 100644 index 0483cf2a4a2..00000000000 --- a/core/services/fluxmonitorv2/deviation_checker.go +++ /dev/null @@ -1,80 +0,0 @@ -package fluxmonitorv2 - -import ( - "github.com/shopspring/decimal" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" -) - -// DeviationThresholds carries parameters used by the threshold-trigger logic -type DeviationThresholds struct { - Rel float64 // Relative change required, i.e. |new-old|/|old| >= Rel - Abs float64 // Absolute change required, i.e. |new-old| >= Abs -} - -// DeviationChecker checks the deviation of the next answer against the current -// answer. -type DeviationChecker struct { - Thresholds DeviationThresholds - lggr logger.Logger -} - -// NewDeviationChecker constructs a new deviation checker with thresholds. -func NewDeviationChecker(rel, abs float64, lggr logger.Logger) *DeviationChecker { - return &DeviationChecker{ - Thresholds: DeviationThresholds{ - Rel: rel, - Abs: abs, - }, - lggr: logger.Sugared(lggr).Named("DeviationChecker").With("threshold", rel, "absoluteThreshold", abs), - } -} - -// NewZeroDeviationChecker constructs a new deviation checker with 0 as thresholds. -func NewZeroDeviationChecker(lggr logger.Logger) *DeviationChecker { - return NewDeviationChecker(0, 0, lggr) -} - -// OutsideDeviation checks whether the next price is outside the threshold. -// If both thresholds are zero (default value), always returns true. -func (c *DeviationChecker) OutsideDeviation(curAnswer, nextAnswer decimal.Decimal) bool { - loggerFields := []any{ - "currentAnswer", curAnswer, - "nextAnswer", nextAnswer, - } - - if c.Thresholds.Rel == 0 && c.Thresholds.Abs == 0 { - c.lggr.Debugw( - "Deviation thresholds both zero; short-circuiting deviation checker to "+ - "true, regardless of feed values", loggerFields...) - return true - } - diff := curAnswer.Sub(nextAnswer).Abs() - loggerFields = append(loggerFields, "absoluteDeviation", diff) - - if !diff.GreaterThan(decimal.NewFromFloat(c.Thresholds.Abs)) { - c.lggr.Debugw("Absolute deviation threshold not met", loggerFields...) - return false - } - - if curAnswer.IsZero() { - if nextAnswer.IsZero() { - c.lggr.Debugw("Relative deviation is undefined; can't satisfy threshold", loggerFields...) - return false - } - c.lggr.Infow("Threshold met: relative deviation is ∞", loggerFields...) - return true - } - - // 100*|new-old|/|old|: Deviation (relative to curAnswer) as a percentage - percentage := diff.Div(curAnswer.Abs()).Mul(decimal.NewFromInt(100)) - - loggerFields = append(loggerFields, "percentage", percentage) - - if percentage.LessThan(decimal.NewFromFloat(c.Thresholds.Rel)) { - c.lggr.Debugw("Relative deviation threshold not met", loggerFields...) - return false - } - c.lggr.Infow("Relative and absolute deviation thresholds both met", loggerFields...) - return true -} diff --git a/core/services/fluxmonitorv2/deviation_checker_test.go b/core/services/fluxmonitorv2/deviation_checker_test.go deleted file mode 100644 index 66b813daa1b..00000000000 --- a/core/services/fluxmonitorv2/deviation_checker_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package fluxmonitorv2_test - -import ( - "fmt" - "testing" - - "github.com/shopspring/decimal" - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/quarantine" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -type outsideDeviationRow struct { - name string - curPrice, nextPrice decimal.Decimal - threshold float64 // in percentage - absoluteThreshold float64 - expectation bool -} - -func (o outsideDeviationRow) String() string { - return fmt.Sprintf( - `{name: "%s", curPrice: %s, nextPrice: %s, threshold: %.2f, `+ - "absoluteThreshold: %f, expectation: %v}", o.name, o.curPrice, o.nextPrice, - o.threshold, o.absoluteThreshold, o.expectation) -} - -func TestDeviationChecker_OutsideDeviation(t *testing.T) { - quarantine.Flaky(t, "DX-1856") - t.Parallel() - - f, i := decimal.NewFromFloat, decimal.NewFromInt - testCases := []outsideDeviationRow{ - // Start with a huge absoluteThreshold, to test relative threshold behavior - {"0 current price, outside deviation", i(0), i(100), 2, 0, true}, - {"0 current and next price", i(0), i(0), 2, 0, false}, - - {"inside deviation", i(100), i(101), 2, 0, false}, - {"equal to deviation", i(100), i(102), 2, 0, true}, - {"outside deviation", i(100), i(103), 2, 0, true}, - {"outside deviation zero", i(100), i(0), 2, 0, true}, - - {"inside deviation, crosses 0 backwards", f(0.1), f(-0.1), 201, 0, false}, - {"equal to deviation, crosses 0 backwards", f(0.1), f(-0.1), 200, 0, true}, - {"outside deviation, crosses 0 backwards", f(0.1), f(-0.1), 199, 0, true}, - - {"inside deviation, crosses 0 forwards", f(-0.1), f(0.1), 201, 0, false}, - {"equal to deviation, crosses 0 forwards", f(-0.1), f(0.1), 200, 0, true}, - {"outside deviation, crosses 0 forwards", f(-0.1), f(0.1), 199, 0, true}, - - {"thresholds=0, deviation", i(0), i(100), 0, 0, true}, - {"thresholds=0, no deviation", i(100), i(100), 0, 0, true}, - {"thresholds=0, all zeros", i(0), i(0), 0, 0, true}, - } - - c := func(tc outsideDeviationRow) { - checker := fluxmonitorv2.NewDeviationChecker(tc.threshold, tc.absoluteThreshold, logger.TestLogger(t)) - - assert.Equal(t, tc.expectation, - checker.OutsideDeviation(tc.curPrice, tc.nextPrice), - "check on OutsideDeviation failed for %s", tc, - ) - } - - for _, tc := range testCases { - // Checks on relative threshold - t.Run(tc.name, func(t *testing.T) { c(tc) }) - // Check corresponding absolute threshold tests; make relative threshold - // always pass (as long as curPrice and nextPrice aren't both 0.) - test2 := tc - test2.threshold = 0 - // absoluteThreshold is initially zero, so any change will trigger - test2.expectation = test2.curPrice.Sub(tc.nextPrice).Abs().GreaterThan(i(0)) || - test2.absoluteThreshold == 0 - t.Run(tc.name+" threshold zeroed", func(t *testing.T) { c(test2) }) - // Huge absoluteThreshold means trigger always fails - test3 := tc - test3.absoluteThreshold = 1e307 - test3.expectation = false - t.Run(tc.name+" max absolute threshold", func(t *testing.T) { c(test3) }) - } -} diff --git a/core/services/fluxmonitorv2/flags.go b/core/services/fluxmonitorv2/flags.go deleted file mode 100644 index fc3fa380312..00000000000 --- a/core/services/fluxmonitorv2/flags.go +++ /dev/null @@ -1,77 +0,0 @@ -package fluxmonitorv2 - -import ( - "reflect" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flags_wrapper" - evmclient "github.com/smartcontractkit/chainlink-evm/pkg/client" - "github.com/smartcontractkit/chainlink-evm/pkg/utils" -) - -type Flags interface { - ContractExists() bool - IsLowered(contractAddr common.Address) (bool, error) - Address() common.Address - ParseLog(log types.Log) (generated.AbigenLog, error) -} - -// ContractFlags wraps the a contract -type ContractFlags struct { - flags_wrapper.FlagsInterface -} - -// NewFlags constructs a new Flags from a flags contract address -func NewFlags(addrHex string, ethClient evmclient.Client) (Flags, error) { - flags := &ContractFlags{} - - if addrHex == "" { - return flags, nil - } - - contractAddr := common.HexToAddress(addrHex) - contract, err := flags_wrapper.NewFlags(contractAddr, ethClient) - if err != nil { - return flags, err - } - - // This is necessary due to the unfortunate fact that assigning `nil` to an - // interface variable causes `x == nil` checks to always return false. If we - // do this here, in the constructor, we can avoid using reflection when we - // check `p.flags == nil` later in the code. - if contract != nil && !reflect.ValueOf(contract).IsNil() { - flags.FlagsInterface = contract - } - - return flags, nil -} - -// Contract returns the flags contract -func (f *ContractFlags) Contract() flags_wrapper.FlagsInterface { - return f.FlagsInterface -} - -// ContractExists returns whether a flag contract exists -func (f *ContractFlags) ContractExists() bool { - return f.FlagsInterface != nil -} - -// IsLowered determines whether the flag is lowered for a given contract. -// If a contract does not exist, it is considered to be lowered -func (f *ContractFlags) IsLowered(contractAddr common.Address) (bool, error) { - if !f.ContractExists() { - return true, nil - } - - flags, err := f.GetFlags(nil, - []common.Address{utils.ZeroAddress, contractAddr}, - ) - if err != nil { - return true, err - } - - return !flags[0] || !flags[1], nil -} diff --git a/core/services/fluxmonitorv2/flags_test.go b/core/services/fluxmonitorv2/flags_test.go deleted file mode 100644 index 33f8f8781cd..00000000000 --- a/core/services/fluxmonitorv2/flags_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package fluxmonitorv2_test - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-evm/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -func TestFlags_IsLowered(t *testing.T) { - t.Parallel() - - testCases := []struct { - name string - getFlagsResult []bool - expected bool - }{ - {"both lowered", []bool{false, false}, true}, - {"global lowered", []bool{false, true}, true}, - {"contract lowered", []bool{true, false}, true}, - {"both raised", []bool{true, true}, false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - var ( - flagsContract = mocks.NewFlags(t) - address = testutils.NewAddress() - ) - - flags := fluxmonitorv2.ContractFlags{FlagsInterface: flagsContract} - - flagsContract.On("GetFlags", mock.Anything, mock.Anything). - Run(func(args mock.Arguments) { - require.Equal(t, []common.Address{ - utils.ZeroAddress, - address, - }, args.Get(1).([]common.Address)) - }). - Return(tc.getFlagsResult, nil) - - result, err := flags.IsLowered(address) - require.NoError(t, err) - require.Equal(t, tc.expected, result) - }) - } -} diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go deleted file mode 100644 index 9960abda9e5..00000000000 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ /dev/null @@ -1,1117 +0,0 @@ -package fluxmonitorv2 - -import ( - "context" - "database/sql" - "fmt" - "math/big" - mrand "math/rand" - "reflect" - "strconv" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - "github.com/shopspring/decimal" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flags_wrapper" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - evmclient "github.com/smartcontractkit/chainlink-evm/pkg/client" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - evmutils "github.com/smartcontractkit/chainlink-evm/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/recovery" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2/promfm" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -// PollRequest defines a request to initiate a poll -type PollRequest struct { - Type PollRequestType - Timestamp time.Time -} - -// PollRequestType defines which method was used to request a poll -type PollRequestType int - -const ( - PollRequestTypeUnknown PollRequestType = iota - PollRequestTypeInitial - PollRequestTypePoll - PollRequestTypeIdle - PollRequestTypeRound - PollRequestTypeHibernation - PollRequestTypeRetry - PollRequestTypeAwaken - PollRequestTypeDrumbeat -) - -// DefaultHibernationPollPeriod defines the hibernation polling period -const DefaultHibernationPollPeriod = 24 * time.Hour - -// FluxMonitor polls external price adapters via HTTP to check for price swings. -type FluxMonitor struct { - services.Service - eng *services.Engine - logger logger.SugaredLogger - - contractAddress common.Address - oracleAddress common.Address - jobSpec job.Job - spec pipeline.Spec - runner pipeline.Runner - ds sqlutil.DataSource - orm ORM - jobORM job.ORM - pipelineORM pipeline.ORM - keyStore KeyStoreInterface - pollManager *PollManager - paymentChecker *PaymentChecker - contractSubmitter ContractSubmitter - deviationChecker *DeviationChecker - submissionChecker *SubmissionChecker - flags Flags - fluxAggregator flux_aggregator_wrapper.FluxAggregatorInterface - logBroadcaster log.Broadcaster - chainID *big.Int - - backlog *utils.BoundedPriorityQueue[log.Broadcast] - chProcessLogs chan struct{} -} - -// NewFluxMonitor returns a new instance of PollingDeviationChecker. -func NewFluxMonitor( - pipelineRunner pipeline.Runner, - jobSpec job.Job, - spec pipeline.Spec, - ds sqlutil.DataSource, - orm ORM, - jobORM job.ORM, - pipelineORM pipeline.ORM, - keyStore KeyStoreInterface, - pollManager *PollManager, - paymentChecker *PaymentChecker, - contractAddress common.Address, - contractSubmitter ContractSubmitter, - deviationChecker *DeviationChecker, - submissionChecker *SubmissionChecker, - flags Flags, - fluxAggregator flux_aggregator_wrapper.FluxAggregatorInterface, - logBroadcaster log.Broadcaster, - lggr logger.Logger, - chainID *big.Int, -) (*FluxMonitor, error) { - fm := &FluxMonitor{ - ds: ds, - runner: pipelineRunner, - jobSpec: jobSpec, - spec: spec, - orm: orm, - jobORM: jobORM, - pipelineORM: pipelineORM, - keyStore: keyStore, - pollManager: pollManager, - paymentChecker: paymentChecker, - contractAddress: contractAddress, - contractSubmitter: contractSubmitter, - deviationChecker: deviationChecker, - submissionChecker: submissionChecker, - flags: flags, - logBroadcaster: logBroadcaster, - fluxAggregator: fluxAggregator, - chainID: chainID, - backlog: utils.NewBoundedPriorityQueue[log.Broadcast](map[uint]int{ - // We want reconnecting nodes to be able to submit to a round - // that hasn't hit maxAnswers yet, as well as the newest round. - PriorityNewRoundLog: 2, - PriorityAnswerUpdatedLog: 1, - PriorityFlagChangedLog: 2, - }), - chProcessLogs: make(chan struct{}, 1), - } - fm.Service, fm.eng = services.Config{ - Name: "FluxMonitor", - Start: fm.start, - Close: fm.close, - }.NewServiceEngine(lggr) - fm.logger = logger.Sugared(fm.eng) - - return fm, nil -} - -// NewFromJobSpec constructs an instance of FluxMonitor with sane defaults and -// validation. -func NewFromJobSpec( - jobSpec job.Job, - ds sqlutil.DataSource, - orm ORM, - jobORM job.ORM, - pipelineORM pipeline.ORM, - keyStore KeyStoreInterface, - ethClient evmclient.Client, - logBroadcaster log.Broadcaster, - pipelineRunner pipeline.Runner, - cfg Config, - fcfg EvmFeeConfig, - jcfg JobPipelineConfig, - lggr logger.Logger, -) (*FluxMonitor, error) { - fmSpec := jobSpec.FluxMonitorSpec - chainId := ethClient.ConfiguredChainID() - - if !validatePollTimer(fmSpec.PollTimerDisabled, MinimumPollingInterval(jcfg), fmSpec.PollTimerPeriod) { - return nil, fmt.Errorf( - "PollTimerPeriod (%s), must be equal or greater than JobPipeline.HTTPRequest.DefaultTimeout (%s) ", - fmSpec.PollTimerPeriod, - MinimumPollingInterval(jcfg), - ) - } - - // Set up the flux aggregator - fluxAggregator, err := flux_aggregator_wrapper.NewFluxAggregator( - fmSpec.ContractAddress.Address(), - ethClient, - ) - if err != nil { - return nil, err - } - - gasLimit := fcfg.LimitDefault() - fmLimit := fcfg.LimitJobType().FM() - if jobSpec.GasLimit.Valid { - gasLimit = uint64(jobSpec.GasLimit.Uint32) - } else if fmLimit != nil { - gasLimit = uint64(*fmLimit) - } - - contractSubmitter := NewFluxAggregatorContractSubmitter( - fluxAggregator, - orm, - keyStore, - gasLimit, - jobSpec.ForwardingAllowed, - chainId, - ) - - flags, err := NewFlags(cfg.FlagsContractAddress(), ethClient) - logger.Sugared(lggr).ErrorIf(err, - "Error creating Flags contract instance, check address: "+cfg.FlagsContractAddress(), - ) - - paymentChecker := &PaymentChecker{ - MinContractPayment: cfg.MinContractPayment(), - MinJobPayment: fmSpec.MinPayment, - } - - min, err := fluxAggregator.MinSubmissionValue(nil) - if err != nil { - return nil, err - } - - max, err := fluxAggregator.MaxSubmissionValue(nil) - if err != nil { - return nil, err - } - - fmLogger := logger.With(lggr, - "jobID", jobSpec.ID, - "contract", fmSpec.ContractAddress.Hex(), - ) - - pollManager, err := NewPollManager( - PollManagerConfig{ - PollTickerInterval: fmSpec.PollTimerPeriod, - PollTickerDisabled: fmSpec.PollTimerDisabled, - IdleTimerPeriod: fmSpec.IdleTimerPeriod, - IdleTimerDisabled: fmSpec.IdleTimerDisabled, - DrumbeatSchedule: fmSpec.DrumbeatSchedule, - DrumbeatEnabled: fmSpec.DrumbeatEnabled, - DrumbeatRandomDelay: fmSpec.DrumbeatRandomDelay, - HibernationPollPeriod: DefaultHibernationPollPeriod, // Not currently configurable - MinRetryBackoffDuration: 1 * time.Minute, - MaxRetryBackoffDuration: 1 * time.Hour, - }, - fmLogger, - ) - if err != nil { - return nil, err - } - - return NewFluxMonitor( - pipelineRunner, - jobSpec, - *jobSpec.PipelineSpec, - ds, - orm, - jobORM, - pipelineORM, - keyStore, - pollManager, - paymentChecker, - fmSpec.ContractAddress.Address(), - contractSubmitter, - NewDeviationChecker( - float64(fmSpec.Threshold), - float64(fmSpec.AbsoluteThreshold), - fmLogger, - ), - NewSubmissionChecker(min, max), - flags, - fluxAggregator, - logBroadcaster, - fmLogger, - chainId, - ) -} - -const ( - PriorityFlagChangedLog uint = 0 - PriorityNewRoundLog uint = 1 - PriorityAnswerUpdatedLog uint = 2 -) - -// Start implements the job.Service interface. It begins the CSP consumer in a -// single goroutine to poll the price adapters and listen to NewRound events. -func (fm *FluxMonitor) start(context.Context) error { - fm.eng.Go(fm.consume) - return nil -} - -func (fm *FluxMonitor) IsHibernating() bool { - if !fm.flags.ContractExists() { - return false - } - - isFlagLowered, err := fm.flags.IsLowered(fm.contractAddress) - if err != nil { - fm.logger.Errorf("unable to determine hibernation status: %v", err) - - return false - } - - return !isFlagLowered -} - -// close stops this instance from -// polling, cleaning up resources. -func (fm *FluxMonitor) close() error { - fm.pollManager.Stop() - - return nil -} - -// JobID implements the listener.Listener interface. -func (fm *FluxMonitor) JobID() int32 { return fm.spec.JobID } - -// HandleLog processes the contract logs -func (fm *FluxMonitor) HandleLog(ctx context.Context, broadcast log.Broadcast) { - log := broadcast.DecodedLog() - if log == nil || reflect.ValueOf(log).IsNil() { - fm.logger.Panic("HandleLog: failed to handle log of type nil") - } - - switch log := log.(type) { - case *flux_aggregator_wrapper.FluxAggregatorNewRound: - fm.backlog.Add(PriorityNewRoundLog, broadcast) - - case *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated: - fm.backlog.Add(PriorityAnswerUpdatedLog, broadcast) - - case *flags_wrapper.FlagsFlagRaised: - if log.Subject == evmutils.ZeroAddress || log.Subject == fm.contractAddress { - fm.backlog.Add(PriorityFlagChangedLog, broadcast) - } - - case *flags_wrapper.FlagsFlagLowered: - if log.Subject == evmutils.ZeroAddress || log.Subject == fm.contractAddress { - fm.backlog.Add(PriorityFlagChangedLog, broadcast) - } - - default: - fm.logger.Warnf("unexpected log type %T", log) - return - } - - select { - case fm.chProcessLogs <- struct{}{}: - default: - } -} - -func (fm *FluxMonitor) consume(ctx context.Context) { - if err := fm.SetOracleAddress(ctx); err != nil { - fm.logger.Warnw( - "unable to set oracle address, this flux monitor job may not work correctly", - "err", err, - ) - } - - // Subscribe to contract logs - unsubscribe := fm.logBroadcaster.Register(fm, log.ListenerOpts{ - Contract: fm.fluxAggregator.Address(), - ParseLog: fm.fluxAggregator.ParseLog, - LogsWithTopics: map[common.Hash][][]log.Topic{ - flux_aggregator_wrapper.FluxAggregatorNewRound{}.Topic(): nil, - flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}.Topic(): nil, - }, - MinIncomingConfirmations: 0, - }) - defer unsubscribe() - - if fm.flags.ContractExists() { - unsubscribe := fm.logBroadcaster.Register(fm, log.ListenerOpts{ - Contract: fm.flags.Address(), - ParseLog: fm.flags.ParseLog, - LogsWithTopics: map[common.Hash][][]log.Topic{ - flags_wrapper.FlagsFlagLowered{}.Topic(): nil, - flags_wrapper.FlagsFlagRaised{}.Topic(): nil, - }, - MinIncomingConfirmations: 0, - }) - defer unsubscribe() - } - - fm.pollManager.Start(fm.IsHibernating(), fm.initialRoundState()) - - tickLogger := fm.logger.With( - "pollInterval", fm.pollManager.cfg.PollTickerInterval, - "idlePeriod", fm.pollManager.cfg.IdleTimerPeriod, - ) - - for { - select { - case <-ctx.Done(): - return - - case <-fm.chProcessLogs: - recovery.WrapRecover(fm.logger, func() { fm.processLogs(ctx) }) - - case at := <-fm.pollManager.PollTickerTicks(): - tickLogger.Debugf("Poll ticker fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypePoll, fm.deviationChecker, nil) - }) - - case at := <-fm.pollManager.IdleTimerTicks(): - tickLogger.Debugf("Idle timer fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypeIdle, NewZeroDeviationChecker(fm.logger), nil) - }) - - case at := <-fm.pollManager.RoundTimerTicks(): - tickLogger.Debugf("Round timer fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypeRound, fm.deviationChecker, nil) - }) - - case at := <-fm.pollManager.HibernationTimerTicks(): - tickLogger.Debugf("Hibernation timer fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypeHibernation, NewZeroDeviationChecker(fm.logger), nil) - }) - - case at := <-fm.pollManager.RetryTickerTicks(): - tickLogger.Debugf("Retry ticker fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypeRetry, NewZeroDeviationChecker(fm.logger), nil) - }) - - case at := <-fm.pollManager.DrumbeatTicks(): - tickLogger.Debugf("Drumbeat ticker fired on %v", formatTime(at)) - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, PollRequestTypeDrumbeat, NewZeroDeviationChecker(fm.logger), nil) - }) - - case request := <-fm.pollManager.Poll(): - switch request.Type { - case PollRequestTypeUnknown: - break - default: - recovery.WrapRecover(fm.logger, func() { - fm.pollIfEligible(ctx, request.Type, fm.deviationChecker, nil) - }) - } - } - } -} - -func formatTime(at time.Time) string { - ago := time.Since(at) - return fmt.Sprintf("%v (%v ago)", at.UTC().Format(time.RFC3339), ago) -} - -// SetOracleAddress sets the oracle address which matches the node's keys. -// If none match, it uses the first available key -func (fm *FluxMonitor) SetOracleAddress(ctx context.Context) error { - oracleAddrs, err := fm.fluxAggregator.GetOracles(nil) - if err != nil { - fm.logger.Error("failed to get list of oracles from FluxAggregator contract") - return errors.Wrap(err, "failed to get list of oracles from FluxAggregator contract") - } - keys, err := fm.keyStore.EnabledKeysForChain(ctx, fm.chainID) - if err != nil { - return errors.Wrap(err, "failed to load keys") - } - for _, k := range keys { - for _, oracleAddr := range oracleAddrs { - if k.Address == oracleAddr { - fm.oracleAddress = oracleAddr - return nil - } - } - } - - log := fm.logger.With( - "keys", keys, - "oracleAddresses", oracleAddrs, - ) - - if len(keys) > 0 { - addr := keys[0].Address - log.Warnw("None of the node's keys matched any oracle addresses, using first available key. This flux monitor job may not work correctly", - "address", addr.Hex(), - ) - fm.oracleAddress = addr - - return nil - } - - log.Error("No keys found. This flux monitor job may not work correctly") - return errors.New("No keys found") -} - -func (fm *FluxMonitor) processLogs(ctx context.Context) { - for ctx.Err() == nil && !fm.backlog.Empty() { - broadcast := fm.backlog.Take() - fm.processBroadcast(ctx, broadcast) - } -} - -func (fm *FluxMonitor) processBroadcast(ctx context.Context, broadcast log.Broadcast) { - // If the log is a duplicate of one we've seen before, ignore it (this - // happens because of the LogBroadcaster's backfilling behavior). - consumed, err := fm.logBroadcaster.WasAlreadyConsumed(ctx, broadcast) - - if err != nil { - fm.logger.Errorf("Error determining if log was already consumed: %v", err) - return - } else if consumed { - fm.logger.Debug("Log was already consumed by Flux Monitor, skipping") - return - } - - started := time.Now() - decodedLog := broadcast.DecodedLog() - switch log := decodedLog.(type) { - case *flux_aggregator_wrapper.FluxAggregatorNewRound: - fm.respondToNewRoundLog(ctx, *log, broadcast) - case *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated: - fm.respondToAnswerUpdatedLog(*log) - fm.markLogAsConsumed(ctx, broadcast, decodedLog, started) - case *flags_wrapper.FlagsFlagRaised: - fm.respondToFlagsRaisedLog() - fm.markLogAsConsumed(ctx, broadcast, decodedLog, started) - case *flags_wrapper.FlagsFlagLowered: - // Only reactivate if it is hibernating - if fm.pollManager.isHibernating.Load() { - fm.pollManager.Awaken(fm.initialRoundState()) - fm.pollIfEligible(ctx, PollRequestTypeAwaken, NewZeroDeviationChecker(fm.logger), broadcast) - } - default: - fm.logger.Errorf("unknown log %v of type %T", log, log) - } -} - -func (fm *FluxMonitor) markLogAsConsumed(ctx context.Context, broadcast log.Broadcast, decodedLog any, started time.Time) { - if err := fm.logBroadcaster.MarkConsumed(ctx, nil, broadcast); err != nil { - fm.logger.Errorw("Failed to mark log as consumed", - "err", err, "logType", fmt.Sprintf("%T", decodedLog), "log", broadcast.String(), "elapsed", time.Since(started)) - } -} - -func (fm *FluxMonitor) respondToFlagsRaisedLog() { - fm.logger.Debug("FlagsFlagRaised log") - // check the contract before hibernating, because one flag could be lowered - // while the other flag remains raised - isFlagLowered, err := fm.flags.IsLowered(fm.contractAddress) - fm.logger.ErrorIf(err, "Error determining if flag is still raised") - if !isFlagLowered { - fm.pollManager.Hibernate() - } -} - -// The AnswerUpdated log tells us that round has successfully closed with a new -// answer. We update our view of the oracleRoundState in case this log was -// generated by a chain reorg. -func (fm *FluxMonitor) respondToAnswerUpdatedLog(log flux_aggregator_wrapper.FluxAggregatorAnswerUpdated) { - answerUpdatedLogger := fm.logger.With( - "round", log.RoundId, - "answer", log.Current.String(), - "timestamp", log.UpdatedAt.String(), - ) - - answerUpdatedLogger.Debug("AnswerUpdated log") - - roundState, err := fm.roundState(0) - if err != nil { - answerUpdatedLogger.Errorf("could not fetch oracleRoundState: %v", err) - - return - } - - fm.pollManager.Reset(roundState) -} - -// The NewRound log tells us that an oracle has initiated a new round. This tells us that we -// need to poll and submit an answer to the contract regardless of the deviation. -func (fm *FluxMonitor) respondToNewRoundLog(ctx context.Context, log flux_aggregator_wrapper.FluxAggregatorNewRound, lb log.Broadcast) { - started := time.Now() - - newRoundLogger := fm.logger.With( - "round", log.RoundId, - "startedBy", log.StartedBy.Hex(), - "startedAt", log.StartedAt.String(), - "startedAtUtc", time.Unix(log.StartedAt.Int64(), 0).UTC().Format(time.RFC3339), - ) - var markConsumed = true - defer func() { - if markConsumed { - if err := fm.logBroadcaster.MarkConsumed(ctx, nil, lb); err != nil { - fm.logger.Errorw("Failed to mark log consumed", "err", err, "log", lb.String()) - } - } - }() - - newRoundLogger.Debug("NewRound log") - promfm.SetBigInt(promfm.SeenRound.WithLabelValues(strconv.Itoa(int(fm.spec.JobID))), log.RoundId) - - // - // NewRound answer submission logic: - // - Any log that reaches this point, regardless of chain reorgs or log backfilling, is one that we have - // not seen before. Therefore, we should consider acting upon it. - // - We always take the round ID from the log, rather than the round ID suggested by `.RoundState`. The - // reason is that if two NewRound logs come in in rapid succession, and we submit a tx for the first, - // the `.ReportableRoundID` field in the roundState() response for the 2nd log will not reflect the - // fact that we've submitted for the first round (assuming it hasn't been mined yet). - // - In the event of a reorg that pushes our previous submissions back into the mempool, we can rely on the - // TxManager to ensure they end up being mined into blocks, but this may cause them to revert if they - // are mined in an order that violates certain conditions in the FluxAggregator (restartDelay, etc.). - // Therefore, the cleanest solution at present is to resubmit for the reorged rounds. The drawback - // of this approach is that one or the other submission tx for a given round will revert, costing the - // node operator some gas. The benefit is that those submissions are guaranteed to be made, ensuring - // that we have high data availability (and also ensuring that node operators get paid). - // - There are a few straightforward cases where we don't want to submit: - // - When we're not eligible - // - When the aggregator is underfunded - // - When we were the initiator of the round (i.e. we've received our own NewRound log) - // - There are a few more nuanced cases as well: - // - When our node polls at the same time as another node, and both attempt to start a round. In that - // case, it's possible that the other node will start the round, and our node will see the NewRound - // log and try to submit again. - // - When the poll ticker fires very soon after we've responded to a NewRound log. - // - // To handle these more nuanced cases, we record round IDs and whether we've submitted for those rounds - // in the DB. If we see we've already submitted for a given round, we simply bail out. - // - // However, in the case of a chain reorganization, we might see logs with round IDs that we've already - // seen. As mentioned above, we want to re-respond to these rounds to ensure high data availability. - // Therefore, if a log arrives with a round ID that is < the most recent that we submitted to, we delete - // all of the round IDs in the DB back to (and including) the incoming round ID. This essentially - // rewinds the system back to a state wherein those reorg'ed rounds never occurred, allowing it to move - // forward normally. - // - // There is one small exception: if the reorg is fairly shallow, and only un-starts a single round, we - // do not need to resubmit, because the TxManager will ensure that our existing submission gets back - // into the chain. There is a very small risk that one of the nodes in the quorum (namely, whichever - // one started the previous round) will have its existing submission mined first, thereby violating - // the restartDelay, but as this risk is isolated to a single node, the round will not time out and - // go stale. We consider this acceptable. - // - - logRoundID := uint32(log.RoundId.Uint64()) - - // We always want to reset the idle timer upon receiving a NewRound log, so we do it before any `return` statements. - fm.pollManager.ResetIdleTimer(log.StartedAt.Uint64()) - - mostRecentRoundID, err := fm.orm.MostRecentFluxMonitorRoundID(ctx, fm.contractAddress) - if err != nil && !errors.Is(err, sql.ErrNoRows) { - newRoundLogger.Errorf("error fetching Flux Monitor most recent round ID from DB: %v", err) - return - } - - roundStats, jobRunStatus, err := fm.statsAndStatusForRound(ctx, logRoundID, 1) - if err != nil { - newRoundLogger.Errorf("error determining round stats / run status for round: %v", err) - return - } - - if logRoundID < mostRecentRoundID && roundStats.NumNewRoundLogs > 0 { - newRoundLogger.Debugf("Received an older round log (and number of previously received NewRound logs is: %v) - "+ - "a possible reorg, hence deleting round ids from %v to %v", roundStats.NumNewRoundLogs, logRoundID, mostRecentRoundID) - err = fm.orm.DeleteFluxMonitorRoundsBackThrough(ctx, fm.contractAddress, logRoundID) - if err != nil { - newRoundLogger.Errorf("error deleting reorged Flux Monitor rounds from DB: %v", err) - return - } - - // as all newer stats were deleted, at this point a new round stats entry will be created - roundStats, err = fm.orm.FindOrCreateFluxMonitorRoundStats(ctx, fm.contractAddress, logRoundID, 1) - if err != nil { - newRoundLogger.Errorf("error determining subsequent round stats for round: %v", err) - return - } - } - - if roundStats.NumSubmissions > 0 { - // This indicates either that: - // - We tried to start a round at the same time as another node, and their transaction was mined first, or - // - The chain experienced a shallow reorg that unstarted the current round. - // If our previous attempt is still pending, return early and don't re-submit - // If our previous attempt is already over (completed or errored), we should retry - newRoundLogger.Debugf("There are already %v existing submissions to this round, while job run status is: %v", roundStats.NumSubmissions, jobRunStatus) - if !jobRunStatus.Finished() { - newRoundLogger.Debug("Ignoring new round request: started round simultaneously with another node") - return - } - } - - // Ignore rounds we started - if fm.oracleAddress == log.StartedBy { - newRoundLogger.Info("Ignoring new round request: we started this round") - return - } - - // Ignore rounds we're not eligible for, or for which we won't be paid - roundState, err := fm.roundState(logRoundID) - if err != nil { - newRoundLogger.Errorf("Ignoring new round request: error fetching eligibility from contract: %v", err) - return - } - - fm.pollManager.Reset(roundState) - err = fm.checkEligibilityAndAggregatorFunding(roundState) - if err != nil { - newRoundLogger.Infof("Ignoring new round request: %v", err) - return - } - - newRoundLogger.Info("Responding to new round request") - - // Best effort to attach metadata. - var metaDataForBridge map[string]any - lrd, err := fm.fluxAggregator.LatestRoundData(nil) - if err != nil { - newRoundLogger.Warnw("Couldn't read latest round data for request meta", "err", err) - } else { - metaDataForBridge, err = bridges.MarshalBridgeMetaData(lrd.Answer, lrd.UpdatedAt) - if err != nil { - newRoundLogger.Warnw("Error marshalling roundState for request meta", "err", err) - } - } - - vars := pipeline.NewVarsFrom(map[string]any{ - "jobSpec": map[string]any{ - "databaseID": fm.jobSpec.ID, - "externalJobID": fm.jobSpec.ExternalJobID, - "name": fm.jobSpec.Name.ValueOrZero(), - "evmChainID": fm.chainID.String(), - }, - "jobRun": map[string]any{ - "meta": metaDataForBridge, - }, - }) - - // Call the v2 pipeline to execute a new job run - run, results, err := fm.runner.ExecuteRun(ctx, fm.spec, vars) - if err != nil { - newRoundLogger.Errorw(fmt.Sprintf("error executing new run for job ID %v name %v", fm.spec.JobID, fm.spec.JobName), "err", err) - return - } - result, err := results.FinalResult().SingularResult() - if err != nil || result.Error != nil { - newRoundLogger.Errorw("can't fetch answer", "err", err, "result", result) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, "Error polling") - return - } - answer, err := utils.ToDecimal(result.Value) - if err != nil { - newRoundLogger.Errorw(fmt.Sprintf("error executing new run for job ID %v name %v", fm.spec.JobID, fm.spec.JobName), "err", err) - return - } - - if !fm.isValidSubmission(ctx, newRoundLogger, answer, started) { - return - } - - if roundState.PaymentAmount == nil { - newRoundLogger.Error("roundState.PaymentAmount shouldn't be nil") - } - - err = fm.Transact(ctx, func(tx sqlutil.DataSource) error { - if err2 := fm.runner.InsertFinishedRun(ctx, tx, run, false); err2 != nil { - return err2 - } - if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, &log); err2 != nil { - return err2 - } - return fm.logBroadcaster.MarkConsumed(ctx, tx, lb) - }) - // Either the tx failed and we want to reprocess the log, or it succeeded and already marked it consumed - markConsumed = false - if err != nil { - newRoundLogger.Errorf("unable to create job run: %v", err) - return - } -} - -func (fm *FluxMonitor) Transact(ctx context.Context, fn func(sqlutil.DataSource) error) error { - return sqlutil.TransactDataSource(ctx, fm.ds, nil, fn) -} - -var ( - // ErrNotEligible defines when the round is not eligible for submission - ErrNotEligible = errors.New("not eligible to submit") - // ErrUnderfunded defines when the aggregator does not have sufficient funds - ErrUnderfunded = errors.New("aggregator is underfunded") - // ErrPaymentTooLow defines when the round payment is too low - ErrPaymentTooLow = errors.New("round payment amount < minimum contract payment") -) - -func (fm *FluxMonitor) checkEligibilityAndAggregatorFunding(roundState flux_aggregator_wrapper.OracleRoundState) error { - if !roundState.EligibleToSubmit { - return ErrNotEligible - } else if !fm.paymentChecker.SufficientFunds( - roundState.AvailableFunds, - roundState.PaymentAmount, - roundState.OracleCount, - ) { - return ErrUnderfunded - } else if !fm.paymentChecker.SufficientPayment(roundState.PaymentAmount) { - return ErrPaymentTooLow - } - return nil -} - -func (fm *FluxMonitor) pollIfEligible(ctx context.Context, pollReq PollRequestType, deviationChecker *DeviationChecker, broadcast log.Broadcast) { - started := time.Now() - - l := fm.logger.With( - "threshold", deviationChecker.Thresholds.Rel, - "absoluteThreshold", deviationChecker.Thresholds.Abs, - ) - var markConsumed = true - defer func() { - if markConsumed && broadcast != nil { - if err := fm.logBroadcaster.MarkConsumed(ctx, nil, broadcast); err != nil { - l.Errorw("Failed to mark log consumed", "err", err, "log", broadcast.String()) - } - } - }() - - if pollReq != PollRequestTypeHibernation && fm.pollManager.isHibernating.Load() { - l.Warnw("Skipping poll because a ticker fired while hibernating") - return - } - - if !fm.logBroadcaster.IsConnected() { - l.Warnw("LogBroadcaster is not connected to Ethereum node, skipping poll") - return - } - - // - // Poll ticker submission logic: - // - We avoid saving on-chain state wherever possible. Therefore, we do not know which round we should be - // submitting for when the pollTicker fires. - // - We pass 0 into `roundState()`, and the FluxAggregator returns a suggested roundID for us to - // submit to, as well as our eligibility to submit to that round. - // - If the poll ticker fires very soon after we've responded to a NewRound log, and our tx has not been - // mined, we risk double-submitting for a round. To detect this, we check the DB to see whether - // we've responded to this round already, and bail out if so. - // - - // Ask the FluxAggregator which round we should be submitting to, and what the state of that round is. - roundState, err := fm.roundState(0) - if err != nil { - l.Errorw("unable to determine eligibility to submit from FluxAggregator contract", "err", err) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, - "Unable to call roundState method on provided contract. Check contract address.", - ) - - return - } - - l = l.With("reportableRound", roundState.RoundId) - - // Because drumbeat ticker may fire at the same time on multiple nodes, we wait a short random duration - // after getting a recommended round id, to avoid starting multiple rounds in case of chains with instant tx confirmation - if pollReq == PollRequestTypeDrumbeat && fm.pollManager.cfg.DrumbeatEnabled && fm.pollManager.cfg.DrumbeatRandomDelay > 0 { - // #nosec - delay := time.Duration(mrand.Int63n(int64(fm.pollManager.cfg.DrumbeatRandomDelay))) - l.Infof("waiting %v (of max: %v) before continuing...", delay, fm.pollManager.cfg.DrumbeatRandomDelay) - time.Sleep(delay) - - roundStateNew, err2 := fm.roundState(roundState.RoundId) - if err2 != nil { - l.Errorw("unable to determine eligibility to submit from FluxAggregator contract", "err", err2) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, - "Unable to call roundState method on provided contract. Check contract address.", - ) - - return - } - roundState = roundStateNew - } - - fm.pollManager.Reset(roundState) - // Retry if a idle timer fails - defer func() { - if pollReq == PollRequestTypeIdle { - if err != nil { - if fm.pollManager.StartRetryTicker() { - min, max := fm.pollManager.retryTicker.Bounds() - l.Debugw(fmt.Sprintf("started retry ticker (frequency between: %v - %v) because of error: '%v'", min, max, err.Error())) - } - return - } - fm.pollManager.StopRetryTicker() - } - }() - - roundStats, jobRunStatus, err := fm.statsAndStatusForRound(ctx, roundState.RoundId, 0) - if err != nil { - l.Errorw("error determining round stats / run status for round", "err", err) - - return - } - - // If we've already successfully submitted to this round (ie through a NewRound log) - // and the associated JobRun hasn't errored, skip polling - if roundStats.NumSubmissions > 0 && !jobRunStatus.Errored() { - l.Infow("skipping poll: round already answered, tx unconfirmed", "jobRunStatus", jobRunStatus) - - return - } - - // Don't submit if we're not eligible, or won't get paid - err = fm.checkEligibilityAndAggregatorFunding(roundState) - if err != nil { - l.Infof("skipping poll: %v", err) - - return - } - - var metaDataForBridge map[string]any - lrd, err := fm.fluxAggregator.LatestRoundData(nil) - if err != nil { - l.Warnw("Couldn't read latest round data for request meta", "err", err) - } else { - metaDataForBridge, err = bridges.MarshalBridgeMetaData(lrd.Answer, lrd.UpdatedAt) - if err != nil { - l.Warnw("Error marshalling roundState for request meta", "err", err) - } - } - - // Call the v2 pipeline to execute a new pipeline run - // Note: we expect the FM pipeline to scale the fetched answer by the same - // amount as "decimals" in the FM contract. - - vars := pipeline.NewVarsFrom(map[string]any{ - "jobSpec": map[string]any{ - "databaseID": fm.jobSpec.ID, - "externalJobID": fm.jobSpec.ExternalJobID, - "name": fm.jobSpec.Name.ValueOrZero(), - "evmChainID": fm.chainID.String(), - }, - "jobRun": map[string]any{ - "meta": metaDataForBridge, - }, - }) - - run, results, err := fm.runner.ExecuteRun(ctx, fm.spec, vars) - if err != nil { - l.Errorw("can't fetch answer", "err", err) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, "Error polling") - return - } - result, err := results.FinalResult().SingularResult() - if err != nil || result.Error != nil { - l.Errorw("can't fetch answer", "err", err, "result", result) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, "Error polling") - return - } - answer, err := utils.ToDecimal(result.Value) - if err != nil { - l.Errorw(fmt.Sprintf("error executing new run for job ID %v name %v", fm.spec.JobID, fm.spec.JobName), "err", err) - return - } - - if !fm.isValidSubmission(ctx, l, answer, started) { - return - } - - jobID := strconv.Itoa(int(fm.spec.JobID)) - latestAnswer := decimal.NewFromBigInt(roundState.LatestSubmission, 0) - promfm.SetDecimal(promfm.SeenValue.WithLabelValues(jobID), answer) - - l = l.With( - "latestAnswer", latestAnswer, - "answer", answer, - ) - - if roundState.RoundId > 1 && !deviationChecker.OutsideDeviation(latestAnswer, answer) { - l.Debugw("deviation < threshold, not submitting") - return - } - - if roundState.RoundId > 1 { - l.Infow("deviation > threshold, submitting") - } else { - l.Infow("starting first round") - } - - if roundState.PaymentAmount == nil { - l.Error("roundState.PaymentAmount shouldn't be nil") - } - - err = fm.Transact(ctx, func(tx sqlutil.DataSource) error { - if err2 := fm.runner.InsertFinishedRun(ctx, tx, run, true); err2 != nil { - return err2 - } - if err2 := fm.queueTransactionForTxm(ctx, tx, run.ID, answer, roundState.RoundId, nil); err2 != nil { - return err2 - } - if broadcast != nil { - // In the case of a flag lowered, the pollEligible call is triggered by a log. - return fm.logBroadcaster.MarkConsumed(ctx, tx, broadcast) - } - return nil - }) - // Either the tx failed and we want to reprocess the log, or it succeeded and already marked it consumed - markConsumed = false - if err != nil { - l.Errorw("can't create job run", "err", err) - return - } - - promfm.SetDecimal(promfm.ReportedValue.WithLabelValues(jobID), answer) - promfm.SetUint32(promfm.ReportedRound.WithLabelValues(jobID), roundState.RoundId) -} - -// If the answer is outside the allowable range, log an error and don't submit. -// to avoid an onchain reversion. -func (fm *FluxMonitor) isValidSubmission(ctx context.Context, l logger.Logger, answer decimal.Decimal, started time.Time) bool { - if fm.submissionChecker.IsValid(answer) { - return true - } - - l.Errorw("answer is outside acceptable range", - "min", fm.submissionChecker.Min, - "max", fm.submissionChecker.Max, - "answer", answer, - ) - fm.jobORM.TryRecordError(ctx, fm.spec.JobID, "Answer is outside acceptable range") - - jobId := fm.spec.JobID - jobName := fm.spec.JobName - elapsed := time.Since(started) - pipeline.PromPipelineTaskExecutionTime.WithLabelValues(strconv.Itoa(int(jobId)), jobName, "", job.FluxMonitor.String()).Set(float64(elapsed)) - pipeline.PromPipelineRunErrors.WithLabelValues(strconv.Itoa(int(jobId)), jobName).Inc() - pipeline.PromPipelineRunTotalTimeToCompletion.WithLabelValues(strconv.Itoa(int(jobId)), jobName).Set(float64(elapsed)) - pipeline.PromPipelineTasksTotalFinished.WithLabelValues(strconv.Itoa(int(jobId)), jobName, "", job.FluxMonitor.String(), "", "error").Inc() - return false -} - -func (fm *FluxMonitor) roundState(roundID uint32) (flux_aggregator_wrapper.OracleRoundState, error) { - return fm.fluxAggregator.OracleRoundState(nil, fm.oracleAddress, roundID) -} - -// initialRoundState fetches the round information that the fluxmonitor should use when starting -// new jobs. Choosing the correct round on startup is key to setting timers correctly. -func (fm *FluxMonitor) initialRoundState() flux_aggregator_wrapper.OracleRoundState { - defaultRoundState := flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - } - latestRoundData, err := fm.fluxAggregator.LatestRoundData(nil) - if err != nil { - fm.logger.Warnf( - "unable to retrieve latestRoundData for FluxAggregator contract - defaulting "+ - "to current time for tickers: %v", - err, - ) - return defaultRoundState - } - roundID := uint32(latestRoundData.RoundId.Uint64()) - latestRoundState, err := fm.fluxAggregator.OracleRoundState(nil, fm.oracleAddress, roundID) - if err != nil { - fm.logger.Warnf( - "unable to call roundState for latest round, round: %d, err: %v", - latestRoundData.RoundId, - err, - ) - return defaultRoundState - } - return latestRoundState -} - -func (fm *FluxMonitor) queueTransactionForTxm(ctx context.Context, tx sqlutil.DataSource, runID int64, answer decimal.Decimal, roundID uint32, log *flux_aggregator_wrapper.FluxAggregatorNewRound) error { - // Use pipeline run ID to generate globally unique key that can correlate this run to a Tx - idempotencyKey := fmt.Sprintf("fluxmonitor-%d", runID) - // Submit the Eth Tx - err := fm.contractSubmitter.Submit( - ctx, - new(big.Int).SetInt64(int64(roundID)), - answer.BigInt(), - &idempotencyKey, - ) - if err != nil { - fm.logger.Errorw("failed to submit Tx to TXM", "err", err) - return err - } - - numLogs := uint(0) - if log != nil { - numLogs = 1 - } - // Update the flux monitor round stats - err = fm.orm.WithDataSource(tx).UpdateFluxMonitorRoundStats( - ctx, - fm.contractAddress, - roundID, - runID, - numLogs, - ) - if err != nil { - fm.logger.Errorw( - fmt.Sprintf("error updating FM round submission count: %v", err), - "roundID", roundID, - ) - - return err - } - - return nil -} - -func (fm *FluxMonitor) statsAndStatusForRound(ctx context.Context, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, pipeline.RunStatus, error) { - roundStats, err := fm.orm.FindOrCreateFluxMonitorRoundStats(ctx, fm.contractAddress, roundID, newRoundLogs) - if err != nil { - return FluxMonitorRoundStatsV2{}, pipeline.RunStatusUnknown, err - } - - // JobRun will not exist if this is the first time responding to this round - var run pipeline.Run - if roundStats.PipelineRunID.Valid { - run, err = fm.pipelineORM.FindRun(ctx, roundStats.PipelineRunID.Int64) - if err != nil { - return FluxMonitorRoundStatsV2{}, pipeline.RunStatusUnknown, err - } - } - - return roundStats, run.Status(), nil -} diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go deleted file mode 100644 index cb17e391859..00000000000 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ /dev/null @@ -1,1967 +0,0 @@ -package fluxmonitorv2_test - -import ( - "fmt" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/google/uuid" - "github.com/jmoiron/sqlx" - "github.com/onsi/gomega" - "github.com/pkg/errors" - "github.com/shopspring/decimal" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" - - "github.com/smartcontractkit/quarantine" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - - "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - "github.com/smartcontractkit/chainlink-evm/pkg/txmgr" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" - logmocks "github.com/smartcontractkit/chainlink/v2/common/log/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - corenull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - fmmocks "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - jobmocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" -) - -const oracleCount uint8 = 17 - -var ( - defaultMinimumContractPayment = assets.NewLinkFromJuels(10_000_000_000_000) // 0.00001 LINK -) - -type answerSet struct{ latestAnswer, polledAnswer int64 } - -func newORM(t *testing.T, db *sqlx.DB, txm txmgr.TxManager) fluxmonitorv2.ORM { - return fluxmonitorv2.NewORM(db, logger.TestLogger(t), txm, txmgrcommon.NewSendEveryStrategy(), txmgr.TransmitCheckerSpec{}) -} - -var ( - now = func() uint64 { return uint64(time.Now().UTC().Unix()) } - nilOpts *bind.CallOpts - - makeRoundDataForRoundID = func(roundID uint32) flux_aggregator_wrapper.LatestRoundData { - return flux_aggregator_wrapper.LatestRoundData{ - RoundId: big.NewInt(int64(roundID)), - } - } - freshContractRoundDataResponse = func() (flux_aggregator_wrapper.LatestRoundData, error) { - return flux_aggregator_wrapper.LatestRoundData{}, errors.New("No data present") - } - - contractAddress = testutils.NewAddress() - threshold = float64(0.5) - absoluteThreshold = float64(0.01) - idleTimerPeriod = time.Minute - pipelineSpec = pipeline.Spec{ - ID: 1, - DotDagSource: ` -// data source 1 -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds1_parse [type=jsonparse path="latest"]; - -// data source 2 -ds2 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds2_parse [type=jsonparse path="latest"]; - -ds1 -> ds1_parse -> answer1; -ds2 -> ds2_parse -> answer1; - -answer1 [type=median index=0]; -`, - JobID: 1, - } -) - -// testMocks defines all the mock interfaces used by the Flux Monitor -type testMocks struct { - fluxAggregator *mocks.FluxAggregator - logBroadcast *logmocks.Broadcast - logBroadcaster *logmocks.Broadcaster - orm *fmmocks.ORM - jobORM *jobmocks.ORM - pipelineORM *pipelinemocks.ORM - pipelineRunner *pipelinemocks.Runner - keyStore *fmmocks.KeyStoreInterface - contractSubmitter *fmmocks.ContractSubmitter - flags *fmmocks.Flags -} - -func setupMocks(t *testing.T) *testMocks { - t.Helper() - - tm := &testMocks{ - fluxAggregator: mocks.NewFluxAggregator(t), - logBroadcast: logmocks.NewBroadcast(t), - logBroadcaster: logmocks.NewBroadcaster(t), - orm: fmmocks.NewORM(t), - jobORM: jobmocks.NewORM(t), - pipelineORM: pipelinemocks.NewORM(t), - pipelineRunner: pipelinemocks.NewRunner(t), - keyStore: fmmocks.NewKeyStoreInterface(t), - contractSubmitter: fmmocks.NewContractSubmitter(t), - flags: fmmocks.NewFlags(t), - } - - tm.flags.On("ContractExists").Maybe().Return(false) - tm.logBroadcast.On("String").Maybe().Return("") - - return tm -} - -func buildIdempotencyKey(ID int64) *string { - key := fmt.Sprintf("fluxmonitor-%d", ID) - return &key -} - -type setupOptions struct { - pollTickerDisabled bool - idleTimerDisabled bool - idleTimerPeriod time.Duration - drumbeatEnabled bool - drumbeatSchedule string - drumbeatRandomDelay time.Duration - hibernationPollPeriod time.Duration - flags *fmmocks.Flags - orm fluxmonitorv2.ORM -} - -// setup sets up a Flux Monitor for testing, allowing the test to provide -// functional options to configure the setup -func setup(t *testing.T, ds sqlutil.DataSource, optionFns ...func(*setupOptions)) (*fluxmonitorv2.FluxMonitor, *testMocks) { - t.Helper() - tests.SkipShort(t, "long test") - - tm := setupMocks(t) - options := setupOptions{ - idleTimerPeriod: time.Minute, - hibernationPollPeriod: fluxmonitorv2.DefaultHibernationPollPeriod, - flags: tm.flags, - orm: tm.orm, - } - - for _, optionFn := range optionFns { - optionFn(&options) - } - - tm.flags = options.flags - - lggr := logger.TestLogger(t) - - pollManager, err := fluxmonitorv2.NewPollManager( - fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: time.Minute, - PollTickerDisabled: options.pollTickerDisabled, - IdleTimerPeriod: options.idleTimerPeriod, - IdleTimerDisabled: options.idleTimerDisabled, - DrumbeatEnabled: options.drumbeatEnabled, - DrumbeatSchedule: options.drumbeatSchedule, - DrumbeatRandomDelay: options.drumbeatRandomDelay, - HibernationPollPeriod: options.hibernationPollPeriod, - MinRetryBackoffDuration: 1 * time.Minute, - MaxRetryBackoffDuration: 1 * time.Hour, - }, - lggr, - ) - require.NoError(t, err) - - fm, err := fluxmonitorv2.NewFluxMonitor( - tm.pipelineRunner, - job.Job{}, - pipelineSpec, - ds, - options.orm, - tm.jobORM, - tm.pipelineORM, - tm.keyStore, - pollManager, - fluxmonitorv2.NewPaymentChecker(assets.NewLinkFromJuels(1), nil), - contractAddress, - tm.contractSubmitter, - fluxmonitorv2.NewDeviationChecker(threshold, absoluteThreshold, lggr), - fluxmonitorv2.NewSubmissionChecker(big.NewInt(0), big.NewInt(100000000000)), - options.flags, - tm.fluxAggregator, - tm.logBroadcaster, - lggr, - testutils.FixtureChainID, - ) - require.NoError(t, err) - - return fm, tm -} - -// disablePollTicker is an option to disable the poll ticker during setup -func disablePollTicker(disabled bool) func(*setupOptions) { - return func(opts *setupOptions) { - opts.pollTickerDisabled = disabled - } -} - -// disableIdleTimer is an option to disable the idle timer during setup -func disableIdleTimer(disabled bool) func(*setupOptions) { - return func(opts *setupOptions) { - opts.idleTimerDisabled = disabled - } -} - -// enableDrumbeatTicker is an option to enable the drumbeat ticker during setup -func enableDrumbeatTicker(schedule string, randomDelay time.Duration) func(*setupOptions) { - return func(opts *setupOptions) { - opts.drumbeatEnabled = true - opts.drumbeatSchedule = schedule - opts.drumbeatRandomDelay = randomDelay - } -} - -// setIdleTimerPeriod is an option to set the idle timer period during setup -func setIdleTimerPeriod(period time.Duration) func(*setupOptions) { - return func(opts *setupOptions) { - opts.idleTimerPeriod = period - } -} - -// setHibernationTickerPeriod is an option to set the hibernation ticker period during setup -func setHibernationTickerPeriod(period time.Duration) func(*setupOptions) { - return func(opts *setupOptions) { - opts.hibernationPollPeriod = period - } -} - -// setHibernationTickerPeriod is an option to set the hibernation ticker period during setup -func setHibernationState(t *testing.T, hibernating bool) func(*setupOptions) { - return func(opts *setupOptions) { - opts.flags = fmmocks.NewFlags(t) - opts.flags.On("ContractExists").Return(true) - opts.flags.On("Address").Return(common.Address{}) - opts.flags.On("IsLowered", mock.Anything).Return(!hibernating, nil) - } -} - -func setFlags(flags *fmmocks.Flags) func(*setupOptions) { - return func(opts *setupOptions) { - opts.flags = flags - } -} - -// withORM is an option to switch out the ORM during set up. Useful when you -// want to use a database backed ORM -func withORM(orm fluxmonitorv2.ORM) func(*setupOptions) { - return func(opts *setupOptions) { - opts.orm = orm - } -} - -// setupStoreWithKey setups a new store and adds a key to the keystore -func setupStoreWithKey(t *testing.T) (*sqlx.DB, common.Address) { - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) - - return db, nodeAddr -} - -// setupStoreWithKey setups a new store and adds a key to the keystore -func setupFullDBWithKey(t *testing.T) (*sqlx.DB, common.Address) { - _, db := heavyweight.FullTestDBV2(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, nodeAddr := cltest.MustInsertRandomKey(t, ethKeyStore) - - return db, nodeAddr -} - -func TestFluxMonitor_PollIfEligible(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - eligible bool - connected bool - funded bool - answersDeviate bool - hasPreviousRun bool - previousRunStatus pipeline.RunStatus - expectedToPoll bool - expectedToSubmit bool - }{ - { - name: "eligible", - eligible: true, connected: true, funded: true, answersDeviate: true, - expectedToPoll: true, expectedToSubmit: true, - }, - { - name: "ineligible", - eligible: false, connected: true, funded: true, answersDeviate: true, - expectedToPoll: false, expectedToSubmit: false, - }, { - name: "disconnected", - eligible: true, connected: false, funded: true, answersDeviate: true, - expectedToPoll: false, expectedToSubmit: false, - }, { - name: "under funded", - eligible: true, connected: true, funded: false, answersDeviate: true, - expectedToPoll: false, expectedToSubmit: false, - }, { - name: "answer undeviated", - eligible: true, connected: true, funded: true, answersDeviate: false, - expectedToPoll: true, expectedToSubmit: false, - }, { - name: "previous job run completed", - eligible: true, connected: true, funded: true, answersDeviate: true, - hasPreviousRun: true, previousRunStatus: pipeline.RunStatusCompleted, - expectedToPoll: false, expectedToSubmit: false, - }, { - name: "previous job run in progress", - eligible: true, connected: true, funded: true, answersDeviate: true, - hasPreviousRun: true, previousRunStatus: pipeline.RunStatusRunning, - expectedToPoll: false, expectedToSubmit: false, - }, { - name: "previous job run errored", - eligible: true, connected: true, funded: true, answersDeviate: true, - hasPreviousRun: true, previousRunStatus: pipeline.RunStatusErrored, - expectedToPoll: true, expectedToSubmit: true, - }, - } - - db, nodeAddr := setupStoreWithKey(t) - - const reportableRoundID = 2 - var ( - thresholds = struct{ abs, rel float64 }{0.1, 200} - deviatedAnswers = answerSet{1, 100} - undeviatedAnswers = answerSet{100, 101} - ) - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - fm, tm := setup(t, db) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("IsConnected").Return(tc.connected).Once() - - // Setup Answers - answers := undeviatedAnswers - if tc.answersDeviate { - answers = deviatedAnswers - } - latestAnswer := answers.latestAnswer - - // Setup Run - run := pipeline.Run{ - ID: 1, - PipelineSpecID: 1, - } - if tc.hasPreviousRun { - switch tc.previousRunStatus { - case pipeline.RunStatusCompleted: - now := time.Now() - run.FinishedAt = null.TimeFrom(now) - case pipeline.RunStatusErrored: - run.FatalErrors = []null.String{ - null.StringFrom("Random: String, foo"), - } - default: - } - - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(reportableRoundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: reportableRoundID, - PipelineRunID: corenull.Int64From(run.ID), - NumSubmissions: 1, - }, nil) - - tm.pipelineORM. - On("FindRun", mock.Anything, run.ID). - Return(run, nil) - } else { - if tc.connected { - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(reportableRoundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: reportableRoundID, - }, nil) - } - } - - // Set up funds - var availableFunds *big.Int - var paymentAmount *big.Int - minPayment := defaultMinimumContractPayment.ToInt() - if tc.funded { - availableFunds = big.NewInt(1).Mul(big.NewInt(10000), minPayment) - paymentAmount = minPayment - } else { - availableFunds = big.NewInt(1) - paymentAmount = minPayment - } - - roundState := flux_aggregator_wrapper.OracleRoundState{ - RoundId: reportableRoundID, - EligibleToSubmit: tc.eligible, - LatestSubmission: big.NewInt(latestAnswer), - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: oracleCount, - } - tm.fluxAggregator. - On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(roundState, nil).Maybe() - - if tc.expectedToPoll { - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ - Answer: big.NewInt(10), - UpdatedAt: big.NewInt(100), - }, nil) - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, pipeline.NewVarsFrom( - map[string]any{ - "jobRun": map[string]any{ - "meta": map[string]any{ - "latestAnswer": float64(10), - "updatedAt": float64(100), - }, - }, - "jobSpec": map[string]any{ - "databaseID": int32(0), - "externalJobID": uuid.UUID{}, - "name": "", - "evmChainID": testutils.FixtureChainID.String(), - }, - }, - ), mock.Anything). - Return(&run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(answers.polledAnswer), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil) - } - - if tc.expectedToSubmit { - tm.pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 1 - }). - Once() - tm.contractSubmitter. - On("Submit", mock.Anything, big.NewInt(reportableRoundID), big.NewInt(answers.polledAnswer), buildIdempotencyKey(run.ID)). - Return(nil). - Once() - - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(reportableRoundID), - int64(1), - mock.Anything, - ). - Return(nil) - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - } - - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - require.NoError(t, fm.SetOracleAddress(t.Context())) - fm.ExportedPollIfEligible(thresholds.rel, thresholds.abs) - }) - } -} - -// If the roundState method is unable to communicate with the contract (possibly due to -// incorrect address) then the pollIfEligible method should create a JobErr record -func TestFluxMonitor_PollIfEligible_Creates_JobErr(t *testing.T) { - t.Parallel() - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - var ( - roundState = flux_aggregator_wrapper.OracleRoundState{} - ) - - fm, tm := setup(t, db) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("IsConnected").Return(true).Once() - - tm.jobORM. - On("TryRecordError", - mock.Anything, - pipelineSpec.JobID, - "Unable to call roundState method on provided contract. Check contract address.", - ).Once() - - tm.fluxAggregator. - On("OracleRoundState", nilOpts, nodeAddr, mock.Anything). - Return(roundState, errors.New("err")). - Once() - - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - require.NoError(t, fm.SetOracleAddress(t.Context())) - - fm.ExportedPollIfEligible(1, 1) -} - -func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { - t.Parallel() - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - fm, tm := setup(t, - db, - disableIdleTimer(true), - disablePollTicker(true), - ) - - const ( - fetchedValue = 100 - ) - - // Test helpers - var ( - makeRoundStateForRoundID = func(roundID uint32) flux_aggregator_wrapper.OracleRoundState { - return flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - EligibleToSubmit: true, - LatestSubmission: big.NewInt(100), - AvailableFunds: defaultMinimumContractPayment.ToInt(), - PaymentAmount: defaultMinimumContractPayment.ToInt(), - } - } - ) - - readyToAssert := cltest.NewAwaiter() - readyToFillQueue := cltest.NewAwaiter() - logsAwaiter := cltest.NewAwaiter() - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Maybe() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(1)). - Return(makeRoundStateForRoundID(1), nil). - Run(func(mock.Arguments) { - readyToFillQueue.ItHappened() - logsAwaiter.AwaitOrFail(t) - }). - Once() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(3)).Return(makeRoundStateForRoundID(3), nil).Once() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(4)).Return(makeRoundStateForRoundID(4), nil).Once() - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - - tm.logBroadcaster.On("Register", fm, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(1), nil) - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(3), nil) - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(4), nil) - - // Round 1 - run := &pipeline.Run{ID: 1} - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 1, - }, nil) - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(fetchedValue), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil).Once() - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 1 - }).Once() - tm.contractSubmitter. - On("Submit", mock.Anything, big.NewInt(1), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). - Return(nil). - Once() - - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(1), - mock.AnythingOfType("int64"), // int64(1), - mock.Anything, - ). - Return(nil).Once() - - // Round 3 - run = &pipeline.Run{ID: 2} - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(3), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 3, - }, nil) - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(fetchedValue), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil).Once() - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 2 - }).Once() - tm.contractSubmitter. - On("Submit", mock.Anything, big.NewInt(3), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). - Return(nil). - Once() - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(3), - mock.AnythingOfType("int64"), // int64(2), - mock.Anything, - ). - Return(nil).Once() - - // Round 4 - run = &pipeline.Run{ID: 3} - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(4), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 3, - }, nil) - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(fetchedValue), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil).Once() - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 3 - }).Once() - tm.contractSubmitter. - On("Submit", mock.Anything, big.NewInt(4), big.NewInt(fetchedValue), buildIdempotencyKey(run.ID)). - Return(nil). - Once() - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(4), - mock.AnythingOfType("int64"), // int64(3), - mock.Anything, - ). - Return(nil). - Once(). - Run(func(mock.Arguments) { readyToAssert.ItHappened() }) - - servicetest.Run(t, fm) - - var logBroadcasts []*logmocks.Broadcast - - for i := 1; i <= 4; i++ { - logBroadcast := logmocks.NewBroadcast(t) - logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorNewRound{RoundId: big.NewInt(int64(i)), StartedAt: big.NewInt(0)}) - logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - logBroadcasts = append(logBroadcasts, logBroadcast) - } - ctx := testutils.Context(t) - fm.HandleLog(ctx, logBroadcasts[0]) // Get the checker to start processing a log so we can freeze it - - readyToFillQueue.AwaitOrFail(t) - - fm.HandleLog(ctx, logBroadcasts[1]) // This log is evicted from the priority queue - fm.HandleLog(ctx, logBroadcasts[2]) - fm.HandleLog(ctx, logBroadcasts[3]) - - logsAwaiter.ItHappened() - readyToAssert.AwaitOrFail(t) -} - -func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { - t.Parallel() - g := gomega.NewWithT(t) - - testCases := []struct { - name string - idleTimerDisabled bool - idleDuration time.Duration - expectedToSubmit bool - }{ - {"no idleDuration", true, 0, false}, - {"idleDuration > 0", false, 2 * time.Second, true}, - } - - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - var ( - orm = newORM(t, db, nil) - ) - - fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(tc.idleTimerDisabled), setIdleTimerPeriod(tc.idleDuration), withORM(orm)) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - - idleDurationOccurred := make(chan struct{}, 3) - - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Once() - if tc.expectedToSubmit { - // performInitialPoll() - roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1, nil).Once() - // idleDuration 1 - roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState2, nil).Once().Run(func(args mock.Arguments) { - idleDurationOccurred <- struct{}{} - }) - } - - require.NoError(t, fm.Start(testutils.Context(t))) - require.Empty(t, idleDurationOccurred, "no Job Runs created") - - if tc.expectedToSubmit { - g.Eventually(func() int { return len(idleDurationOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(1)) - - chBlock := make(chan struct{}) - // NewRound resets the idle timer - roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 2, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(2)).Return(roundState2, nil).Once().Run(func(args mock.Arguments) { - close(chBlock) - }) - - decodedLog := flux_aggregator_wrapper.FluxAggregatorNewRound{RoundId: big.NewInt(2), StartedAt: big.NewInt(0)} - tm.logBroadcast.On("DecodedLog").Return(&decodedLog) - tm.logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fm.HandleLog(testutils.Context(t), tm.logBroadcast) - - g.Eventually(chBlock).Should(gomega.BeClosed()) - - // idleDuration 2 - roundState3 := flux_aggregator_wrapper.OracleRoundState{RoundId: 3, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState3, nil).Once().Run(func(args mock.Arguments) { - idleDurationOccurred <- struct{}{} - }) - - g.Eventually(func() int { return len(idleDurationOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(2)) - } - - fm.Close() - - if !tc.expectedToSubmit { - require.Empty(t, idleDurationOccurred) - } - }) - } -} - -func TestFluxMonitor_HibernationTickerFiresMultipleTimes(t *testing.T) { - t.Parallel() - - g := gomega.NewWithT(t) - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - fm, tm := setup(t, - db, - disablePollTicker(true), - disableIdleTimer(true), - setHibernationTickerPeriod(time.Second), - setHibernationState(t, true), - ) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - tm.fluxAggregator.On("Address").Return(contractAddress) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Once() - - pollOccurred := make(chan struct{}, 4) - - err := fm.Start(testutils.Context(t)) - require.NoError(t, err) - - t.Cleanup(func() { fm.Close() }) - - roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1, nil).Once().Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 0, - }, nil).Once() - - g.Eventually(func() int { return len(pollOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(1)) - - // hiberation tick 1 triggers using the same round id as the initial poll. This resets the idle timer - roundState1Responded := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now() + 1} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1Responded, nil).Once().Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }) - - // Finds an existing run created by the initial poll - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 1, - }, nil).Once() - finishedAt := time.Now() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ - FinishedAt: null.TimeFrom(finishedAt), - }, nil) - - g.Eventually(func() int { return len(pollOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(2)) - - // hiberation tick 2 triggers a new round. Started at is 0 - roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 2, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: 0} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState2, nil).Once().Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(2), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 2, - NumSubmissions: 0, - }, nil).Once() - - g.Eventually(func() int { return len(pollOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(3)) -} - -func TestFluxMonitor_HibernationIsEnteredAndRetryTickerStopped(t *testing.T) { - quarantine.Flaky(t, "DX-1806") - t.Parallel() - db, nodeAddr := setupFullDBWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - const ( - roundZero = uint32(0) - roundOne = uint32(1) - roundTwo = uint32(2) - ) - - flags := fmmocks.NewFlags(t) - flags.On("ContractExists").Return(true) - flags.On("Address").Return(common.Address{}) - flags.On("IsLowered", mock.Anything).Return(true, nil).Once() - - fm, tm := setup(t, - db, - setIdleTimerPeriod(time.Second), - disablePollTicker(true), - setHibernationTickerPeriod(4*time.Second), - setFlags(flags), - ) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - tm.fluxAggregator.On("Address").Return(contractAddress) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Once() - - pollOccurred := make(chan struct{}, 4) - - err := fm.Start(testutils.Context(t)) - require.NoError(t, err) - - t.Cleanup(func() { fm.Close() }) - - // idle ticker - roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now(), AvailableFunds: big.NewInt(0)} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, roundZero).Return(roundState1, nil).Once().Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundOne, mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 0, - }, nil).Once() - - select { - case <-pollOccurred: - case <-time.After(testutils.WaitTimeout(t)): - t.Fatal("Poll did not occur!") - } - - roundState1Responded := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now() + 1} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, roundZero).Return(roundState1Responded, nil).Once().Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }) - - // Finds an error run, so that retry ticker will be kicked off - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundOne, mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 1, - }, nil).Once() - finishedAt := time.Now() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ - FinishedAt: null.TimeFrom(finishedAt), - FatalErrors: []null.String{null.StringFrom("an error to start retry ticker")}, - }, nil) - - select { - case <-pollOccurred: - case <-time.After(testutils.WaitTimeout(t)): - t.Fatal("Poll did not occur!") - } - - // ---------- Begin hibernation mode ------------ - flags.On("IsLowered", mock.Anything).Return(false, nil) - fm.ExportedRespondToFlagsRaisedLog() - - // hibernation ticker - roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 2, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: 0} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, roundZero).Return(roundState2, nil).Once() - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundTwo, mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 2, - NumSubmissions: 0, - }, nil). - Run(func(args mock.Arguments) { - pollOccurred <- struct{}{} - }). - Once() - - select { - case <-pollOccurred: - t.Fatal("Poll should not occur for next few seconds because we are in hibernation mode and all other tickers should be stopped") - case <-time.After(2 * time.Second): - } - - select { - case <-pollOccurred: - case <-time.After(testutils.WaitTimeout(t)): - t.Fatal("Poll did not occur, though it should have via hibernation ticker") - } -} - -func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { - quarantine.Flaky(t, "DX-1857") - t.Parallel() - - g := gomega.NewWithT(t) - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - fm, tm := setup(t, - db, - disablePollTicker(true), - setIdleTimerPeriod(2*time.Second), - ) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - tm.fluxAggregator.On("Address").Return(contractAddress) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Once() - - idleDurationOccurred := make(chan struct{}, 4) - initialPollOccurred := make(chan struct{}, 1) - - servicetest.Run(t, fm) - - // Initial Poll - roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1, nil).Once() - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 0, - }, nil).Once().Run(func(args mock.Arguments) { - initialPollOccurred <- struct{}{} - }) - require.Empty(t, idleDurationOccurred, "no Job Runs created") - g.Eventually(func() int { return len(initialPollOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(1)) - - // idleDuration 1 triggers using the same round id as the initial poll. This resets the idle timer - roundState1Responded := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now() + 1} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState1Responded, nil).Once().Run(func(args mock.Arguments) { - idleDurationOccurred <- struct{}{} - }) - // Finds an existing run created by the initial poll - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(1), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: 1, - NumSubmissions: 1, - }, nil).Once() - finishedAt := time.Now() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ - FinishedAt: null.TimeFrom(finishedAt), - }, nil) - - g.Eventually(func() int { return len(idleDurationOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(1)) - - // idleDuration 2 triggers a new round. Started at is 0 - roundState2 := flux_aggregator_wrapper.OracleRoundState{RoundId: 2, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: 0} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState2, nil).Once().Run(func(args mock.Arguments) { - idleDurationOccurred <- struct{}{} - }) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(2), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 2, - NumSubmissions: 0, - }, nil).Once() - - g.Eventually(func() int { return len(idleDurationOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(2)) - - // idleDuration 3 triggers from the previous new round - roundState3 := flux_aggregator_wrapper.OracleRoundState{RoundId: 3, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now() - 1000000} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState3, nil).Twice().Run(func(args mock.Arguments) { - idleDurationOccurred <- struct{}{} - }) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(3), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: 3, - NumSubmissions: 0, - }, nil).Once() - - // AnswerUpdated comes in, which attempts to reset the timers - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Once() - tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}) - tm.logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - fm.ExportedBacklog().Add(fluxmonitorv2.PriorityNewRoundLog, tm.logBroadcast) - fm.ExportedProcessLogs() - - g.Eventually(func() int { return len(idleDurationOccurred) }, testutils.WaitTimeout(t)).Should(gomega.Equal(4)) -} - -func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { - t.Parallel() - - g := gomega.NewWithT(t) - db, nodeAddr := setupStoreWithKey(t) - - var ( - oracles = []common.Address{nodeAddr, testutils.NewAddress()} - orm = newORM(t, db, nil) - ) - - fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) - - tm.keyStore. - On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID). - Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil). - Twice() // Once called from the test, once during start - - ch := make(chan struct{}) - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(makeRoundDataForRoundID(1), nil).Once() - roundState0 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(1)).Return(roundState0, nil).Once() // initialRoundState() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - LatestSubmission: answerBigInt, - StartedAt: 0, - Timeout: 0, - }, nil). - Run(func(mock.Arguments) { close(ch) }). - Once() - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - - require.NoError(t, fm.SetOracleAddress(t.Context())) - fm.ExportedRoundState(t) - servicetest.Run(t, fm) - - g.Eventually(ch).Should(gomega.BeClosed()) -} - -func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) { - quarantine.Flaky(t, "DX-1845") - t.Parallel() - g := gomega.NewWithT(t) - - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - tests := []struct { - name string - timeout uint64 - expectedToSubmit bool - }{ - {"active round exists - round will time out", 2, true}, - {"active round exists - round will not time out", 100, false}, - {"no active round", 0, false}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - orm := newORM(t, db, nil) - - fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(makeRoundDataForRoundID(1), nil).Once() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(1)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - StartedAt: now(), - Timeout: test.timeout, - }, nil).Once() - - // 2nd roundstate call means round timer triggered - chRoundState := make(chan struct{}) - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - }, nil). - Run(func(mock.Arguments) { close(chRoundState) }). - Maybe() - - servicetest.Run(t, fm) - - if test.expectedToSubmit { - g.Eventually(chRoundState).Should(gomega.BeClosed()) - } else { - g.Consistently(chRoundState).ShouldNot(gomega.BeClosed()) - } - }) - } -} - -func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { - t.Parallel() - g := gomega.NewWithT(t) - - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - almostExpired := time.Now(). - Add(idleTimerPeriod * -1). - Add(2 * time.Second). - Unix() - - testCases := []struct { - name string - startedAt uint64 - expectedToSubmit bool - }{ - {"active round exists - idleTimer about to expired", uint64(almostExpired), true}, - {"active round exists - idleTimer will not expire", 100, false}, - {"no active round", 0, false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - orm := newORM(t, db, nil) - - fm, tm := setup(t, - db, - disablePollTicker(true), - withORM(orm), - ) - initialPollOccurred := make(chan struct{}, 1) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(makeRoundDataForRoundID(1), nil).Once() - - // first roundstate calling initialRoundState on fm.Start() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(1)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - StartedAt: tc.startedAt, - Timeout: 10000, // round won't time out - }, nil) - - // 2nd roundstate in initial poll - roundState := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false} - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState, nil). - Once(). - Run(func(args mock.Arguments) { - initialPollOccurred <- struct{}{} - }) - - // 3rd roundState call means idleTimer triggered - chRoundState := make(chan struct{}) - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(roundState, nil). - Run(func(mock.Arguments) { - close(chRoundState) - }). - Maybe() - - servicetest.Run(t, fm) - - require.Eventually(t, func() bool { return len(initialPollOccurred) == 1 }, 3*time.Second, 10*time.Millisecond) - - if tc.expectedToSubmit { - g.Eventually(chRoundState).Should(gomega.BeClosed()) - } else { - g.Consistently(chRoundState).ShouldNot(gomega.BeClosed()) - } - }) - } -} - -func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { - t.Parallel() - - g := gomega.NewWithT(t) - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - orm := newORM(t, db, nil) - - fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), withORM(orm)) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - chRoundState1 := make(chan struct{}) - chRoundState2 := make(chan struct{}) - - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(makeRoundDataForRoundID(1), nil).Once() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(1)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - LatestSubmission: answerBigInt, - StartedAt: now(), - Timeout: uint64(1000000), - }, nil).Once() - - startedAt := uint64(time.Now().Unix()) - timeout := uint64(3) - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - LatestSubmission: answerBigInt, - StartedAt: startedAt, - PaymentAmount: big.NewInt(10), - AvailableFunds: big.NewInt(100), - Timeout: timeout, - }, nil).Once(). - Run(func(mock.Arguments) { close(chRoundState1) }). - Once() - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)).Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: 1, - EligibleToSubmit: false, - LatestSubmission: answerBigInt, - PaymentAmount: big.NewInt(10), - AvailableFunds: big.NewInt(100), - StartedAt: startedAt, - Timeout: timeout, - }, nil).Once(). - Run(func(mock.Arguments) { close(chRoundState2) }). - Once() - - servicetest.Run(t, fm) - - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorNewRound{ - RoundId: big.NewInt(0), - StartedAt: big.NewInt(time.Now().UTC().Unix()), - }) - tm.logBroadcast.On("String").Maybe().Return("") - // To mark it consumed, we need to be eligible to submit. - fm.HandleLog(testutils.Context(t), tm.logBroadcast) - - g.Eventually(chRoundState1).Should(gomega.BeClosed()) - g.Eventually(chRoundState2).Should(gomega.BeClosed()) - - time.Sleep(time.Duration(2*timeout) * time.Second) -} - -func TestFluxMonitor_ConsumeLogBroadcast(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - fm, tm := setup(t, db) - - tm.fluxAggregator. - On("OracleRoundState", nilOpts, mock.Anything, mock.Anything). - Return(flux_aggregator_wrapper.OracleRoundState{RoundId: 123}, nil) - - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(false, nil).Once() - tm.logBroadcast.On("DecodedLog").Return(&flux_aggregator_wrapper.FluxAggregatorAnswerUpdated{}) - tm.logBroadcast.On("String").Maybe().Return("") - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - - fm.ExportedBacklog().Add(fluxmonitorv2.PriorityNewRoundLog, tm.logBroadcast) - fm.ExportedProcessLogs() -} - -func TestFluxMonitor_ConsumeLogBroadcast_Error(t *testing.T) { - t.Parallel() - - testCases := []struct { - name string - consumed bool - err error - }{ - {"already consumed", true, nil}, - {"error determining already consumed", false, errors.New("err")}, - } - - db := pgtest.NewSqlxDB(t) - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - fm, tm := setup(t, db) - - tm.logBroadcaster.On("WasAlreadyConsumed", mock.Anything, mock.Anything).Return(tc.consumed, tc.err).Once() - - fm.ExportedBacklog().Add(fluxmonitorv2.PriorityNewRoundLog, tm.logBroadcast) - fm.ExportedProcessLogs() - }) - } -} - -func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) { - t.Parallel() - t.Run("when NewRound log arrives, then poll ticker fires", func(t *testing.T) { - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - fm, tm := setup(t, - db, - disableIdleTimer(true), - disablePollTicker(true), - ) - - var ( - paymentAmount = defaultMinimumContractPayment.ToInt() - availableFunds = big.NewInt(1).Mul(paymentAmount, big.NewInt(1000)) - ) - - const ( - roundID = 3 - answer = 100 - ) - - run := &pipeline.Run{ID: 1} - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - - // Mocks initiated by the New Round log - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil).Once() - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: roundID, - }, nil).Once() - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(answer), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil) - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 1 - }) - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() - tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(roundID), - int64(1), - uint(1), - ). - Return(nil) - - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - require.NoError(t, fm.SetOracleAddress(t.Context())) - - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ - Answer: big.NewInt(10), - UpdatedAt: big.NewInt(100), - }, nil) - - // Fire off the NewRound log, which the node should respond to - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(roundID)). - Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - LatestSubmission: big.NewInt(answer), - EligibleToSubmit: true, - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: 1, - }, nil). - Once() - - fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ - RoundId: big.NewInt(roundID), - StartedAt: big.NewInt(0), - }, log.NewLogBroadcast(types.Log{}, cltest.FixtureChainID, nil)) - - // Mocks initiated by polling - // Now force the node to try to poll and ensure it does not respond this time - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - LatestSubmission: big.NewInt(answer), - EligibleToSubmit: true, - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: 1, - }, nil). - Once() - - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: roundID, - NumSubmissions: 1, - }, nil).Once() - - now := time.Now() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{ - FinishedAt: null.TimeFrom(now), - }, nil) - - fm.ExportedPollIfEligible(0, 0) - }) - - t.Run("when poll ticker fires, then NewRound log arrives", func(t *testing.T) { - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - fm, tm := setup(t, - db, - disableIdleTimer(true), - disablePollTicker(true), - ) - - var ( - paymentAmount = defaultMinimumContractPayment.ToInt() - availableFunds = big.NewInt(1).Mul(paymentAmount, big.NewInt(1000)) - ) - - const ( - roundID = 3 - answer = 100 - ) - - run := &pipeline.Run{ID: 1} - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - - // First, force the node to try to poll, which should result in a submission - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ - Answer: big.NewInt(10), - UpdatedAt: big.NewInt(100), - }, nil) - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - LatestSubmission: big.NewInt(answer), - EligibleToSubmit: true, - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: 1, - }, nil). - Once() - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: roundID, - }, nil).Once() - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(answer), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil) - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 1 - }) - tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(roundID), - int64(1), - uint(0), - ). - Return(nil). - Once() - - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - require.NoError(t, fm.SetOracleAddress(t.Context())) - fm.ExportedPollIfEligible(0, 0) - - // Now fire off the NewRound log and ensure it does not respond this time - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: roundID, - NumSubmissions: 1, - }, nil).Once() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) - - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ - RoundId: big.NewInt(roundID), - StartedAt: big.NewInt(0), - }, log.NewLogBroadcast(types.Log{}, cltest.FixtureChainID, nil)) - }) - - t.Run("when poll ticker fires, then an older NewRound log arrives, but does submit on a log arrival after a reorg", func(t *testing.T) { - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - fm, tm := setup(t, - db, - disableIdleTimer(true), - disablePollTicker(true), - ) - - var ( - paymentAmount = defaultMinimumContractPayment.ToInt() - availableFunds = big.NewInt(1).Mul(paymentAmount, big.NewInt(1000)) - ) - - const ( - olderRoundID = 2 - roundID = 3 - answer = 100 - ) - run := &pipeline.Run{ID: 1} - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil).Once() - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - - // First, force the node to try to poll, which should result in a submission - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{ - Answer: big.NewInt(10), - UpdatedAt: big.NewInt(100), - }, nil) - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - LatestSubmission: big.NewInt(answer), - EligibleToSubmit: true, - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: 1, - }, nil). - Once() - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(roundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - Aggregator: contractAddress, - RoundID: roundID, - }, nil).Once() - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, mock.Anything, mock.Anything). - Return(run, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(answer), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil) - tm.pipelineRunner. - On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = 1 - }) - tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(roundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(roundID), - int64(1), - uint(0), - ). - Return(nil). - Once() - - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - require.NoError(t, fm.SetOracleAddress(t.Context())) - fm.ExportedPollIfEligible(0, 0) - - // Now fire off the NewRound log and ensure it does not respond this time - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: olderRoundID, - NumSubmissions: 1, - }, nil).Once() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) - - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ - RoundId: big.NewInt(olderRoundID), - StartedAt: big.NewInt(0), - }, log.NewLogBroadcast(types.Log{}, cltest.FixtureChainID, nil)) - - // Simulate a reorg - fire the same NewRound log again, which should result in a submission this time - tm.orm.On("MostRecentFluxMonitorRoundID", mock.Anything, contractAddress).Return(uint32(roundID), nil) - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), uint(1)). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: olderRoundID, - NumSubmissions: 1, - NumNewRoundLogs: 1, - }, nil).Once() - tm.pipelineORM.On("FindRun", mock.Anything, int64(1)).Return(pipeline.Run{}, nil) - - // all newer round stats should be deleted - tm.orm.On("DeleteFluxMonitorRoundsBackThrough", mock.Anything, contractAddress, uint32(olderRoundID)).Return(nil) - - // then we are returning a fresh round stat, with NumSubmissions: 0 - tm.orm. - On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, uint32(olderRoundID), uint(1)). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{ - PipelineRunID: corenull.NewInt64(int64(1), true), - Aggregator: contractAddress, - RoundID: olderRoundID, - NumSubmissions: 0, - NumNewRoundLogs: 1, - }, nil).Once() - - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(olderRoundID)). - Return(flux_aggregator_wrapper.OracleRoundState{ - RoundId: olderRoundID, - LatestSubmission: big.NewInt(answer), - EligibleToSubmit: true, - AvailableFunds: availableFunds, - PaymentAmount: paymentAmount, - OracleCount: 1, - }, nil). - Once() - - // and that should result in a new submission - tm.contractSubmitter.On("Submit", mock.Anything, big.NewInt(olderRoundID), big.NewInt(answer), buildIdempotencyKey(run.ID)).Return(nil).Once() - - tm.orm. - On("UpdateFluxMonitorRoundStats", - mock.Anything, - contractAddress, - uint32(olderRoundID), - int64(1), - uint(1), - ). - Return(nil). - Once() - - tm.logBroadcaster.On("MarkConsumed", mock.Anything, mock.Anything, mock.Anything).Return(nil) - fm.ExportedRespondToNewRoundLog(&flux_aggregator_wrapper.FluxAggregatorNewRound{ - RoundId: big.NewInt(olderRoundID), - StartedAt: big.NewInt(0), - }, log.NewLogBroadcast(types.Log{}, cltest.FixtureChainID, nil)) - }) -} - -// This is a flaky test: inserting time.Sleep(15 * time.Second) in its end makes it failing with an unexpected call. -// For now, we let it use a custom EventuallyExpectationsMet instead of assert.Eventually because it flakes -// with the latter approach (somehow assert.Eventually gives it a little bit more time, and then it fails -// with the same unexpected call). -func TestFluxMonitor_DrumbeatTicker(t *testing.T) { - t.Parallel() - - db, nodeAddr := setupStoreWithKey(t) - oracles := []common.Address{nodeAddr, testutils.NewAddress()} - - // a setup with a random delay being zero - _, _ = setup(t, db, enableDrumbeatTicker("@every 10s", 0)) - - fm, tm := setup(t, db, disablePollTicker(true), disableIdleTimer(true), enableDrumbeatTicker("@every 3s", 2*time.Second)) - - tm.keyStore.On("EnabledKeysForChain", mock.Anything, testutils.FixtureChainID).Return([]ethkey.KeyV2{{Address: nodeAddr}}, nil) - tm.orm.On("WithDataSource", mock.Anything).Return(fluxmonitorv2.ORM(tm.orm)) - - const fetchedAnswer = 100 - answerBigInt := big.NewInt(fetchedAnswer) - - tm.fluxAggregator.On("Address").Return(common.Address{}) - tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil) - tm.logBroadcaster.On("Register", mock.Anything, mock.Anything).Return(func() {}) - tm.logBroadcaster.On("IsConnected").Return(true).Maybe() - - tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(freshContractRoundDataResponse()).Once() - - expectSubmission := func(roundID uint32, runID int64) { - roundState := flux_aggregator_wrapper.OracleRoundState{ - RoundId: roundID, - EligibleToSubmit: true, - LatestSubmission: answerBigInt, - AvailableFunds: big.NewInt(1).Mul(big.NewInt(10000), defaultMinimumContractPayment.ToInt()), - PaymentAmount: defaultMinimumContractPayment.ToInt(), - StartedAt: now(), - } - - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(roundState, nil). - Once() - - tm.fluxAggregator.On("OracleRoundState", nilOpts, nodeAddr, roundID). - Return(roundState, nil). - Once() - - tm.orm.On("FindOrCreateFluxMonitorRoundStats", mock.Anything, contractAddress, roundID, mock.Anything). - Return(fluxmonitorv2.FluxMonitorRoundStatsV2{Aggregator: contractAddress, RoundID: roundID}, nil). - Once() - - tm.fluxAggregator.On("LatestRoundData", nilOpts). - Return(flux_aggregator_wrapper.LatestRoundData{ - Answer: answerBigInt, - UpdatedAt: big.NewInt(100), - }, nil). - Once() - - tm.pipelineRunner. - On("ExecuteRun", mock.Anything, pipelineSpec, pipeline.NewVarsFrom( - map[string]any{ - "jobRun": map[string]any{ - "meta": map[string]any{ - "latestAnswer": float64(fetchedAnswer), - "updatedAt": float64(100), - }, - }, - "jobSpec": map[string]any{ - "databaseID": int32(0), - "externalJobID": uuid.UUID{}, - "name": "", - "evmChainID": testutils.FixtureChainID.String(), - }, - }, - ), mock.Anything). - Return(&pipeline.Run{ID: runID}, pipeline.TaskRunResults{ - { - Result: pipeline.Result{ - Value: decimal.NewFromInt(fetchedAnswer), - Error: nil, - }, - Task: &pipeline.HTTPTask{}, - }, - }, nil). - Once() - - tm.pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil). - Run(func(args mock.Arguments) { - args.Get(2).(*pipeline.Run).ID = runID - }). - Once() - tm.contractSubmitter. - On("Submit", mock.Anything, big.NewInt(int64(roundID)), answerBigInt, buildIdempotencyKey(runID)). - Return(nil). - Once() - - tm.orm. - On("UpdateFluxMonitorRoundStats", mock.Anything, contractAddress, roundID, runID, mock.Anything). - Return(nil). - Once() - } - - expectSubmission(2, 1) - expectSubmission(3, 2) - expectSubmission(4, 3) - - // catch remaining drumbeats - tm.fluxAggregator. - On("OracleRoundState", nilOpts, nodeAddr, uint32(0)). - Return(flux_aggregator_wrapper.OracleRoundState{RoundId: 4, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()}, nil). - Maybe() - - servicetest.Run(t, fm) - - waitTime := 15 * time.Second - interval := 50 * time.Millisecond - eventuallyExpectationsMet(t, tm.logBroadcaster, waitTime, interval) - eventuallyExpectationsMet(t, tm.fluxAggregator, waitTime, interval) - eventuallyExpectationsMet(t, tm.orm, waitTime, interval) - eventuallyExpectationsMet(t, tm.pipelineORM, waitTime, interval) - eventuallyExpectationsMet(t, tm.contractSubmitter, waitTime, interval) -} - -type testifyExpectationsAsserter interface { - AssertExpectations(t mock.TestingT) bool -} - -type fakeT struct{} - -func (ft fakeT) Logf(format string, args ...any) {} -func (ft fakeT) Errorf(format string, args ...any) {} -func (ft fakeT) FailNow() {} - -func eventuallyExpectationsMet(t *testing.T, mock testifyExpectationsAsserter, timeout time.Duration, interval time.Duration) { - t.Helper() - - chTimeout := time.After(timeout) - for { - var ft fakeT - success := mock.AssertExpectations(ft) - if success { - return - } - select { - case <-chTimeout: - mock.AssertExpectations(t) - t.FailNow() - default: - time.Sleep(interval) - } - } -} diff --git a/core/services/fluxmonitorv2/helpers_test.go b/core/services/fluxmonitorv2/helpers_test.go deleted file mode 100644 index 512b1b2140d..00000000000 --- a/core/services/fluxmonitorv2/helpers_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package fluxmonitorv2 - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -// Format implements fmt.Formatter to always print just the pointer address. -// This is a hack to work around a race in github.com/stretchr/testify which -// prints internal fields, including the state of nested, embedded mutexes. -func (fm *FluxMonitor) Format(f fmt.State, verb rune) { - fmt.Fprintf(f, "%[1]T<%[1]p>", fm) -} - -func (fm *FluxMonitor) ExportedPollIfEligible(threshold, absoluteThreshold float64) { - ctx, cancel := fm.eng.NewCtx() - defer cancel() - fm.pollIfEligible(ctx, PollRequestTypePoll, NewDeviationChecker(threshold, absoluteThreshold, fm.logger), nil) -} - -func (fm *FluxMonitor) ExportedProcessLogs() { - ctx, cancel := fm.eng.NewCtx() - defer cancel() - fm.processLogs(ctx) -} - -func (fm *FluxMonitor) ExportedBacklog() *utils.BoundedPriorityQueue[log.Broadcast] { - return fm.backlog -} - -func (fm *FluxMonitor) ExportedRoundState(t *testing.T) { - _, err := fm.roundState(0) - require.NoError(t, err) -} - -func (fm *FluxMonitor) ExportedRespondToNewRoundLog(log *flux_aggregator_wrapper.FluxAggregatorNewRound, broadcast log.Broadcast) { - ctx, cancel := fm.eng.NewCtx() - defer cancel() - fm.respondToNewRoundLog(ctx, *log, broadcast) -} - -func (fm *FluxMonitor) ExportedRespondToFlagsRaisedLog() { - fm.respondToFlagsRaisedLog() - fm.rotateSelectLoop() -} - -func (fm *FluxMonitor) rotateSelectLoop() { - // the PollRequest is sent to 'rotate' the main select loop, so that new timers will be evaluated - fm.pollManager.chPoll <- PollRequest{Type: PollRequestTypeUnknown} -} diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go deleted file mode 100644 index fcd91eac537..00000000000 --- a/core/services/fluxmonitorv2/integrations_test.go +++ /dev/null @@ -1,1109 +0,0 @@ -package fluxmonitorv2_test - -import ( - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - gethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/params" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/quarantine" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - - "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flags_wrapper" - faw "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/link_token_interface" - "github.com/smartcontractkit/chainlink-evm/pkg/assets" - "github.com/smartcontractkit/chainlink-evm/pkg/log" - evmtestutils "github.com/smartcontractkit/chainlink-evm/pkg/testutils" - "github.com/smartcontractkit/chainlink-evm/pkg/types" - evmutils "github.com/smartcontractkit/chainlink-evm/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/web" -) - -const description = "exactly thirty-three characters!!" - -const decimals = 8 -const fee = int64(100) // Amount paid by FA contract, in LINK-wei -const faTimeout = uint32(1) - -var pollTimerPeriod = 200 * time.Millisecond // if failing due to timeouts, increase this -var emptyList = []common.Address{} - -func oneEth() *big.Int { return big.NewInt(1000000000000000000) } - -// fluxAggregatorUniverse represents the universe with which the aggregator -// contract interacts -type fluxAggregatorUniverse struct { - key ethkey.KeyV2 - aggregatorContract *faw.FluxAggregator - aggregatorContractAddress common.Address - linkContract *link_token_interface.LinkToken - flagsContract *flags_wrapper.Flags - flagsContractAddress common.Address - evmChainID big.Int - // Abstraction representation of the ethereum blockchain - backend types.Backend - aggregatorABI abi.ABI - // Cast of participants - sergey *bind.TransactOpts // Owns all the LINK initially - neil *bind.TransactOpts // Node operator Flux Monitor Oracle - ned *bind.TransactOpts // Node operator Flux Monitor Oracle - nallory *bind.TransactOpts // Node operator Flux Monitor Oracle running this node -} - -type fluxAggregatorUniverseConfig struct { - MinSubmission *big.Int - MaxSubmission *big.Int -} - -func WithMinMaxSubmission(min, max *big.Int) func(cfg *fluxAggregatorUniverseConfig) { - return func(cfg *fluxAggregatorUniverseConfig) { - cfg.MinSubmission = min - cfg.MaxSubmission = max - } -} - -// setupFluxAggregatorUniverse returns a fully initialized fluxAggregator universe. The -// arguments match the arguments of the same name in the FluxAggregator -// constructor. -func setupFluxAggregatorUniverse(t *testing.T, configOptions ...func(cfg *fluxAggregatorUniverseConfig)) fluxAggregatorUniverse { - tests.SkipShort(t, "VRFCoordinatorV2Universe") - cfg := &fluxAggregatorUniverseConfig{ - MinSubmission: big.NewInt(0), - MaxSubmission: big.NewInt(100000000000), - } - - for _, optFn := range configOptions { - optFn(cfg) - } - - key, err := ethkey.NewV2() - require.NoError(t, err) - oracleTransactor := &bind.TransactOpts{ - From: key.Address, - Signer: key.SignerFn(testutils.SimulatedChainID), - } - - var f fluxAggregatorUniverse - f.evmChainID = *testutils.SimulatedChainID - f.key = key - f.sergey = evmtestutils.MustNewSimTransactor(t) - f.neil = evmtestutils.MustNewSimTransactor(t) - f.ned = evmtestutils.MustNewSimTransactor(t) - f.nallory = oracleTransactor - genesisData := gethtypes.GenesisAlloc{ - f.sergey.From: {Balance: assets.Ether(1000).ToInt()}, - f.neil.From: {Balance: assets.Ether(1000).ToInt()}, - f.ned.From: {Balance: assets.Ether(1000).ToInt()}, - f.nallory.From: {Balance: assets.Ether(1000).ToInt()}, - } - // https://github.com/ethereum/go-ethereum/blob/abeb78c647e354ed922726a1d719ac7bc64a07e2/core/state_transition.go#L329-L332 - gasLimit := min(ethconfig.Defaults.Miner.GasCeil*2, params.MaxTxGas) // gas limit to respect EIP-7825 cap - f.backend = cltest.NewSimulatedBackend(t, genesisData, gasLimit) - - f.aggregatorABI, err = abi.JSON(strings.NewReader(faw.FluxAggregatorABI)) - require.NoError(t, err, "could not parse FluxAggregator ABI") - - var linkAddress common.Address - linkAddress, _, f.linkContract, err = link_token_interface.DeployLinkToken(f.sergey, f.backend.Client()) - require.NoError(t, err, "failed to deploy link contract to simulated ethereum blockchain") - - f.flagsContractAddress, _, f.flagsContract, err = flags_wrapper.DeployFlags(f.sergey, f.backend.Client(), f.sergey.From) - require.NoError(t, err, "failed to deploy flags contract to simulated ethereum blockchain") - - f.backend.Commit() - - // FluxAggregator contract subtracts timeout from block timestamp, which will - // be less than the timeout, leading to a SafeMath error. Wait for longer than - // the timeout... Golang is unpleasant about mixing int64 and time.Duration in - // arithmetic operations, so do everything as int64 and then convert. - waitTimeMs := int64(faTimeout * 5000) - time.Sleep(time.Duration((waitTimeMs + waitTimeMs/20) * int64(time.Millisecond))) - oldGasLimit := f.sergey.GasLimit - f.sergey.GasLimit = gasLimit - f.aggregatorContractAddress, _, f.aggregatorContract, err = faw.DeployFluxAggregator( - f.sergey, - f.backend.Client(), - linkAddress, - big.NewInt(fee), - faTimeout, - common.Address{}, - cfg.MinSubmission, - cfg.MaxSubmission, - decimals, - description, - ) - f.backend.Commit() // Must commit contract to chain before we can fund with LINK - require.NoError(t, err, "failed to deploy FluxAggregator contract to simulated ethereum blockchain") - - f.sergey.GasLimit = oldGasLimit - - _, err = f.linkContract.Transfer(f.sergey, f.aggregatorContractAddress, oneEth()) // Actually, LINK - require.NoError(t, err, "failed to fund FluxAggregator contract with LINK") - f.backend.Commit() - - _, err = f.aggregatorContract.UpdateAvailableFunds(f.sergey) - require.NoError(t, err, "failed to update aggregator's availableFunds field") - - f.backend.Commit() - availableFunds, err := f.aggregatorContract.AvailableFunds(nil) - require.NoError(t, err, "failed to retrieve AvailableFunds") - require.Equal(t, availableFunds, oneEth()) - - ilogs, err := f.aggregatorContract.FilterAvailableFundsUpdated(nil, []*big.Int{oneEth()}) - require.NoError(t, err, "failed to gather AvailableFundsUpdated logs") - - logs := cltest.GetLogs(t, nil, ilogs) - require.Len(t, logs, 1, "a single AvailableFundsUpdated log should be emitted") - - return f -} - -// watchSubmissionReceived creates a channel which sends the log when a -// submission is received. When event appears on submissionReceived, -// it indicates that flux monitor job run is complete. -// -// It will only watch for logs from addresses that are provided -func (fau fluxAggregatorUniverse) WatchSubmissionReceived(t *testing.T, addresses []common.Address) chan *faw.FluxAggregatorSubmissionReceived { - submissionReceived := make(chan *faw.FluxAggregatorSubmissionReceived) - subscription, err := fau.aggregatorContract.WatchSubmissionReceived( - nil, - submissionReceived, - []*big.Int{}, - []uint32{}, - addresses, - ) - require.NoError(t, err, "failed to subscribe to SubmissionReceived events") - t.Cleanup(subscription.Unsubscribe) - - return submissionReceived -} - -func startApplication( - t *testing.T, - fa fluxAggregatorUniverse, - overrides func(c *chainlink.Config, s *chainlink.Secrets), -) *cltest.TestApplication { - config, _ := heavyweight.FullTestDBV2(t, overrides) - app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, fa.backend, fa.key) - require.NoError(t, app.Start(testutils.Context(t))) - return app -} - -// checkOraclesAdded asserts that the correct logs were emitted for each oracle added -func checkOraclesAdded(t *testing.T, f fluxAggregatorUniverse, oracleList []common.Address) { - iaddedLogs, err := f.aggregatorContract.FilterOraclePermissionsUpdated(nil, oracleList, []bool{true}) - require.NoError(t, err, "failed to gather OraclePermissionsUpdated logs") - - addedLogs := cltest.GetLogs(t, nil, iaddedLogs) - require.Len(t, addedLogs, len(oracleList), "should have log for each oracle") - - iadminLogs, err := f.aggregatorContract.FilterOracleAdminUpdated(nil, oracleList, oracleList) - require.NoError(t, err, "failed to gather OracleAdminUpdated logs") - - adminLogs := cltest.GetLogs(t, nil, iadminLogs) - require.Len(t, adminLogs, len(oracleList), "should have log for each oracle") - - for oracleIdx, oracle := range oracleList { - require.Equal(t, oracle, addedLogs[oracleIdx].(*faw.FluxAggregatorOraclePermissionsUpdated).Oracle, "log for wrong oracle emitted") - require.Equal(t, oracle, adminLogs[oracleIdx].(*faw.FluxAggregatorOracleAdminUpdated).Oracle, "log for wrong oracle emitted") - } -} - -func generatePriceResponseFn(price func() int64) func() string { - return func() string { - return fmt.Sprintf(`{"data":{"result": %d}}`, price()) - } -} - -type answerParams struct { - fa *fluxAggregatorUniverse - roundId, answer int64 - from *bind.TransactOpts - isNewRound, completesAnswer bool -} - -// checkSubmission verifies all the logs emitted by fa's FluxAggregator -// contract after an updateAnswer with the given values. -func checkSubmission(t *testing.T, p answerParams, currentBalance int64, receiptBlock uint64) { - t.Helper() - if receiptBlock == 0 { - h, err := p.fa.backend.Client().HeaderByNumber(testutils.Context(t), nil) - require.NoError(t, err) - receiptBlock = h.Number.Uint64() - } - blockRange := &bind.FilterOpts{Start: 0, End: &receiptBlock} - - // Could filter for the known values here, but while that would be more - // succinct it leads to less informative error messages... Did the log not - // appear at all, or did it just have a wrong value? - ilogs, err := p.fa.aggregatorContract.FilterSubmissionReceived( - blockRange, - []*big.Int{big.NewInt(p.answer)}, - []uint32{uint32(p.roundId)}, - []common.Address{p.from.From}, - ) - require.NoError(t, err, "failed to get SubmissionReceived logs") - - var srlogs []*faw.FluxAggregatorSubmissionReceived - _ = cltest.GetLogs(t, &srlogs, ilogs) - require.Len(t, srlogs, 1, "FluxAggregator did not emit correct "+ - "SubmissionReceived log") - - inrlogs, err := p.fa.aggregatorContract.FilterNewRound( - blockRange, []*big.Int{big.NewInt(p.roundId)}, []common.Address{p.from.From}, - ) - require.NoError(t, err, "failed to get NewRound logs") - - if p.isNewRound { - var nrlogs []*faw.FluxAggregatorNewRound - cltest.GetLogs(t, &nrlogs, inrlogs) - require.Len(t, nrlogs, 1, "FluxAggregator did not emit correct NewRound "+ - "log") - } else { - assert.Empty(t, cltest.GetLogs(t, nil, inrlogs), "FluxAggregator emitted "+ - "unexpected NewRound log") - } - - iaflogs, err := p.fa.aggregatorContract.FilterAvailableFundsUpdated( - blockRange, []*big.Int{big.NewInt(currentBalance - fee)}, - ) - require.NoError(t, err, "failed to get AvailableFundsUpdated logs") - var aflogs []*faw.FluxAggregatorAvailableFundsUpdated - _ = cltest.GetLogs(t, &aflogs, iaflogs) - assert.Len(t, aflogs, 1, "FluxAggregator did not emit correct "+ - "AvailableFundsUpdated log") - - iaulogs, err := p.fa.aggregatorContract.FilterAnswerUpdated(blockRange, - []*big.Int{big.NewInt(p.answer)}, []*big.Int{big.NewInt(p.roundId)}, - ) - require.NoError(t, err, "failed to get AnswerUpdated logs") - if p.completesAnswer { - var aulogs []*faw.FluxAggregatorAnswerUpdated - _ = cltest.GetLogs(t, &aulogs, iaulogs) - // XXX: sometimes this log is repeated; don't know why... - assert.NotEmpty(t, aulogs, "FluxAggregator did not emit correct "+ - "AnswerUpdated log") - } -} - -// currentbalance returns the current balance of fa's FluxAggregator -func currentBalance(t *testing.T, fa *fluxAggregatorUniverse) *big.Int { - currentBalance, err := fa.aggregatorContract.AvailableFunds(nil) - require.NoError(t, err, "failed to get current FA balance") - return currentBalance -} - -// submitAnswer simulates a call to fa's FluxAggregator contract from a fake -// node (neil or ned), with the given roundId and answer, and checks that all -// the logs emitted by the contract are correct -func submitAnswer(t *testing.T, p answerParams) { - cb := currentBalance(t, p.fa) - - // used to ensure that the simulated backend has processed the submission, - // before we search for the log and check it. - srCh := make(chan *faw.FluxAggregatorSubmissionReceived) - fromBlock := uint64(0) - srSubscription, err := p.fa.aggregatorContract.WatchSubmissionReceived( - &bind.WatchOpts{Start: &fromBlock}, - srCh, - []*big.Int{big.NewInt(p.answer)}, - []uint32{uint32(p.roundId)}, - []common.Address{p.from.From}, - ) - defer func() { - srSubscription.Unsubscribe() - err = <-srSubscription.Err() - require.NoError(t, err, "failed to unsubscribe from AvailableFundsUpdated logs") - }() - - _, err = p.fa.aggregatorContract.Submit( - p.from, big.NewInt(p.roundId), big.NewInt(p.answer), - ) - require.NoError(t, err, "failed to submit answer to flux aggregator") - - p.fa.backend.Commit() - - select { - case <-srCh: - case <-time.After(5 * time.Second): - t.Fatal("failed to complete submission to flux aggregator") - } - checkSubmission(t, p, cb.Int64(), 0) -} - -func awaitSubmission(t *testing.T, backend types.Backend, submissionReceived chan *faw.FluxAggregatorSubmissionReceived) ( - receiptBlock uint64, answer int64, -) { - t.Helper() - - // Send blocks until we get a response - stopBlocks := utils.FiniteTicker(time.Second, func() { backend.Commit() }) - defer stopBlocks() - select { // block until FluxAggregator contract acknowledges chainlink message - case log := <-submissionReceived: - return log.Raw.BlockNumber, log.Submission.Int64() - case <-time.After(20 * pollTimerPeriod): - t.Fatal("chainlink failed to submit answer to FluxAggregator contract") - return 0, 0 // unreachable - } -} - -// assertNoSubmission asserts that no submission was sent for a given duration -func assertNoSubmission(t *testing.T, - submissionReceived chan *faw.FluxAggregatorSubmissionReceived, - duration time.Duration, - msg string, -) { - // drain the channel - for len(submissionReceived) > 0 { - <-submissionReceived - } - - select { - case <-submissionReceived: - assert.Fail(t, "flags are up, but submission was sent", msg) - case <-time.After(duration): - } -} - -// assertPipelineRunCreated checks that a pipeline exists for a given round and -// verifies the answer -func assertPipelineRunCreated(t *testing.T, ds sqlutil.DataSource, roundID int64, result int64) pipeline.Run { - ctx := testutils.Context(t) - // Fetch the stats to extract the run id - stats := fluxmonitorv2.FluxMonitorRoundStatsV2{} - require.NoError(t, ds.GetContext(ctx, &stats, "SELECT * FROM flux_monitor_round_stats_v2 WHERE round_id = $1", roundID)) - if stats.ID == 0 { - t.Fatalf("Stats for round id: %v not found!", roundID) - } - require.True(t, stats.PipelineRunID.Valid) - // Verify the pipeline run data - run := pipeline.Run{} - require.NoError(t, ds.GetContext(ctx, &run, `SELECT * FROM pipeline_runs WHERE id = $1`, stats.PipelineRunID.Int64), "runID %v", stats.PipelineRunID) - assert.Equal(t, []any{result}, run.Outputs.Val) - return run -} - -func checkLogWasConsumed(t *testing.T, fa fluxAggregatorUniverse, ds sqlutil.DataSource, pipelineSpecID int32, blockNumber uint64) { - t.Helper() - lggr := logger.TestLogger(t) - lggr.Infof("Waiting for log on block: %v, job id: %v", blockNumber, pipelineSpecID) - - g := gomega.NewWithT(t) - g.Eventually(func() bool { - ctx := testutils.Context(t) - block, err := fa.backend.Client().BlockByNumber(ctx, new(big.Int).SetUint64(blockNumber)) - require.NoError(t, err) - require.NotNil(t, block) - orm := log.NewORM(ds, fa.evmChainID) - consumed, err := orm.WasBroadcastConsumed(ctx, block.Hash(), 0, pipelineSpecID) - require.NoError(t, err) - fa.backend.Commit() - return consumed - }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) -} - -func TestFluxMonitor_Deviation(t *testing.T) { - quarantine.Flaky(t, "DX-1763") - tests := []struct { - name string - eip1559 bool - }{ - {"legacy", false}, - {"eip1559", true}, - } - - for _, tt := range tests { - test := tt - t.Run(test.name, func(t *testing.T) { - t.Parallel() - g := gomega.NewWithT(t) - fa := setupFluxAggregatorUniverse(t) - - // - add oracles - oracleList := []common.Address{fa.nallory.From} - _, err := fa.aggregatorContract.ChangeOracles(fa.sergey, emptyList, oracleList, oracleList, 1, 1, 0) - assert.NoError(t, err, "failed to add oracles to aggregator") - fa.backend.Commit() - checkOraclesAdded(t, fa, oracleList) - - // Set up chainlink app - app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 - }) - - type v struct { - count int - updatedAt int64 - } - expectedMeta := map[string]v{} - var expMetaMu sync.Mutex - - var reportPrice atomic.Int64 - reportPrice.Store(100) - mockServer := cltest.NewHTTPMockServerWithAlterableResponseAndRequest(t, - generatePriceResponseFn(reportPrice.Load), - func(r *http.Request) { - b, err1 := io.ReadAll(r.Body) - require.NoError(t, err1) - var m bridges.BridgeMetaDataJSON - require.NoError(t, json.Unmarshal(b, &m)) - if m.Meta.LatestAnswer != nil && m.Meta.UpdatedAt != nil { - k := m.Meta.LatestAnswer.String() - expMetaMu.Lock() - curr := expectedMeta[k] - assert.True(t, m.Meta.UpdatedAt.IsInt64()) // sanity check unix ts - expectedMeta[k] = v{curr.count + 1, m.Meta.UpdatedAt.Int64()} - expMetaMu.Unlock() - } - }, - ) - t.Cleanup(mockServer.Close) - u, _ := url.Parse(mockServer.URL) - require.NoError(t, app.BridgeORM().CreateBridgeType(testutils.Context(t), &bridges.BridgeType{ - Name: "bridge", - URL: models.WebURL(*u), - })) - - // When event appears on submissionReceived, flux monitor job run is complete - submissionReceived := fa.WatchSubmissionReceived(t, - []common.Address{fa.nallory.From}, - ) - - // Create the job - s := ` - type = "fluxmonitor" - schemaVersion = 1 - name = "integration test" - contractAddress = "%s" - threshold = 2.0 - absoluteThreshold = 0.0 - evmChainID = 1337 - - idleTimerPeriod = "10s" - idleTimerDisabled = false - - pollTimerPeriod = "%s" - pollTimerDisabled = false - - observationSource = """ - ds1 [type=bridge name=bridge]; - ds1_parse [type=jsonparse path="data,result"]; - - ds1 -> ds1_parse - """ - ` - - s = fmt.Sprintf(s, fa.aggregatorContractAddress, 2*time.Second) - - requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: s, - }) - assert.NoError(t, err) - - initialBalance := currentBalance(t, &fa).Int64() - - jobResponse := cltest.CreateJobViaWeb2(t, app, string(requestBody)) - i, err := strconv.ParseInt(jobResponse.ID, 10, 32) - require.NoError(t, err) - jobID := int32(i) - - // Waiting for flux monitor to finish Register process in log broadcaster - // and then to have log broadcaster backfill logs after the debounceResubscribe period of ~ 1 sec - g.Eventually(func() uint32 { - lb := evmtest.MustGetDefaultChain(t, app.GetRelayers().LegacyEVMChains()).LogBroadcaster() - return lb.(log.BroadcasterInTest).TrackedAddressesCount() - }, testutils.WaitTimeout(t), 200*time.Millisecond).Should(gomega.BeNumerically(">=", 1)) - - // Initial Poll - receiptBlock, answer := awaitSubmission(t, fa.backend, submissionReceived) - - lggr := logger.TestLogger(t) - lggr.Infof("Detected submission: %v in block %v", answer, receiptBlock) - - assert.Equal(t, reportPrice.Load(), answer, - "failed to report correct price to contract") - - checkSubmission(t, - answerParams{ - fa: &fa, - roundId: 1, - answer: int64(100), - from: fa.nallory, - isNewRound: true, - completesAnswer: true, - }, - initialBalance, - receiptBlock, - ) - assertPipelineRunCreated(t, app.GetDB(), 1, int64(100)) - - // Need to wait until NewRound log is consumed - otherwise there is a chance - // it will arrive after the next answer is submitted, and cause - // DeleteFluxMonitorRoundsBackThrough to delete previous stats - checkLogWasConsumed(t, fa, app.GetDB(), jobID, receiptBlock) - - lggr.Info("Updating price to 103") - // Change reported price to a value outside the deviation - reportPrice.Store(103) - receiptBlock, answer = awaitSubmission(t, fa.backend, submissionReceived) - - lggr.Infof("Detected submission: %v in block %v", answer, receiptBlock) - - assert.Equal(t, reportPrice.Load(), answer, - "failed to report correct price to contract") - - checkSubmission(t, - answerParams{ - fa: &fa, - roundId: 2, - answer: int64(103), - from: fa.nallory, - isNewRound: true, - completesAnswer: true, - }, - initialBalance-fee, - receiptBlock, - ) - assertPipelineRunCreated(t, app.GetDB(), 2, int64(103)) - - // Need to wait until NewRound log is consumed - otherwise there is a chance - // it will arrive after the next answer is submitted, and cause - // DeleteFluxMonitorRoundsBackThrough to delete previous stats - checkLogWasConsumed(t, fa, app.GetDB(), jobID, receiptBlock) - - // Should not received a submission as it is inside the deviation - reportPrice.Store(104) - assertNoSubmission(t, submissionReceived, 2*time.Second, "Should not receive a submission") - - expMetaMu.Lock() - defer expMetaMu.Unlock() - assert.Len(t, expectedMeta, 2, "expected metadata %v", expectedMeta) - assert.Positive(t, expectedMeta["100"].count, "Stored answer metadata does not contain 100 but contains: %v", expectedMeta) - assert.Positive(t, expectedMeta["103"].count, "Stored answer metadata does not contain 103 but contains: %v", expectedMeta) - assert.Greater(t, expectedMeta["103"].updatedAt, expectedMeta["100"].updatedAt) - }) - } -} - -func TestFluxMonitor_NewRound(t *testing.T) { - quarantine.Flaky(t, "DX-1865") - g := gomega.NewWithT(t) - fa := setupFluxAggregatorUniverse(t) - - // - add oracles - oracleList := []common.Address{fa.neil.From, fa.nallory.From} - _, err := fa.aggregatorContract.ChangeOracles(fa.sergey, emptyList, oracleList, oracleList, 1, 2, 1) - assert.NoError(t, err, "failed to add oracles to aggregator") - fa.backend.Commit() - checkOraclesAdded(t, fa, oracleList) - - // Set up chainlink app - app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - flags := types.EIP55AddressFromAddress(fa.flagsContractAddress) - c.EVM[0].FlagsContractAddress = &flags - }) - - initialBalance := currentBalance(t, &fa).Int64() - - // Create mock server - var reportPrice atomic.Int64 - reportPrice.Store(1) - mockServer := cltest.NewHTTPMockServerWithAlterableResponse(t, - generatePriceResponseFn(reportPrice.Load), - ) - t.Cleanup(mockServer.Close) - - // When event appears on submissionReceived, flux monitor job run is complete - submissionReceived := fa.WatchSubmissionReceived(t, - []common.Address{fa.nallory.From}, - ) - - // Create the job - s := ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "%s" -evmChainID = "%s" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "%s" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="%s"]; -ds1_parse [type=jsonparse path="data,result"]; - -ds1 -> ds1_parse -""" - ` - - s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), pollTimerPeriod, mockServer.URL) - - // raise flags to disable polling - _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch - require.NoError(t, err) - _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) - require.NoError(t, err) - fa.backend.Commit() - - requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: s, - }) - assert.NoError(t, err) - - cltest.CreateJobViaWeb2(t, app, string(requestBody)) - - // Waiting for flux monitor to finish Register process in log broadcaster - // and then to have log broadcaster backfill logs after the debounceResubscribe period of ~ 1 sec - g.Eventually(func() uint32 { - lb := evmtest.MustGetDefaultChain(t, app.GetRelayers().LegacyEVMChains()).LogBroadcaster() - return lb.(log.BroadcasterInTest).TrackedAddressesCount() - }, testutils.WaitTimeout(t), 200*time.Millisecond).Should(gomega.BeNumerically(">=", 2)) - - // Have the fake node start a new round - submitAnswer(t, answerParams{ - fa: &fa, - roundId: 1, - answer: 2, - from: fa.neil, - isNewRound: true, - completesAnswer: false, - }) - - // Finally, the logs from log broadcaster are sent only after a next block is received. - fa.backend.Commit() - - // Wait for the node's submission, and ensure it submits to the round - // started by the fake node - receiptBlock, _ := awaitSubmission(t, fa.backend, submissionReceived) - checkSubmission(t, - answerParams{ - fa: &fa, - roundId: 1, - answer: int64(1), - from: fa.nallory, - isNewRound: false, - completesAnswer: true, - }, - initialBalance-fee, - receiptBlock, - ) -} - -func TestFluxMonitor_HibernationMode(t *testing.T) { - g := gomega.NewWithT(t) - fa := setupFluxAggregatorUniverse(t) - - // - add oracles - oracleList := []common.Address{fa.nallory.From} - _, err := fa.aggregatorContract.ChangeOracles(fa.sergey, emptyList, oracleList, oracleList, 1, 1, 0) - assert.NoError(t, err, "failed to add oracles to aggregator") - fa.backend.Commit() - checkOraclesAdded(t, fa, oracleList) - - // Start chainlink app - app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - flags := types.EIP55AddressFromAddress(fa.flagsContractAddress) - c.EVM[0].FlagsContractAddress = &flags - }) - - // Create mock server - var reportPrice atomic.Int64 - reportPrice.Store(1) - mockServer := cltest.NewHTTPMockServerWithAlterableResponse(t, - generatePriceResponseFn(reportPrice.Load), - ) - t.Cleanup(mockServer.Close) - - // When event appears on submissionReceived, flux monitor job run is complete - submissionReceived := fa.WatchSubmissionReceived(t, - []common.Address{fa.nallory.From}, - ) - - // Create the job - s := ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "%s" -evmChainID = "%s" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "%s" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="%s"]; -ds1_parse [type=jsonparse path="data,result"]; - -ds1 -> ds1_parse -""" - ` - - s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "1000ms", mockServer.URL) - - // raise flags - _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch - require.NoError(t, err) - - _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) - require.NoError(t, err) - fa.backend.Commit() - - requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: s, - }) - assert.NoError(t, err) - - j := cltest.CreateJobViaWeb2(t, app, string(requestBody)) - - // node doesn't submit initial response, because flag is up - // Wait here so the next lower flags doesn't trigger immediately - cltest.AssertPipelineRunsStays(t, j.PipelineSpec.ID, app.GetDB(), 0) - - // lower global kill switch flag - should trigger job run - _, err = fa.flagsContract.LowerFlags(fa.sergey, []common.Address{evmutils.ZeroAddress}) - require.NoError(t, err) - fa.backend.Commit() - awaitSubmission(t, fa.backend, submissionReceived) - - reportPrice.Store(2) // change in price should trigger run - awaitSubmission(t, fa.backend, submissionReceived) - - // lower contract's flag - should have no effect - _, err = fa.flagsContract.LowerFlags(fa.sergey, []common.Address{fa.aggregatorContractAddress}) - require.NoError(t, err) - fa.backend.Commit() - assertNoSubmission(t, submissionReceived, 5*pollTimerPeriod, "should not trigger a new run because FM is already hibernating") - - // change in price should trigger run - reportPrice.Store(4) - awaitSubmission(t, fa.backend, submissionReceived) - - // raise both flags - _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) - require.NoError(t, err) - _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) - require.NoError(t, err) - fa.backend.Commit() - - // wait for FM to receive flags raised logs - g.Eventually(func() int { - ilogs, err := fa.flagsContract.FilterFlagRaised(nil, []common.Address{}) - require.NoError(t, err) - logs := cltest.GetLogs(t, nil, ilogs) - return len(logs) - }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.Equal(4)) - - // change in price should not trigger run - reportPrice.Store(8) - assertNoSubmission(t, submissionReceived, 5*pollTimerPeriod, "should not trigger a new run, while flag is raised") -} - -func TestFluxMonitor_InvalidSubmission(t *testing.T) { - // 8 decimals places used for prices. - fa := setupFluxAggregatorUniverse(t, WithMinMaxSubmission( - big.NewInt(100000000), // 1 * 10^8 - big.NewInt(1000000000000), // 10000 * 10^8 - )) - - oracleList := []common.Address{fa.neil.From, fa.ned.From, fa.nallory.From} - _, err := fa.aggregatorContract.ChangeOracles(fa.sergey, emptyList, oracleList, oracleList, 1, 3, 2) - assert.NoError(t, err, "failed to add oracles to aggregator") - fa.backend.Commit() - - // Set up chainlink app - app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - }) - - // Report a price that is above the maximum allowed value, - // causing it to revert. - var reportPrice atomic.Int64 - reportPrice.Store(10001) // 10001 ETH/USD price is outside the range. - mockServer := cltest.NewHTTPMockServerWithAlterableResponse(t, - generatePriceResponseFn(reportPrice.Load), - ) - t.Cleanup(mockServer.Close) - - // Generate custom TOML for this test due to precision change - toml := ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "%s" -evmChainID = "%s" -threshold = 0.5 -absoluteThreshold = 0.01 - -idleTimerPeriod = "1h" -idleTimerDisabled = false - -pollTimerPeriod = "%s" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="%s"]; -ds1_parse [type=jsonparse path="data,result"]; - -ds1 -> ds1_parse -""" -` - - s := fmt.Sprintf(toml, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "100ms", mockServer.URL) - - // raise flags - _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch - require.NoError(t, err) - _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) - require.NoError(t, err) - fa.backend.Commit() - - requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: s, - }) - assert.NoError(t, err) - - j := cltest.CreateJobViaWeb2(t, app, string(requestBody)) - - _, closer := cltest.Mine(fa.backend, 500*time.Millisecond) - defer closer() - - // We should see a spec error because the value is too large to submit on-chain. - jobID, err := strconv.ParseInt(j.ID, 10, 32) - require.NoError(t, err) - - jse := cltest.WaitForSpecErrorV2(t, app.GetDB(), int32(jobID), 1) - assert.Contains(t, jse[0].Description, "Answer is outside acceptable range") -} - -func TestFluxMonitorAntiSpamLogic(t *testing.T) { - // - deploy a brand new FM contract - fa := setupFluxAggregatorUniverse(t) - - // - add oracles - oracleList := []common.Address{fa.neil.From, fa.ned.From, fa.nallory.From} - _, err := fa.aggregatorContract.ChangeOracles(fa.sergey, emptyList, oracleList, oracleList, 2, 3, 2) - assert.NoError(t, err, "failed to add oracles to aggregator") - fa.backend.Commit() - checkOraclesAdded(t, fa, oracleList) - - // Set up chainlink app - app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) - }) - - answer := int64(1) // Answer the nodes give on the first round - - //- have one of the fake nodes start a round. - roundId := int64(1) - processedAnswer := answer * 100 /* job has multiply times 100 */ - submitAnswer(t, answerParams{ - fa: &fa, - roundId: roundId, - answer: processedAnswer, - from: fa.neil, - isNewRound: true, - completesAnswer: false, - }) - - // - successfully close the round through the submissions of the other nodes - // Response by spammy chainlink node, nallory - // - // The initial balance is the LINK balance of flux aggregator contract. We - // use it to check that the fee for submitting an answer has been paid out. - initialBalance := currentBalance(t, &fa).Int64() - var reportPrice atomic.Int64 - reportPrice.Store(answer) - priceResponse := func() string { - return fmt.Sprintf(`{"data":{"result": %d}}`, reportPrice.Load()) - } - mockServer := cltest.NewHTTPMockServerWithAlterableResponse(t, priceResponse) - t.Cleanup(mockServer.Close) - - // When event appears on submissionReceived, flux monitor job run is complete - submissionReceived := fa.WatchSubmissionReceived(t, - []common.Address{fa.nallory.From}, - ) - - // Create FM Job, and wait for job run to start (the above submitAnswr call - // to FluxAggregator contract initiates a run.) - s := ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "%s" -evmChainID = "%s" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "%s" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="%s"]; -ds1_parse [type=jsonparse path="data,result"]; -ds1_multiply [type=multiply times=100] - -ds1 -> ds1_parse -> ds1_multiply -""" - ` - - s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "200ms", mockServer.URL) - requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: s, - }) - assert.NoError(t, err) - - cltest.CreateJobViaWeb2(t, app, string(requestBody)) - - receiptBlock, answer := awaitSubmission(t, fa.backend, submissionReceived) - - assert.Equal(t, 100*reportPrice.Load(), answer, - "failed to report correct price to contract") - checkSubmission(t, - answerParams{ - fa: &fa, - roundId: roundId, - answer: processedAnswer, - from: fa.nallory, - isNewRound: false, - completesAnswer: true}, - initialBalance, - receiptBlock, - ) - - //- have the malicious node start the next round. - nextRoundBalance := initialBalance - fee - // Triggers a new round, since price deviation exceeds threshold - reportPrice.Store(answer + 1) - - receiptBlock, _ = awaitSubmission(t, fa.backend, submissionReceived) - newRound := roundId + 1 - processedAnswer = 100 * reportPrice.Load() - checkSubmission(t, - answerParams{ - fa: &fa, - roundId: newRound, - answer: processedAnswer, - from: fa.nallory, - isNewRound: true, - completesAnswer: false}, - nextRoundBalance, - receiptBlock, - ) - - // Successfully close the round through the submissions of the other nodes - submitAnswer(t, - answerParams{ - fa: &fa, - roundId: newRound, - answer: processedAnswer, - from: fa.neil, - isNewRound: false, - completesAnswer: true}, - ) - - // Have the malicious node try to start another round. It should not pass as - // restartDelay has not been reached. - newRound = newRound + 1 - processedAnswer = 100 * reportPrice.Load() - - submitMaliciousAnswer(t, - answerParams{ - fa: &fa, - roundId: newRound, - answer: processedAnswer, - from: fa.nallory, - isNewRound: true, - completesAnswer: false}, - ) - - assertNoSubmission(t, submissionReceived, 5*pollTimerPeriod, "FA allowed chainlink node to start a new round early") - - // Try to start a new round directly, should fail because of delay - _, err = fa.aggregatorContract.RequestNewRound(fa.nallory) - assert.Error(t, err, "FA allowed chainlink node to start a new round early") - - //- finally, ensure it can start a legitimate round after restartDelay is - // reached start an intervening round - submitAnswer(t, answerParams{fa: &fa, roundId: newRound, - answer: processedAnswer, from: fa.ned, isNewRound: true, - completesAnswer: false}) - submitAnswer(t, answerParams{fa: &fa, roundId: newRound, - answer: processedAnswer, from: fa.neil, isNewRound: false, - completesAnswer: true}) - - // start a legitimate new round - reportPrice.Add(3) - - // Wait for the node's submission, and ensure it submits to the round - // started by the fake node - awaitSubmission(t, fa.backend, submissionReceived) -} - -// submitMaliciousAnswer simulates a call to fa's FluxAggregator contract from -// nallory, with the given roundId and answer and errors -func submitMaliciousAnswer(t *testing.T, p answerParams) { - _, err := p.fa.aggregatorContract.Submit( - p.from, big.NewInt(p.roundId), big.NewInt(p.answer), - ) - require.Error(t, err) - - p.fa.backend.Commit() -} diff --git a/core/services/fluxmonitorv2/key_store.go b/core/services/fluxmonitorv2/key_store.go deleted file mode 100644 index 26ea88ea960..00000000000 --- a/core/services/fluxmonitorv2/key_store.go +++ /dev/null @@ -1,27 +0,0 @@ -package fluxmonitorv2 - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" -) - -// KeyStoreInterface defines an interface to interact with the keystore -type KeyStoreInterface interface { - EnabledKeysForChain(ctx context.Context, chainID *big.Int) ([]ethkey.KeyV2, error) - GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addrs ...common.Address) (common.Address, error) -} - -// KeyStore implements KeyStoreInterface -type KeyStore struct { - keystore.Eth -} - -// NewKeyStore initializes a new keystore -func NewKeyStore(ks keystore.Eth) *KeyStore { - return &KeyStore{ks} -} diff --git a/core/services/fluxmonitorv2/key_store_test.go b/core/services/fluxmonitorv2/key_store_test.go deleted file mode 100644 index 78804343981..00000000000 --- a/core/services/fluxmonitorv2/key_store_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package fluxmonitorv2_test - -import ( - "testing" - - "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/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -func TestKeyStore_EnabledKeysForChain(t *testing.T) { - t.Parallel() - ctx := testutils.Context(t) - - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - ks := fluxmonitorv2.NewKeyStore(ethKeyStore) - - key, err := ethKeyStore.Create(ctx, testutils.FixtureChainID) - require.NoError(t, err) - key2, err := ethKeyStore.Create(ctx, testutils.SimulatedChainID) - require.NoError(t, err) - - keys, err := ks.EnabledKeysForChain(ctx, testutils.FixtureChainID) - require.NoError(t, err) - require.Len(t, keys, 1) - require.Equal(t, key.ID(), keys[0].ID()) - require.Equal(t, key.Raw(), keys[0].Raw()) - require.EqualExportedValues(t, key, keys[0]) - - keys, err = ks.EnabledKeysForChain(ctx, testutils.SimulatedChainID) - require.NoError(t, err) - require.Len(t, keys, 1) - require.Equal(t, key2.ID(), keys[0].ID()) - require.Equal(t, key2.Raw(), keys[0].Raw()) - require.EqualExportedValues(t, key2, keys[0]) -} - -func TestKeyStore_GetRoundRobinAddress(t *testing.T) { - t.Parallel() - - ctx := testutils.Context(t) - - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, k0Address := cltest.MustInsertRandomKey(t, ethKeyStore) - - ks := fluxmonitorv2.NewKeyStore(ethKeyStore) - - // Gets the only address in the keystore - addr, err := ks.GetRoundRobinAddress(ctx, testutils.FixtureChainID) - require.NoError(t, err) - require.Equal(t, k0Address, addr) -} diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go deleted file mode 100644 index 17b7296bc44..00000000000 --- a/core/services/fluxmonitorv2/mocks/contract_submitter.go +++ /dev/null @@ -1,86 +0,0 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - big "math/big" - - mock "github.com/stretchr/testify/mock" -) - -// ContractSubmitter is an autogenerated mock type for the ContractSubmitter type -type ContractSubmitter struct { - mock.Mock -} - -type ContractSubmitter_Expecter struct { - mock *mock.Mock -} - -func (_m *ContractSubmitter) EXPECT() *ContractSubmitter_Expecter { - return &ContractSubmitter_Expecter{mock: &_m.Mock} -} - -// Submit provides a mock function with given fields: ctx, roundID, submission, idempotencyKey -func (_m *ContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { - ret := _m.Called(ctx, roundID, submission, idempotencyKey) - - if len(ret) == 0 { - panic("no return value specified for Submit") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int, *big.Int, *string) error); ok { - r0 = rf(ctx, roundID, submission, idempotencyKey) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractSubmitter_Submit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Submit' -type ContractSubmitter_Submit_Call struct { - *mock.Call -} - -// Submit is a helper method to define mock.On call -// - ctx context.Context -// - roundID *big.Int -// - submission *big.Int -// - idempotencyKey *string -func (_e *ContractSubmitter_Expecter) Submit(ctx interface{}, roundID interface{}, submission interface{}, idempotencyKey interface{}) *ContractSubmitter_Submit_Call { - return &ContractSubmitter_Submit_Call{Call: _e.mock.On("Submit", ctx, roundID, submission, idempotencyKey)} -} - -func (_c *ContractSubmitter_Submit_Call) Run(run func(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string)) *ContractSubmitter_Submit_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*big.Int), args[2].(*big.Int), args[3].(*string)) - }) - return _c -} - -func (_c *ContractSubmitter_Submit_Call) Return(_a0 error) *ContractSubmitter_Submit_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractSubmitter_Submit_Call) RunAndReturn(run func(context.Context, *big.Int, *big.Int, *string) error) *ContractSubmitter_Submit_Call { - _c.Call.Return(run) - return _c -} - -// NewContractSubmitter creates a new instance of ContractSubmitter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewContractSubmitter(t interface { - mock.TestingT - Cleanup(func()) -}) *ContractSubmitter { - mock := &ContractSubmitter{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go deleted file mode 100644 index 0fb1f92cbab..00000000000 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ /dev/null @@ -1,244 +0,0 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. - -package mocks - -import ( - common "github.com/ethereum/go-ethereum/common" - - types "github.com/ethereum/go-ethereum/core/types" - generated "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated" - mock "github.com/stretchr/testify/mock" -) - -// Flags is an autogenerated mock type for the Flags type -type Flags struct { - mock.Mock -} - -type Flags_Expecter struct { - mock *mock.Mock -} - -func (_m *Flags) EXPECT() *Flags_Expecter { - return &Flags_Expecter{mock: &_m.Mock} -} - -// Address provides a mock function with no fields -func (_m *Flags) Address() common.Address { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Address") - } - - var r0 common.Address - if rf, ok := ret.Get(0).(func() common.Address); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - return r0 -} - -// Flags_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address' -type Flags_Address_Call struct { - *mock.Call -} - -// Address is a helper method to define mock.On call -func (_e *Flags_Expecter) Address() *Flags_Address_Call { - return &Flags_Address_Call{Call: _e.mock.On("Address")} -} - -func (_c *Flags_Address_Call) Run(run func()) *Flags_Address_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Flags_Address_Call) Return(_a0 common.Address) *Flags_Address_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *Flags_Address_Call) RunAndReturn(run func() common.Address) *Flags_Address_Call { - _c.Call.Return(run) - return _c -} - -// ContractExists provides a mock function with no fields -func (_m *Flags) ContractExists() bool { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for ContractExists") - } - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Flags_ContractExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ContractExists' -type Flags_ContractExists_Call struct { - *mock.Call -} - -// ContractExists is a helper method to define mock.On call -func (_e *Flags_Expecter) ContractExists() *Flags_ContractExists_Call { - return &Flags_ContractExists_Call{Call: _e.mock.On("ContractExists")} -} - -func (_c *Flags_ContractExists_Call) Run(run func()) *Flags_ContractExists_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *Flags_ContractExists_Call) Return(_a0 bool) *Flags_ContractExists_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *Flags_ContractExists_Call) RunAndReturn(run func() bool) *Flags_ContractExists_Call { - _c.Call.Return(run) - return _c -} - -// IsLowered provides a mock function with given fields: contractAddr -func (_m *Flags) IsLowered(contractAddr common.Address) (bool, error) { - ret := _m.Called(contractAddr) - - if len(ret) == 0 { - panic("no return value specified for IsLowered") - } - - var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(common.Address) (bool, error)); ok { - return rf(contractAddr) - } - if rf, ok := ret.Get(0).(func(common.Address) bool); ok { - r0 = rf(contractAddr) - } else { - r0 = ret.Get(0).(bool) - } - - if rf, ok := ret.Get(1).(func(common.Address) error); ok { - r1 = rf(contractAddr) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Flags_IsLowered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsLowered' -type Flags_IsLowered_Call struct { - *mock.Call -} - -// IsLowered is a helper method to define mock.On call -// - contractAddr common.Address -func (_e *Flags_Expecter) IsLowered(contractAddr interface{}) *Flags_IsLowered_Call { - return &Flags_IsLowered_Call{Call: _e.mock.On("IsLowered", contractAddr)} -} - -func (_c *Flags_IsLowered_Call) Run(run func(contractAddr common.Address)) *Flags_IsLowered_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(common.Address)) - }) - return _c -} - -func (_c *Flags_IsLowered_Call) Return(_a0 bool, _a1 error) *Flags_IsLowered_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *Flags_IsLowered_Call) RunAndReturn(run func(common.Address) (bool, error)) *Flags_IsLowered_Call { - _c.Call.Return(run) - return _c -} - -// ParseLog provides a mock function with given fields: log -func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { - ret := _m.Called(log) - - if len(ret) == 0 { - panic("no return value specified for ParseLog") - } - - var r0 generated.AbigenLog - var r1 error - if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { - return rf(log) - } - if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok { - r0 = rf(log) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(generated.AbigenLog) - } - } - - if rf, ok := ret.Get(1).(func(types.Log) error); ok { - r1 = rf(log) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Flags_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog' -type Flags_ParseLog_Call struct { - *mock.Call -} - -// ParseLog is a helper method to define mock.On call -// - log types.Log -func (_e *Flags_Expecter) ParseLog(log interface{}) *Flags_ParseLog_Call { - return &Flags_ParseLog_Call{Call: _e.mock.On("ParseLog", log)} -} - -func (_c *Flags_ParseLog_Call) Run(run func(log types.Log)) *Flags_ParseLog_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(types.Log)) - }) - return _c -} - -func (_c *Flags_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *Flags_ParseLog_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *Flags_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *Flags_ParseLog_Call { - _c.Call.Return(run) - return _c -} - -// NewFlags creates a new instance of Flags. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewFlags(t interface { - mock.TestingT - Cleanup(func()) -}) *Flags { - mock := &Flags{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go deleted file mode 100644 index d3aa60f0c31..00000000000 --- a/core/services/fluxmonitorv2/mocks/key_store_interface.go +++ /dev/null @@ -1,173 +0,0 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - big "math/big" - - common "github.com/ethereum/go-ethereum/common" - ethkey "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" - - mock "github.com/stretchr/testify/mock" -) - -// KeyStoreInterface is an autogenerated mock type for the KeyStoreInterface type -type KeyStoreInterface struct { - mock.Mock -} - -type KeyStoreInterface_Expecter struct { - mock *mock.Mock -} - -func (_m *KeyStoreInterface) EXPECT() *KeyStoreInterface_Expecter { - return &KeyStoreInterface_Expecter{mock: &_m.Mock} -} - -// EnabledKeysForChain provides a mock function with given fields: ctx, chainID -func (_m *KeyStoreInterface) EnabledKeysForChain(ctx context.Context, chainID *big.Int) ([]ethkey.KeyV2, error) { - ret := _m.Called(ctx, chainID) - - if len(ret) == 0 { - panic("no return value specified for EnabledKeysForChain") - } - - var r0 []ethkey.KeyV2 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) ([]ethkey.KeyV2, error)); ok { - return rf(ctx, chainID) - } - if rf, ok := ret.Get(0).(func(context.Context, *big.Int) []ethkey.KeyV2); ok { - r0 = rf(ctx, chainID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]ethkey.KeyV2) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { - r1 = rf(ctx, chainID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// KeyStoreInterface_EnabledKeysForChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnabledKeysForChain' -type KeyStoreInterface_EnabledKeysForChain_Call struct { - *mock.Call -} - -// EnabledKeysForChain is a helper method to define mock.On call -// - ctx context.Context -// - chainID *big.Int -func (_e *KeyStoreInterface_Expecter) EnabledKeysForChain(ctx interface{}, chainID interface{}) *KeyStoreInterface_EnabledKeysForChain_Call { - return &KeyStoreInterface_EnabledKeysForChain_Call{Call: _e.mock.On("EnabledKeysForChain", ctx, chainID)} -} - -func (_c *KeyStoreInterface_EnabledKeysForChain_Call) Run(run func(ctx context.Context, chainID *big.Int)) *KeyStoreInterface_EnabledKeysForChain_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*big.Int)) - }) - return _c -} - -func (_c *KeyStoreInterface_EnabledKeysForChain_Call) Return(_a0 []ethkey.KeyV2, _a1 error) *KeyStoreInterface_EnabledKeysForChain_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *KeyStoreInterface_EnabledKeysForChain_Call) RunAndReturn(run func(context.Context, *big.Int) ([]ethkey.KeyV2, error)) *KeyStoreInterface_EnabledKeysForChain_Call { - _c.Call.Return(run) - return _c -} - -// GetRoundRobinAddress provides a mock function with given fields: ctx, chainID, addrs -func (_m *KeyStoreInterface) GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addrs ...common.Address) (common.Address, error) { - _va := make([]interface{}, len(addrs)) - for _i := range addrs { - _va[_i] = addrs[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, chainID) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for GetRoundRobinAddress") - } - - var r0 common.Address - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) (common.Address, error)); ok { - return rf(ctx, chainID, addrs...) - } - if rf, ok := ret.Get(0).(func(context.Context, *big.Int, ...common.Address) common.Address); ok { - r0 = rf(ctx, chainID, addrs...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Address) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, *big.Int, ...common.Address) error); ok { - r1 = rf(ctx, chainID, addrs...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// KeyStoreInterface_GetRoundRobinAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRoundRobinAddress' -type KeyStoreInterface_GetRoundRobinAddress_Call struct { - *mock.Call -} - -// GetRoundRobinAddress is a helper method to define mock.On call -// - ctx context.Context -// - chainID *big.Int -// - addrs ...common.Address -func (_e *KeyStoreInterface_Expecter) GetRoundRobinAddress(ctx interface{}, chainID interface{}, addrs ...interface{}) *KeyStoreInterface_GetRoundRobinAddress_Call { - return &KeyStoreInterface_GetRoundRobinAddress_Call{Call: _e.mock.On("GetRoundRobinAddress", - append([]interface{}{ctx, chainID}, addrs...)...)} -} - -func (_c *KeyStoreInterface_GetRoundRobinAddress_Call) Run(run func(ctx context.Context, chainID *big.Int, addrs ...common.Address)) *KeyStoreInterface_GetRoundRobinAddress_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]common.Address, len(args)-2) - for i, a := range args[2:] { - if a != nil { - variadicArgs[i] = a.(common.Address) - } - } - run(args[0].(context.Context), args[1].(*big.Int), variadicArgs...) - }) - return _c -} - -func (_c *KeyStoreInterface_GetRoundRobinAddress_Call) Return(_a0 common.Address, _a1 error) *KeyStoreInterface_GetRoundRobinAddress_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *KeyStoreInterface_GetRoundRobinAddress_Call) RunAndReturn(run func(context.Context, *big.Int, ...common.Address) (common.Address, error)) *KeyStoreInterface_GetRoundRobinAddress_Call { - _c.Call.Return(run) - return _c -} - -// NewKeyStoreInterface creates a new instance of KeyStoreInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewKeyStoreInterface(t interface { - mock.TestingT - Cleanup(func()) -}) *KeyStoreInterface { - mock := &KeyStoreInterface{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go deleted file mode 100644 index 51cce0ab2ee..00000000000 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ /dev/null @@ -1,408 +0,0 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - common "github.com/ethereum/go-ethereum/common" - sqlutil "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - fluxmonitorv2 "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - mock "github.com/stretchr/testify/mock" -) - -// ORM is an autogenerated mock type for the ORM type -type ORM struct { - mock.Mock -} - -type ORM_Expecter struct { - mock *mock.Mock -} - -func (_m *ORM) EXPECT() *ORM_Expecter { - return &ORM_Expecter{mock: &_m.Mock} -} - -// CountFluxMonitorRoundStats provides a mock function with given fields: ctx -func (_m *ORM) CountFluxMonitorRoundStats(ctx context.Context) (int, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for CountFluxMonitorRoundStats") - } - - var r0 int - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) int); ok { - r0 = rf(ctx) - } else { - r0 = ret.Get(0).(int) - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ORM_CountFluxMonitorRoundStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CountFluxMonitorRoundStats' -type ORM_CountFluxMonitorRoundStats_Call struct { - *mock.Call -} - -// CountFluxMonitorRoundStats is a helper method to define mock.On call -// - ctx context.Context -func (_e *ORM_Expecter) CountFluxMonitorRoundStats(ctx interface{}) *ORM_CountFluxMonitorRoundStats_Call { - return &ORM_CountFluxMonitorRoundStats_Call{Call: _e.mock.On("CountFluxMonitorRoundStats", ctx)} -} - -func (_c *ORM_CountFluxMonitorRoundStats_Call) Run(run func(ctx context.Context)) *ORM_CountFluxMonitorRoundStats_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *ORM_CountFluxMonitorRoundStats_Call) Return(count int, err error) *ORM_CountFluxMonitorRoundStats_Call { - _c.Call.Return(count, err) - return _c -} - -func (_c *ORM_CountFluxMonitorRoundStats_Call) RunAndReturn(run func(context.Context) (int, error)) *ORM_CountFluxMonitorRoundStats_Call { - _c.Call.Return(run) - return _c -} - -// CreateEthTransaction provides a mock function with given fields: ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey -func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint64, idempotencyKey *string) error { - ret := _m.Called(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) - - if len(ret) == 0 { - panic("no return value specified for CreateEthTransaction") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address, []byte, uint64, *string) error); ok { - r0 = rf(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ORM_CreateEthTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateEthTransaction' -type ORM_CreateEthTransaction_Call struct { - *mock.Call -} - -// CreateEthTransaction is a helper method to define mock.On call -// - ctx context.Context -// - fromAddress common.Address -// - toAddress common.Address -// - payload []byte -// - gasLimit uint64 -// - idempotencyKey *string -func (_e *ORM_Expecter) CreateEthTransaction(ctx interface{}, fromAddress interface{}, toAddress interface{}, payload interface{}, gasLimit interface{}, idempotencyKey interface{}) *ORM_CreateEthTransaction_Call { - return &ORM_CreateEthTransaction_Call{Call: _e.mock.On("CreateEthTransaction", ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey)} -} - -func (_c *ORM_CreateEthTransaction_Call) Run(run func(ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint64, idempotencyKey *string)) *ORM_CreateEthTransaction_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Address), args[2].(common.Address), args[3].([]byte), args[4].(uint64), args[5].(*string)) - }) - return _c -} - -func (_c *ORM_CreateEthTransaction_Call) Return(_a0 error) *ORM_CreateEthTransaction_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ORM_CreateEthTransaction_Call) RunAndReturn(run func(context.Context, common.Address, common.Address, []byte, uint64, *string) error) *ORM_CreateEthTransaction_Call { - _c.Call.Return(run) - return _c -} - -// DeleteFluxMonitorRoundsBackThrough provides a mock function with given fields: ctx, aggregator, roundID -func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error { - ret := _m.Called(ctx, aggregator, roundID) - - if len(ret) == 0 { - panic("no return value specified for DeleteFluxMonitorRoundsBackThrough") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32) error); ok { - r0 = rf(ctx, aggregator, roundID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ORM_DeleteFluxMonitorRoundsBackThrough_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFluxMonitorRoundsBackThrough' -type ORM_DeleteFluxMonitorRoundsBackThrough_Call struct { - *mock.Call -} - -// DeleteFluxMonitorRoundsBackThrough is a helper method to define mock.On call -// - ctx context.Context -// - aggregator common.Address -// - roundID uint32 -func (_e *ORM_Expecter) DeleteFluxMonitorRoundsBackThrough(ctx interface{}, aggregator interface{}, roundID interface{}) *ORM_DeleteFluxMonitorRoundsBackThrough_Call { - return &ORM_DeleteFluxMonitorRoundsBackThrough_Call{Call: _e.mock.On("DeleteFluxMonitorRoundsBackThrough", ctx, aggregator, roundID)} -} - -func (_c *ORM_DeleteFluxMonitorRoundsBackThrough_Call) Run(run func(ctx context.Context, aggregator common.Address, roundID uint32)) *ORM_DeleteFluxMonitorRoundsBackThrough_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Address), args[2].(uint32)) - }) - return _c -} - -func (_c *ORM_DeleteFluxMonitorRoundsBackThrough_Call) Return(_a0 error) *ORM_DeleteFluxMonitorRoundsBackThrough_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ORM_DeleteFluxMonitorRoundsBackThrough_Call) RunAndReturn(run func(context.Context, common.Address, uint32) error) *ORM_DeleteFluxMonitorRoundsBackThrough_Call { - _c.Call.Return(run) - return _c -} - -// FindOrCreateFluxMonitorRoundStats provides a mock function with given fields: ctx, aggregator, roundID, newRoundLogs -func (_m *ORM) FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error) { - ret := _m.Called(ctx, aggregator, roundID, newRoundLogs) - - if len(ret) == 0 { - panic("no return value specified for FindOrCreateFluxMonitorRoundStats") - } - - var r0 fluxmonitorv2.FluxMonitorRoundStatsV2 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)); ok { - return rf(ctx, aggregator, roundID, newRoundLogs) - } - if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, uint) fluxmonitorv2.FluxMonitorRoundStatsV2); ok { - r0 = rf(ctx, aggregator, roundID, newRoundLogs) - } else { - r0 = ret.Get(0).(fluxmonitorv2.FluxMonitorRoundStatsV2) - } - - if rf, ok := ret.Get(1).(func(context.Context, common.Address, uint32, uint) error); ok { - r1 = rf(ctx, aggregator, roundID, newRoundLogs) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ORM_FindOrCreateFluxMonitorRoundStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindOrCreateFluxMonitorRoundStats' -type ORM_FindOrCreateFluxMonitorRoundStats_Call struct { - *mock.Call -} - -// FindOrCreateFluxMonitorRoundStats is a helper method to define mock.On call -// - ctx context.Context -// - aggregator common.Address -// - roundID uint32 -// - newRoundLogs uint -func (_e *ORM_Expecter) FindOrCreateFluxMonitorRoundStats(ctx interface{}, aggregator interface{}, roundID interface{}, newRoundLogs interface{}) *ORM_FindOrCreateFluxMonitorRoundStats_Call { - return &ORM_FindOrCreateFluxMonitorRoundStats_Call{Call: _e.mock.On("FindOrCreateFluxMonitorRoundStats", ctx, aggregator, roundID, newRoundLogs)} -} - -func (_c *ORM_FindOrCreateFluxMonitorRoundStats_Call) Run(run func(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint)) *ORM_FindOrCreateFluxMonitorRoundStats_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Address), args[2].(uint32), args[3].(uint)) - }) - return _c -} - -func (_c *ORM_FindOrCreateFluxMonitorRoundStats_Call) Return(_a0 fluxmonitorv2.FluxMonitorRoundStatsV2, _a1 error) *ORM_FindOrCreateFluxMonitorRoundStats_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *ORM_FindOrCreateFluxMonitorRoundStats_Call) RunAndReturn(run func(context.Context, common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)) *ORM_FindOrCreateFluxMonitorRoundStats_Call { - _c.Call.Return(run) - return _c -} - -// MostRecentFluxMonitorRoundID provides a mock function with given fields: ctx, aggregator -func (_m *ORM) MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) { - ret := _m.Called(ctx, aggregator) - - if len(ret) == 0 { - panic("no return value specified for MostRecentFluxMonitorRoundID") - } - - var r0 uint32 - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint32, error)); ok { - return rf(ctx, aggregator) - } - if rf, ok := ret.Get(0).(func(context.Context, common.Address) uint32); ok { - r0 = rf(ctx, aggregator) - } else { - r0 = ret.Get(0).(uint32) - } - - if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { - r1 = rf(ctx, aggregator) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ORM_MostRecentFluxMonitorRoundID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MostRecentFluxMonitorRoundID' -type ORM_MostRecentFluxMonitorRoundID_Call struct { - *mock.Call -} - -// MostRecentFluxMonitorRoundID is a helper method to define mock.On call -// - ctx context.Context -// - aggregator common.Address -func (_e *ORM_Expecter) MostRecentFluxMonitorRoundID(ctx interface{}, aggregator interface{}) *ORM_MostRecentFluxMonitorRoundID_Call { - return &ORM_MostRecentFluxMonitorRoundID_Call{Call: _e.mock.On("MostRecentFluxMonitorRoundID", ctx, aggregator)} -} - -func (_c *ORM_MostRecentFluxMonitorRoundID_Call) Run(run func(ctx context.Context, aggregator common.Address)) *ORM_MostRecentFluxMonitorRoundID_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Address)) - }) - return _c -} - -func (_c *ORM_MostRecentFluxMonitorRoundID_Call) Return(_a0 uint32, _a1 error) *ORM_MostRecentFluxMonitorRoundID_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *ORM_MostRecentFluxMonitorRoundID_Call) RunAndReturn(run func(context.Context, common.Address) (uint32, error)) *ORM_MostRecentFluxMonitorRoundID_Call { - _c.Call.Return(run) - return _c -} - -// UpdateFluxMonitorRoundStats provides a mock function with given fields: ctx, aggregator, roundID, runID, newRoundLogsAddition -func (_m *ORM) UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error { - ret := _m.Called(ctx, aggregator, roundID, runID, newRoundLogsAddition) - - if len(ret) == 0 { - panic("no return value specified for UpdateFluxMonitorRoundStats") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint32, int64, uint) error); ok { - r0 = rf(ctx, aggregator, roundID, runID, newRoundLogsAddition) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ORM_UpdateFluxMonitorRoundStats_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateFluxMonitorRoundStats' -type ORM_UpdateFluxMonitorRoundStats_Call struct { - *mock.Call -} - -// UpdateFluxMonitorRoundStats is a helper method to define mock.On call -// - ctx context.Context -// - aggregator common.Address -// - roundID uint32 -// - runID int64 -// - newRoundLogsAddition uint -func (_e *ORM_Expecter) UpdateFluxMonitorRoundStats(ctx interface{}, aggregator interface{}, roundID interface{}, runID interface{}, newRoundLogsAddition interface{}) *ORM_UpdateFluxMonitorRoundStats_Call { - return &ORM_UpdateFluxMonitorRoundStats_Call{Call: _e.mock.On("UpdateFluxMonitorRoundStats", ctx, aggregator, roundID, runID, newRoundLogsAddition)} -} - -func (_c *ORM_UpdateFluxMonitorRoundStats_Call) Run(run func(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint)) *ORM_UpdateFluxMonitorRoundStats_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(common.Address), args[2].(uint32), args[3].(int64), args[4].(uint)) - }) - return _c -} - -func (_c *ORM_UpdateFluxMonitorRoundStats_Call) Return(_a0 error) *ORM_UpdateFluxMonitorRoundStats_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ORM_UpdateFluxMonitorRoundStats_Call) RunAndReturn(run func(context.Context, common.Address, uint32, int64, uint) error) *ORM_UpdateFluxMonitorRoundStats_Call { - _c.Call.Return(run) - return _c -} - -// WithDataSource provides a mock function with given fields: _a0 -func (_m *ORM) WithDataSource(_a0 sqlutil.DataSource) fluxmonitorv2.ORM { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for WithDataSource") - } - - var r0 fluxmonitorv2.ORM - if rf, ok := ret.Get(0).(func(sqlutil.DataSource) fluxmonitorv2.ORM); ok { - r0 = rf(_a0) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(fluxmonitorv2.ORM) - } - } - - return r0 -} - -// ORM_WithDataSource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithDataSource' -type ORM_WithDataSource_Call struct { - *mock.Call -} - -// WithDataSource is a helper method to define mock.On call -// - _a0 sqlutil.DataSource -func (_e *ORM_Expecter) WithDataSource(_a0 interface{}) *ORM_WithDataSource_Call { - return &ORM_WithDataSource_Call{Call: _e.mock.On("WithDataSource", _a0)} -} - -func (_c *ORM_WithDataSource_Call) Run(run func(_a0 sqlutil.DataSource)) *ORM_WithDataSource_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(sqlutil.DataSource)) - }) - return _c -} - -func (_c *ORM_WithDataSource_Call) Return(_a0 fluxmonitorv2.ORM) *ORM_WithDataSource_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ORM_WithDataSource_Call) RunAndReturn(run func(sqlutil.DataSource) fluxmonitorv2.ORM) *ORM_WithDataSource_Call { - _c.Call.Return(run) - return _c -} - -// NewORM creates a new instance of ORM. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewORM(t interface { - mock.TestingT - Cleanup(func()) -}) *ORM { - mock := &ORM{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/fluxmonitorv2/models.go b/core/services/fluxmonitorv2/models.go deleted file mode 100644 index 9cb572a327b..00000000000 --- a/core/services/fluxmonitorv2/models.go +++ /dev/null @@ -1,17 +0,0 @@ -package fluxmonitorv2 - -import ( - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/v2/core/null" -) - -// FluxMonitorRoundStatsV2 defines the stats for a round -type FluxMonitorRoundStatsV2 struct { - ID uint64 - PipelineRunID null.Int64 - Aggregator common.Address - RoundID uint32 - NumNewRoundLogs uint64 - NumSubmissions uint64 -} diff --git a/core/services/fluxmonitorv2/orm.go b/core/services/fluxmonitorv2/orm.go deleted file mode 100644 index 6056918bb1b..00000000000 --- a/core/services/fluxmonitorv2/orm.go +++ /dev/null @@ -1,131 +0,0 @@ -package fluxmonitorv2 - -import ( - "context" - "database/sql" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-evm/pkg/txmgr" - "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -type transmitter interface { - CreateTransaction(ctx context.Context, txRequest txmgr.TxRequest) (tx txmgr.Tx, err error) -} - -// ORM defines an interface for database commands related to Flux Monitor v2 -type ORM interface { - MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) - DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error - FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (FluxMonitorRoundStatsV2, error) - UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error - CreateEthTransaction(ctx context.Context, fromAddress, toAddress common.Address, payload []byte, gasLimit uint64, idempotencyKey *string) error - CountFluxMonitorRoundStats(ctx context.Context) (count int, err error) - - WithDataSource(sqlutil.DataSource) ORM -} - -type orm struct { - ds sqlutil.DataSource - txm transmitter - strategy types.TxStrategy - checker txmgr.TransmitCheckerSpec - logger logger.Logger -} - -func (o *orm) WithDataSource(ds sqlutil.DataSource) ORM { return o.withDataSource(ds) } - -func (o *orm) withDataSource(ds sqlutil.DataSource) *orm { - return &orm{ds, o.txm, o.strategy, o.checker, o.logger} -} - -// NewORM initializes a new ORM -func NewORM(ds sqlutil.DataSource, lggr logger.Logger, txm transmitter, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec) ORM { - namedLogger := lggr.Named("FluxMonitorORM") - return &orm{ds, txm, strategy, checker, namedLogger} -} - -// MostRecentFluxMonitorRoundID finds roundID of the most recent round that the -// provided oracle address submitted to -func (o *orm) MostRecentFluxMonitorRoundID(ctx context.Context, aggregator common.Address) (uint32, error) { - var stats FluxMonitorRoundStatsV2 - err := o.ds.GetContext(ctx, &stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator = $1 ORDER BY round_id DESC LIMIT 1`, aggregator) - return stats.RoundID, errors.Wrap(err, "MostRecentFluxMonitorRoundID failed") -} - -// DeleteFluxMonitorRoundsBackThrough deletes all the RoundStat records for a -// given oracle address starting from the most recent round back through the -// given round -func (o *orm) DeleteFluxMonitorRoundsBackThrough(ctx context.Context, aggregator common.Address, roundID uint32) error { - _, err := o.ds.ExecContext(ctx, ` - DELETE FROM flux_monitor_round_stats_v2 - WHERE aggregator = $1 - AND round_id >= $2 - `, aggregator, roundID) - return errors.Wrap(err, "DeleteFluxMonitorRoundsBackThrough failed") -} - -// FindOrCreateFluxMonitorRoundStats find the round stats record for a given -// oracle on a given round, or creates it if no record exists -func (o *orm) FindOrCreateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, newRoundLogs uint) (stats FluxMonitorRoundStatsV2, err error) { - err = sqlutil.Transact(ctx, o.withDataSource, o.ds, nil, func(tx *orm) error { - err = tx.ds.GetContext(ctx, &stats, - `INSERT INTO flux_monitor_round_stats_v2 (aggregator, round_id, num_new_round_logs, num_submissions) VALUES ($1, $2, $3, 0) - ON CONFLICT (aggregator, round_id) DO NOTHING`, - aggregator, roundID, newRoundLogs) - if errors.Is(err, sql.ErrNoRows) { - err = tx.ds.GetContext(ctx, &stats, `SELECT * FROM flux_monitor_round_stats_v2 WHERE aggregator=$1 AND round_id=$2`, aggregator, roundID) - } - return err - }) - - return stats, errors.Wrap(err, "FindOrCreateFluxMonitorRoundStats failed") -} - -// UpdateFluxMonitorRoundStats trys to create a RoundStat record for the given oracle -// at the given round. If one already exists, it increments the num_submissions column. -func (o *orm) UpdateFluxMonitorRoundStats(ctx context.Context, aggregator common.Address, roundID uint32, runID int64, newRoundLogsAddition uint) error { - _, err := o.ds.ExecContext(ctx, ` - INSERT INTO flux_monitor_round_stats_v2 ( - aggregator, round_id, pipeline_run_id, num_new_round_logs, num_submissions - ) VALUES ( - $1, $2, $3, $4, 1 - ) ON CONFLICT (aggregator, round_id) - DO UPDATE SET - num_new_round_logs = flux_monitor_round_stats_v2.num_new_round_logs + $5, - num_submissions = flux_monitor_round_stats_v2.num_submissions + 1, - pipeline_run_id = EXCLUDED.pipeline_run_id - `, aggregator, roundID, runID, newRoundLogsAddition, newRoundLogsAddition) - return errors.Wrapf(err, "Failed to insert round stats for roundID=%v, runID=%v, newRoundLogsAddition=%v", roundID, runID, newRoundLogsAddition) -} - -// CountFluxMonitorRoundStats counts the total number of records -func (o *orm) CountFluxMonitorRoundStats(ctx context.Context) (count int, err error) { - err = o.ds.GetContext(ctx, &count, `SELECT count(*) FROM flux_monitor_round_stats_v2`) - return count, errors.Wrap(err, "CountFluxMonitorRoundStats failed") -} - -// CreateEthTransaction creates an ethereum transaction for the Txm to pick up -func (o *orm) CreateEthTransaction( - ctx context.Context, - fromAddress common.Address, - toAddress common.Address, - payload []byte, - gasLimit uint64, - idempotencyKey *string, -) (err error) { - _, err = o.txm.CreateTransaction(ctx, txmgr.TxRequest{ - IdempotencyKey: idempotencyKey, - FromAddress: fromAddress, - ToAddress: toAddress, - EncodedPayload: payload, - FeeLimit: gasLimit, - Strategy: o.strategy, - Checker: o.checker, - }) - return errors.Wrap(err, "Skipped Flux Monitor submission") -} diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go deleted file mode 100644 index e199b1c4d35..00000000000 --- a/core/services/fluxmonitorv2/orm_test.go +++ /dev/null @@ -1,200 +0,0 @@ -package fluxmonitorv2_test - -import ( - "testing" - "time" - - "github.com/google/uuid" - "gopkg.in/guregu/null.v4" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" - - "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-evm/pkg/txmgr" - txmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/mocks" - commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" - "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" -) - -func TestORM_MostRecentFluxMonitorRoundID(t *testing.T) { - t.Parallel() - ctx := t.Context() - - db := pgtest.NewSqlxDB(t) - orm := newORM(t, db, nil) - - address := testutils.NewAddress() - - // Setup the rounds - for round := range uint32(10) { - _, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, round, 1) - require.NoError(t, err) - } - - count, err := orm.CountFluxMonitorRoundStats(ctx) - require.NoError(t, err) - require.Equal(t, 10, count) - - // Ensure round stats are not created again for the same address/roundID - stats, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, uint32(0), 1) - require.NoError(t, err) - require.Equal(t, uint32(0), stats.RoundID) - require.Equal(t, address, stats.Aggregator) - require.Equal(t, uint64(1), stats.NumNewRoundLogs) - - count, err = orm.CountFluxMonitorRoundStats(ctx) - require.NoError(t, err) - require.Equal(t, 10, count) - - roundID, err := orm.MostRecentFluxMonitorRoundID(ctx, testutils.NewAddress()) - require.Error(t, err) - require.Equal(t, uint32(0), roundID) - - roundID, err = orm.MostRecentFluxMonitorRoundID(ctx, address) - require.NoError(t, err) - require.Equal(t, uint32(9), roundID) - - // Deleting rounds against a new address should incur no changes - err = orm.DeleteFluxMonitorRoundsBackThrough(ctx, testutils.NewAddress(), 5) - require.NoError(t, err) - - count, err = orm.CountFluxMonitorRoundStats(ctx) - require.NoError(t, err) - require.Equal(t, 10, count) - - // Deleting rounds against the address - err = orm.DeleteFluxMonitorRoundsBackThrough(ctx, address, 5) - require.NoError(t, err) - - count, err = orm.CountFluxMonitorRoundStats(ctx) - require.NoError(t, err) - require.Equal(t, 5, count) -} - -func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { - t.Parallel() - ctx := t.Context() - - cfg := configtest.NewGeneralConfig(t, nil) - db := pgtest.NewSqlxDB(t) - - keyStore := cltest.NewKeyStore(t, db) - lggr := logger.TestLogger(t) - - // Instantiate a real pipeline ORM because we need to create a pipeline run - // for the foreign key constraint of the stats record - pipelineORM := pipeline.NewORM(db, lggr, cfg.JobPipeline().MaxSuccessfulRuns()) - bridgeORM := bridges.NewORM(db) - - // Instantiate a real job ORM because we need to create a job to satisfy - // a check in pipeline.CreateRun - jobORM := job.NewORM(db, pipelineORM, bridgeORM, keyStore, lggr) - orm := newORM(t, db, nil) - - address := testutils.NewAddress() - var roundID uint32 = 1 - - jb := makeJob(t) - require.NoError(t, jobORM.CreateJob(ctx, jb)) - - for expectedCount := uint64(1); expectedCount < 4; expectedCount++ { - f := time.Now() - run := - &pipeline.Run{ - State: pipeline.RunStatusCompleted, - PipelineSpecID: jb.PipelineSpec.ID, - PruningKey: jb.ID, - PipelineSpec: *jb.PipelineSpec, - CreatedAt: time.Now(), - FinishedAt: null.TimeFrom(f), - AllErrors: pipeline.RunErrors{null.String{}}, - FatalErrors: pipeline.RunErrors{null.String{}}, - Outputs: jsonserializable.JSONSerializable{Val: []any{10}, Valid: true}, - PipelineTaskRuns: []pipeline.TaskRun{ - { - ID: uuid.New(), - Type: pipeline.TaskTypeHTTP, - Output: jsonserializable.JSONSerializable{Val: 10, Valid: true}, - CreatedAt: f, - FinishedAt: null.TimeFrom(f), - }, - }, - } - err := pipelineORM.InsertFinishedRun(ctx, run, true) - require.NoError(t, err) - - err = orm.UpdateFluxMonitorRoundStats(ctx, address, roundID, run.ID, 0) - require.NoError(t, err) - - stats, err := orm.FindOrCreateFluxMonitorRoundStats(ctx, address, roundID, 0) - require.NoError(t, err) - require.Equal(t, expectedCount, stats.NumSubmissions) - require.True(t, stats.PipelineRunID.Valid) - require.Equal(t, run.ID, stats.PipelineRunID.Int64) - } -} - -func makeJob(t *testing.T) *job.Job { - t.Helper() - - return &job.Job{ - ID: 1, - Type: "fluxmonitor", - SchemaVersion: 1, - ExternalJobID: uuid.New(), - FluxMonitorSpec: &job.FluxMonitorSpec{ - ID: 2, - ContractAddress: cltest.NewEIP55Address(), - Threshold: 0.5, - PollTimerPeriod: 1 * time.Second, - PollTimerDisabled: false, - IdleTimerPeriod: 1 * time.Minute, - IdleTimerDisabled: false, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - EVMChainID: (*sqlutil.Big)(testutils.FixtureChainID), - }, - } -} - -func TestORM_CreateEthTransaction(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - strategy := commontxmmocks.NewTxStrategy(t) - - var ( - txm = txmmocks.NewMockEvmTxManager(t) - orm = fluxmonitorv2.NewORM(db, logger.TestLogger(t), txm, strategy, txmgr.TransmitCheckerSpec{}) - - _, from = cltest.MustInsertRandomKey(t, ethKeyStore) - to = testutils.NewAddress() - payload = []byte{1, 0, 0} - gasLimit = uint64(21000) - ) - idempotencyKey := uuid.New().String() - txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{ - IdempotencyKey: &idempotencyKey, - FromAddress: from, - ToAddress: to, - EncodedPayload: payload, - FeeLimit: gasLimit, - Meta: nil, - Strategy: strategy, - }).Return(txmgr.Tx{}, nil).Once() - - require.NoError(t, orm.CreateEthTransaction(testutils.Context(t), from, to, payload, gasLimit, &idempotencyKey)) -} diff --git a/core/services/fluxmonitorv2/payment_checker.go b/core/services/fluxmonitorv2/payment_checker.go deleted file mode 100644 index e4cc40c96a3..00000000000 --- a/core/services/fluxmonitorv2/payment_checker.go +++ /dev/null @@ -1,50 +0,0 @@ -package fluxmonitorv2 - -import ( - "math/big" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" -) - -// MinFundedRounds defines the minimum number of rounds that needs to be paid -// to oracles on a contract -const MinFundedRounds int64 = 3 - -// PaymentChecker provides helper functions to check whether payments are valid -type PaymentChecker struct { - // The minimum amount for a payment set in the ENV Var - MinContractPayment *assets.Link - // The minimum amount for a payment set in the job - MinJobPayment *assets.Link -} - -// NewPaymentChecker constructs a new payment checker -func NewPaymentChecker(minContractPayment, minJobPayment *assets.Link) *PaymentChecker { - return &PaymentChecker{ - MinContractPayment: minContractPayment, - MinJobPayment: minJobPayment, - } -} - -// SufficientFunds checks if the contract has sufficient funding to pay all the -// oracles on a contract for a minimum number of rounds, based on the payment -// amount in the contract -func (c *PaymentChecker) SufficientFunds(availableFunds *big.Int, paymentAmount *big.Int, oracleCount uint8) bool { - min := big.NewInt(int64(oracleCount)) - min = min.Mul(min, big.NewInt(MinFundedRounds)) - min = min.Mul(min, paymentAmount) - - return availableFunds.Cmp(min) >= 0 -} - -// SufficientPayment checks if the available payment is enough to submit an -// answer. It compares the payment amount on chain with the min payment amount -// listed in the job / ENV var. -func (c *PaymentChecker) SufficientPayment(payment *big.Int) bool { - aboveOrEqMinGlobalPayment := payment.Cmp(c.MinContractPayment.ToInt()) >= 0 - aboveOrEqMinJobPayment := true - if c.MinJobPayment != nil { - aboveOrEqMinJobPayment = payment.Cmp(c.MinJobPayment.ToInt()) >= 0 - } - return aboveOrEqMinGlobalPayment && aboveOrEqMinJobPayment -} diff --git a/core/services/fluxmonitorv2/payment_checker_test.go b/core/services/fluxmonitorv2/payment_checker_test.go deleted file mode 100644 index 089ebcc4004..00000000000 --- a/core/services/fluxmonitorv2/payment_checker_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package fluxmonitorv2_test - -import ( - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -func TestPaymentChecker_SufficientFunds(t *testing.T) { - t.Parallel() - var ( - checker = fluxmonitorv2.NewPaymentChecker(nil, nil) - payment = 100 - rounds = 3 - oracleCount = 21 - min = payment * rounds * oracleCount - ) - - testCases := []struct { - name string - funds int - want bool - }{ - {"above minimum", min + 1, true}, - {"equal to minimum", min, true}, - {"below minimum", min - 1, false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - assert.Equal(t, tc.want, checker.SufficientFunds( - big.NewInt(int64(tc.funds)), - big.NewInt(int64(payment)), - uint8(oracleCount), - )) - }) - } -} - -func TestPaymentChecker_SufficientPayment(t *testing.T) { - t.Parallel() - var ( - payment int64 = 10 - eq = payment - gt = payment + 1 - lt = payment - 1 - ) - - testCases := []struct { - name string - minContractPayment int64 - minJobPayment any // nil or int64 - want bool - }{ - {"payment above min contract payment, no min job payment", lt, nil, true}, - {"payment equal to min contract payment, no min job payment", eq, nil, true}, - {"payment below min contract payment, no min job payment", gt, nil, false}, - - {"payment above min contract payment, above min job payment", lt, lt, true}, - {"payment equal to min contract payment, above min job payment", eq, lt, true}, - {"payment below min contract payment, above min job payment", gt, lt, false}, - - {"payment above min contract payment, equal to min job payment", lt, eq, true}, - {"payment equal to min contract payment, equal to min job payment", eq, eq, true}, - {"payment below min contract payment, equal to min job payment", gt, eq, false}, - - {"payment above minimum contract payment, below min job payment", lt, gt, false}, - {"payment equal to minimum contract payment, below min job payment", eq, gt, false}, - {"payment below minimum contract payment, below min job payment", gt, gt, false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - var minJobPayment *assets.Link - if tc.minJobPayment != nil { - mjb := assets.Link(*big.NewInt(tc.minJobPayment.(int64))) - minJobPayment = &mjb - } - - checker := fluxmonitorv2.NewPaymentChecker(assets.NewLinkFromJuels(tc.minContractPayment), minJobPayment) - - assert.Equal(t, tc.want, checker.SufficientPayment(big.NewInt(payment))) - }) - } -} diff --git a/core/services/fluxmonitorv2/poll_manager.go b/core/services/fluxmonitorv2/poll_manager.go deleted file mode 100644 index 38805651e47..00000000000 --- a/core/services/fluxmonitorv2/poll_manager.go +++ /dev/null @@ -1,348 +0,0 @@ -package fluxmonitorv2 - -import ( - "fmt" - "sync/atomic" - "time" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type PollManagerConfig struct { - IsHibernating bool - PollTickerInterval time.Duration - PollTickerDisabled bool - IdleTimerPeriod time.Duration - IdleTimerDisabled bool - DrumbeatSchedule string - DrumbeatEnabled bool - DrumbeatRandomDelay time.Duration - HibernationPollPeriod time.Duration - MinRetryBackoffDuration time.Duration - MaxRetryBackoffDuration time.Duration -} - -// PollManager manages the tickers/timers which cause the Flux Monitor to start -// a poll. It contains 4 types of tickers and timers which determine when to -// initiate a poll -// -// HibernationTimer - The PollManager can be set to hibernate, which disables all -// other ticker/timers, and enables the hibernation timer. Upon expiry of the -// hibernation timer, a poll is requested. When the PollManager is awakened, the -// other tickers and timers are enabled with the current round state, and the -// hibernation timer is disabled. -// -// PollTicker - The poll ticker requests a poll at a given interval defined in -// PollManagerConfig. Disabling this through config will permanently disable -// the ticker, even through a resets. -// -// IdleTimer - The idle timer requests a poll after no poll has taken place -// since the last round was start and the IdleTimerPeriod has elapsed. This can -// also be known as a heartbeat. -// -// RoundTimer - The round timer requests a poll when the round state provided by -// the contract has timed out. -// -// RetryTicker - The retry ticker requests a poll with a backoff duration. This -// is started when the idle timer fails, and will poll with a maximum backoff -// of either 1 hour or the idle timer period if it is lower -type PollManager struct { - cfg PollManagerConfig - - isHibernating atomic.Bool - hibernationTimer utils.ResettableTimer - pollTicker utils.PausableTicker - idleTimer utils.ResettableTimer - roundTimer utils.ResettableTimer - retryTicker utils.BackoffTicker - drumbeat utils.CronTicker - chPoll chan PollRequest - - logger logger.Logger -} - -// NewPollManager initializes a new PollManager -func NewPollManager(cfg PollManagerConfig, lggr logger.Logger) (*PollManager, error) { - minBackoffDuration := min(cfg.IdleTimerPeriod, cfg.MinRetryBackoffDuration) - maxBackoffDuration := min(cfg.IdleTimerPeriod, cfg.MaxRetryBackoffDuration) - // Always initialize the idle timer so that no matter what it has a ticker - // and won't get starved by an old startedAt timestamp from the oracle state on boot. - var idleTimer = utils.NewResettableTimer() - if !cfg.IdleTimerDisabled { - idleTimer.Reset(cfg.IdleTimerPeriod) - } - - p := &PollManager{ - cfg: cfg, - logger: logger.Named(lggr, "PollManager"), - - hibernationTimer: utils.NewResettableTimer(), - pollTicker: utils.NewPausableTicker(cfg.PollTickerInterval), - idleTimer: idleTimer, - roundTimer: utils.NewResettableTimer(), - retryTicker: utils.NewBackoffTicker(minBackoffDuration, maxBackoffDuration), - chPoll: make(chan PollRequest), - } - var err error - if cfg.DrumbeatEnabled { - p.drumbeat, err = utils.NewCronTicker(cfg.DrumbeatSchedule) - if err != nil { - return nil, err - } - } - p.isHibernating.Store(cfg.IsHibernating) - return p, nil -} - -// PollTickerTicks ticks on a given interval -func (pm *PollManager) PollTickerTicks() <-chan time.Time { - return pm.pollTicker.Ticks() -} - -// IdleTimerTicks ticks after a given period -func (pm *PollManager) IdleTimerTicks() <-chan time.Time { - return pm.idleTimer.Ticks() -} - -// HibernationTimerTicks ticks after a given period -func (pm *PollManager) HibernationTimerTicks() <-chan time.Time { - return pm.hibernationTimer.Ticks() -} - -// RoundTimerTicks ticks after a given period -func (pm *PollManager) RoundTimerTicks() <-chan time.Time { - return pm.roundTimer.Ticks() -} - -// RetryTickerTicks ticks with a backoff when the retry ticker is activated -func (pm *PollManager) RetryTickerTicks() <-chan time.Time { - return pm.retryTicker.Ticks() -} - -// DrumbeatTicks ticks on a cron schedule when the drumbeat ticker is activated -func (pm *PollManager) DrumbeatTicks() <-chan time.Time { - return pm.drumbeat.Ticks() -} - -// Poll returns a channel which the manager will use to send polling requests -// -// Note: In the future, we should change the tickers above to send their request -// through this channel to simplify the listener. -func (pm *PollManager) Poll() <-chan PollRequest { - return pm.chPoll -} - -// Start initializes all the timers and determines whether to go into immediate -// hibernation. -func (pm *PollManager) Start(hibernate bool, roundState flux_aggregator_wrapper.OracleRoundState) { - pm.isHibernating.Store(hibernate) - - if pm.ShouldPerformInitialPoll() { - // We want this to be non blocking but if there is no received for the - // polling channel, this go routine would hang around forever. Since we - // should always have a receiver for the polling channel, set a timeout - // of 5 seconds to kill the goroutine. - go func() { - select { - case pm.chPoll <- PollRequest{PollRequestTypeInitial, time.Now()}: - case <-time.After(5 * time.Second): - pm.logger.Warn("Start up poll was not consumed") - } - }() - } - - pm.maybeWarnAboutIdleAndPollIntervals() - - if hibernate { - pm.Hibernate() - } else { - pm.Awaken(roundState) - } -} - -// ShouldPerformInitialPoll determines whether to perform an initial poll -func (pm *PollManager) ShouldPerformInitialPoll() bool { - return (!pm.cfg.PollTickerDisabled || !pm.cfg.IdleTimerDisabled) && !pm.isHibernating.Load() -} - -// Reset resets the timers except for the hibernation timer. Will not reset if -// hibernating. -func (pm *PollManager) Reset(roundState flux_aggregator_wrapper.OracleRoundState) { - if pm.isHibernating.Load() { - pm.hibernationTimer.Reset(pm.cfg.HibernationPollPeriod) - } else { - pm.startPollTicker() - pm.startIdleTimer(roundState.StartedAt) - pm.startRoundTimer(roundStateTimesOutAt(roundState)) - pm.startDrumbeat() - } -} - -// ResetIdleTimer resets the idle timer unless hibernating -func (pm *PollManager) ResetIdleTimer(roundStartedAtUTC uint64) { - if !pm.isHibernating.Load() { - pm.startIdleTimer(roundStartedAtUTC) - } -} - -// StartRetryTicker starts the retry ticker -func (pm *PollManager) StartRetryTicker() bool { - return pm.retryTicker.Start() -} - -// StopRetryTicker stops the retry ticker -func (pm *PollManager) StopRetryTicker() { - if pm.retryTicker.Stop() { - pm.logger.Debug("stopped retry ticker") - } -} - -// Stop stops all timers/tickers -func (pm *PollManager) Stop() { - pm.hibernationTimer.Stop() - pm.pollTicker.Destroy() - pm.idleTimer.Stop() - pm.roundTimer.Stop() - pm.drumbeat.Stop() -} - -// Hibernate sets hibernation to true, starts the hibernation timer and stops -// all other ticker/timers -func (pm *PollManager) Hibernate() { - pm.logger.Infof("entering hibernation mode (period: %v)", pm.cfg.HibernationPollPeriod) - - // Start the hibernation timer - pm.isHibernating.Store(true) - pm.hibernationTimer.Reset(pm.cfg.HibernationPollPeriod) - - // Stop the other tickers - pm.pollTicker.Pause() - pm.idleTimer.Stop() - pm.roundTimer.Stop() - pm.drumbeat.Stop() - pm.StopRetryTicker() -} - -// Awaken sets hibernation to false, stops the hibernation timer and starts all -// other tickers -func (pm *PollManager) Awaken(roundState flux_aggregator_wrapper.OracleRoundState) { - pm.logger.Info("exiting hibernation mode, reactivating contract") - - // Stop the hibernation timer - pm.isHibernating.Store(false) - pm.hibernationTimer.Stop() - - // Start the other tickers - pm.startPollTicker() - pm.startIdleTimer(roundState.StartedAt) - pm.startRoundTimer(roundStateTimesOutAt(roundState)) - pm.startDrumbeat() -} - -// startPollTicker starts the poll ticker if it is enabled -func (pm *PollManager) startPollTicker() { - if pm.cfg.PollTickerDisabled { - pm.pollTicker.Pause() - - return - } - - pm.pollTicker.Resume() -} - -// startIdleTimer starts the idle timer if it is enabled -func (pm *PollManager) startIdleTimer(roundStartedAtUTC uint64) { - if pm.cfg.IdleTimerDisabled { - pm.idleTimer.Stop() - - return - } - - // Keep using the idleTimer we already have - if roundStartedAtUTC == 0 { - pm.logger.Debugw("not resetting idleTimer, no active round") - - return - } - - startedAt := time.Unix(int64(roundStartedAtUTC), 0) - deadline := startedAt.Add(pm.cfg.IdleTimerPeriod) - deadlineDuration := time.Until(deadline) - - log := logger.With(pm.logger, - "pollFrequency", pm.cfg.PollTickerInterval, - "idleDuration", pm.cfg.IdleTimerPeriod, - "startedAt", roundStartedAtUTC, - "timeUntilIdleDeadline", deadlineDuration, - ) - - if deadlineDuration <= 0 { - log.Debugw("not resetting idleTimer, round was started further in the past than idle timer period") - return - } - - // Stop the retry timer when the idle timer is started - if pm.retryTicker.Stop() { - pm.logger.Debugw("stopped the retryTicker") - } - - pm.idleTimer.Reset(deadlineDuration) - log.Debugw("resetting idleTimer") -} - -// startRoundTimer starts the round timer -func (pm *PollManager) startRoundTimer(roundTimesOutAt uint64) { - log := logger.With(pm.logger, - "pollFrequency", pm.cfg.PollTickerInterval, - "idleDuration", pm.cfg.IdleTimerPeriod, - "timesOutAt", roundTimesOutAt, - ) - - if roundTimesOutAt == 0 { - log.Debugw("disabling roundTimer, no active round") - pm.roundTimer.Stop() - - return - } - - timesOutAt := time.Unix(int64(roundTimesOutAt), 0) - timeoutDuration := time.Until(timesOutAt) - - if timeoutDuration <= 0 { - log.Debugw(fmt.Sprintf("disabling roundTimer, as the round is already past its timeout by %v", -timeoutDuration)) - pm.roundTimer.Stop() - - return - } - - pm.roundTimer.Reset(timeoutDuration) - log.Debugw("updating roundState.TimesOutAt", "value", roundTimesOutAt) -} - -// startDrumbeat starts the drumbeat ticker if it is enabled -func (pm *PollManager) startDrumbeat() { - if !pm.cfg.DrumbeatEnabled { - if pm.drumbeat.Stop() { - pm.logger.Debug("disabled drumbeat ticker") - } - return - } - - if pm.drumbeat.Start() { - pm.logger.Debugw("started drumbeat ticker", "schedule", pm.cfg.DrumbeatSchedule) - } -} - -func roundStateTimesOutAt(rs flux_aggregator_wrapper.OracleRoundState) uint64 { - return rs.StartedAt + rs.Timeout -} - -// ShouldPerformInitialPoll determines whether to perform an initial poll -func (pm *PollManager) maybeWarnAboutIdleAndPollIntervals() { - if !pm.cfg.IdleTimerDisabled && !pm.cfg.PollTickerDisabled && pm.cfg.IdleTimerPeriod < pm.cfg.PollTickerInterval { - pm.logger.Warnw("The value of IdleTimerPeriod is lower than PollTickerInterval. The idle timer should usually be less frequent that poll", - "IdleTimerPeriod", pm.cfg.IdleTimerPeriod, "PollTickerInterval", pm.cfg.PollTickerInterval) - } -} diff --git a/core/services/fluxmonitorv2/poll_manager_test.go b/core/services/fluxmonitorv2/poll_manager_test.go deleted file mode 100644 index dcf3527ee9e..00000000000 --- a/core/services/fluxmonitorv2/poll_manager_test.go +++ /dev/null @@ -1,467 +0,0 @@ -package fluxmonitorv2_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/flux_aggregator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -var ( - pollTickerDefaultDuration = 200 * time.Millisecond - idleTickerDefaultDuration = 1 * time.Second // Setting this too low will cause the idle timer to fire before the assert -) - -func newPollManager(t *testing.T) *fluxmonitorv2.PollManager { - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - IsHibernating: false, - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: false, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: false, - HibernationPollPeriod: 24 * time.Hour, - }, logger.TestLogger(t)) - require.NoError(t, err) - return pm -} - -type tickChecker struct { - pollTicked bool - idleTicked bool - roundTicked bool - hibernationTicked bool - retryTicked bool - initialPoll bool -} - -// watchTicks watches the PollManager for ticks for the waitDuration -func watchTicks(t *testing.T, pm *fluxmonitorv2.PollManager, waitDuration time.Duration) tickChecker { - ticks := tickChecker{ - pollTicked: false, - idleTicked: false, - roundTicked: false, - hibernationTicked: false, - retryTicked: false, - initialPoll: false, - } - - waitCh := time.After(waitDuration) - for { - select { - case <-pm.PollTickerTicks(): - ticks.pollTicked = true - case <-pm.IdleTimerTicks(): - ticks.idleTicked = true - case <-pm.RoundTimerTicks(): - ticks.roundTicked = true - case <-pm.HibernationTimerTicks(): - ticks.hibernationTicked = true - case <-pm.RetryTickerTicks(): - ticks.retryTicked = true - case request := <-pm.Poll(): - switch request.Type { - case fluxmonitorv2.PollRequestTypeInitial: - ticks.initialPoll = true - // Don't do anything with the other types for now - default: - } - - case <-waitCh: - waitCh = nil - } - - if waitCh == nil { - break - } - } - - return ticks -} - -func TestPollManager_PollTicker(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: false, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: true, - HibernationPollPeriod: 24 * time.Hour, - }, logger.TestLogger(t)) - require.NoError(t, err) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{}) - t.Cleanup(pm.Stop) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.True(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) -} - -func TestPollManager_IdleTimer(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: 100 * time.Millisecond, - PollTickerDisabled: true, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: false, - HibernationPollPeriod: 24 * time.Hour, - }, logger.TestLogger(t)) - require.NoError(t, err) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()) - 10, // Even 10 seconds old the idle timer should tick - }) - t.Cleanup(pm.Stop) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.False(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) -} - -func TestPollManager_RoundTimer(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: true, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: true, - HibernationPollPeriod: 24 * time.Hour, - }, logger.TestLogger(t)) - require.NoError(t, err) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - t.Cleanup(pm.Stop) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) -} - -func TestPollManager_RetryTimer(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: true, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: true, - HibernationPollPeriod: 24 * time.Hour, - MinRetryBackoffDuration: 200 * time.Microsecond, - MaxRetryBackoffDuration: 1 * time.Minute, - }, logger.TestLogger(t)) - require.NoError(t, err) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 10000, // in seconds. Don't timeout the round - }) - t.Cleanup(pm.Stop) - - pm.StartRetryTicker() - - // Retry ticker fires - ticks := watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) - assert.True(t, ticks.retryTicked) - - pm.StopRetryTicker() - - ticks = watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) - assert.False(t, ticks.retryTicked) -} - -func TestPollManager_InitialPoll(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{}) - - ticks := watchTicks(t, pm, 1*time.Second) - assert.True(t, ticks.initialPoll) -} - -func TestPollManager_HibernationTimer(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: true, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: true, - HibernationPollPeriod: 1 * time.Second, - }, logger.TestLogger(t)) - require.NoError(t, err) - - pm.Start(true, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - t.Cleanup(pm.Stop) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.True(t, ticks.hibernationTicked) -} - -func TestPollManager_HibernationOnStartThenAwaken(t *testing.T) { - t.Parallel() - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: false, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: false, - HibernationPollPeriod: 24 * time.Hour, - }, logger.TestLogger(t)) - require.NoError(t, err) - t.Cleanup(pm.Stop) - - pm.Start(true, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) - - pm.Awaken(flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - - ticks = watchTicks(t, pm, 2*time.Second) - - assert.True(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) -} - -func TestPollManager_AwakeOnStartThenHibernate(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - t.Cleanup(pm.Stop) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.True(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) - - pm.Hibernate() - - ticks = watchTicks(t, pm, 2*time.Second) - - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) -} - -func TestPollManager_ShouldPerformInitialPoll(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - pollTickerDisabled bool - idleTimerDisabled bool - isHibernating bool - want bool - }{ - { - name: "perform poll - all enabled", - pollTickerDisabled: false, - idleTimerDisabled: false, - isHibernating: false, - want: true, - }, - { - name: "don't perform poll - hibernating", - pollTickerDisabled: false, - idleTimerDisabled: false, - isHibernating: true, - want: false, - }, - { - name: "perform poll - only pollTickerDisabled", - pollTickerDisabled: true, - idleTimerDisabled: false, - isHibernating: false, - want: true, - }, - { - name: "perform poll - only idleTimerDisabled", - pollTickerDisabled: false, - idleTimerDisabled: true, - isHibernating: false, - want: true, - }, - { - name: "don't perform poll - idleTimerDisabled and pollTimerDisabled", - pollTickerDisabled: true, - idleTimerDisabled: true, - isHibernating: false, - want: false, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - pm, err := fluxmonitorv2.NewPollManager(fluxmonitorv2.PollManagerConfig{ - IsHibernating: tc.isHibernating, - HibernationPollPeriod: 24 * time.Hour, - PollTickerInterval: pollTickerDefaultDuration, - PollTickerDisabled: tc.pollTickerDisabled, - IdleTimerPeriod: idleTickerDefaultDuration, - IdleTimerDisabled: tc.idleTimerDisabled, - }, logger.TestLogger(t)) - require.NoError(t, err) - - assert.Equal(t, tc.want, pm.ShouldPerformInitialPoll()) - }) - } -} - -func TestPollManager_Stop(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - - ticks := watchTicks(t, pm, 2*time.Second) - - assert.True(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) - - pm.Stop() - - ticks = watchTicks(t, pm, 2*time.Second) - - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) -} - -func TestPollManager_ResetIdleTimer(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - // Start again in awake mode - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - t.Cleanup(pm.Stop) - - // Idle timer fires when not hibernating - ticks := watchTicks(t, pm, 2*time.Second) - assert.True(t, ticks.idleTicked) - - // Idle timer fires again after reset - pm.ResetIdleTimer(uint64(time.Now().Unix()) + 1) // 1 second after now - ticks = watchTicks(t, pm, 2*time.Second) - assert.True(t, ticks.idleTicked) -} - -func TestPollManager_ResetIdleTimerWhenHibernating(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - // Start in hibernation - pm.Start(true, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - t.Cleanup(pm.Stop) - - // Idle timer does not fire when hibernating - ticks := watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.idleTicked) - - // Idle timer does not reset because in hibernation, so it does not fire - pm.ResetIdleTimer(uint64(time.Now().Unix())) - ticks = watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.idleTicked) -} - -func TestPollManager_Reset(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - // Start again in awake mode - pm.Start(false, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - t.Cleanup(pm.Stop) - - // Ticker/timers fires when not hibernating - ticks := watchTicks(t, pm, 2*time.Second) - assert.True(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) - - // Idle timer fires again after reset - pm.Reset(flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, - }) - ticks = watchTicks(t, pm, 2*time.Second) - assert.True(t, ticks.pollTicked) - assert.True(t, ticks.idleTicked) - assert.True(t, ticks.roundTicked) -} - -func TestPollManager_ResetWhenHibernating(t *testing.T) { - t.Parallel() - pm := newPollManager(t) - - // Start in hibernation - pm.Start(true, flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - t.Cleanup(pm.Stop) - - // Ticker/timers do not fire when hibernating - ticks := watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) - - // Ticker/timers does not reset because in hibernation, so they do not fire - pm.Reset(flux_aggregator_wrapper.OracleRoundState{ - StartedAt: uint64(time.Now().Unix()), - Timeout: 1, // in seconds - }) - ticks = watchTicks(t, pm, 2*time.Second) - assert.False(t, ticks.pollTicked) - assert.False(t, ticks.idleTicked) - assert.False(t, ticks.roundTicked) -} diff --git a/core/services/fluxmonitorv2/promfm/prometheus.go b/core/services/fluxmonitorv2/promfm/prometheus.go deleted file mode 100644 index d7d9db83158..00000000000 --- a/core/services/fluxmonitorv2/promfm/prometheus.go +++ /dev/null @@ -1,59 +0,0 @@ -package promfm - -import ( - "math/big" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/shopspring/decimal" -) - -var ( - ReportedValue = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "flux_monitor_reported_value", - Help: "Flux monitor's last reported price", - }, - []string{"job_spec_id"}, - ) - - SeenValue = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "flux_monitor_seen_value", - Help: "Flux monitor's last observed value from target", - }, - []string{"job_spec_id"}, - ) - - ReportedRound = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "flux_monitor_reported_round", - Help: "Flux monitor's last reported round", - }, - []string{"job_spec_id"}, - ) - - SeenRound = promauto.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "flux_monitor_seen_round", - Help: "Last seen round by other node operators", - }, - []string{"job_spec_id"}, - ) -) - -// SetDecimal sets a decimal metric -func SetDecimal(gauge prometheus.Gauge, arg decimal.Decimal) { - val, _ := arg.Float64() - gauge.Set(val) -} - -// SetBigInt sets a big.Int metric -func SetBigInt(gauge prometheus.Gauge, arg *big.Int) { - gauge.Set(float64(arg.Int64())) -} - -// SetUint32 sets a uint32 metric -func SetUint32(gauge prometheus.Gauge, arg uint32) { - gauge.Set(float64(arg)) -} diff --git a/core/services/fluxmonitorv2/submission_checker.go b/core/services/fluxmonitorv2/submission_checker.go deleted file mode 100644 index b26e70ac7b5..00000000000 --- a/core/services/fluxmonitorv2/submission_checker.go +++ /dev/null @@ -1,26 +0,0 @@ -package fluxmonitorv2 - -import ( - "math/big" - - "github.com/shopspring/decimal" -) - -// SubmissionChecker checks whether an answer is inside the allowable range. -type SubmissionChecker struct { - Min decimal.Decimal - Max decimal.Decimal -} - -// NewSubmissionChecker initializes a new SubmissionChecker -func NewSubmissionChecker(min *big.Int, max *big.Int) *SubmissionChecker { - return &SubmissionChecker{ - Min: decimal.NewFromBigInt(min, 0), - Max: decimal.NewFromBigInt(max, 0), - } -} - -// IsValid checks if the submission is between the min and max -func (c *SubmissionChecker) IsValid(answer decimal.Decimal) bool { - return answer.GreaterThanOrEqual(c.Min) && answer.LessThanOrEqual(c.Max) -} diff --git a/core/services/fluxmonitorv2/submission_checker_test.go b/core/services/fluxmonitorv2/submission_checker_test.go deleted file mode 100644 index 4417a043ba9..00000000000 --- a/core/services/fluxmonitorv2/submission_checker_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package fluxmonitorv2_test - -import ( - "math/big" - "testing" - - "github.com/shopspring/decimal" - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" -) - -func TestSubmissionChecker_IsValid(t *testing.T) { - t.Parallel() - testCases := []struct { - name string - answer decimal.Decimal - want bool - }{ - { - name: "equal to min", - answer: decimal.NewFromFloat(1), - want: true, - }, - { - name: "in between", - answer: decimal.NewFromFloat(2), - want: true, - }, - { - name: "equal to max", - answer: decimal.NewFromFloat(3), - want: true, - }, - { - name: "below min", - answer: decimal.NewFromFloat(0), - want: false, - }, - { - name: "over max", - answer: decimal.NewFromFloat(4), - want: false, - }, - } - - checker := fluxmonitorv2.NewSubmissionChecker( - big.NewInt(1), - big.NewInt(3), - ) - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - assert.Equal(t, tc.want, checker.IsValid(tc.answer)) - }) - } -} diff --git a/core/services/fluxmonitorv2/validate.go b/core/services/fluxmonitorv2/validate.go deleted file mode 100644 index fc531fc7cb4..00000000000 --- a/core/services/fluxmonitorv2/validate.go +++ /dev/null @@ -1,90 +0,0 @@ -package fluxmonitorv2 - -import ( - "time" - - "github.com/google/uuid" - - "github.com/pelletier/go-toml" - "github.com/pkg/errors" - - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type ValidationConfig interface { - DefaultHTTPTimeout() commonconfig.Duration -} - -func ValidatedFluxMonitorSpec(config ValidationConfig, ts string) (job.Job, error) { - var jb = job.Job{ - ExternalJobID: uuid.New(), // Default to generating a uuid, can be overwritten by the specified one in tomlString. - } - var spec job.FluxMonitorSpec - tree, err := toml.Load(ts) - if err != nil { - return jb, err - } - err = tree.Unmarshal(&jb) - if err != nil { - return jb, err - } - err = tree.Unmarshal(&spec) - if err != nil { - return jb, err - } - jb.FluxMonitorSpec = &spec - - if jb.Type != job.FluxMonitor { - return jb, errors.Errorf("unsupported type %s", jb.Type) - } - - // Find the smallest of all the timeouts - // and ensure the polling period is greater than that. - minTaskTimeout, aTimeoutSet, err := jb.Pipeline.MinTimeout() - if err != nil { - return jb, err - } - timeouts := []time.Duration{ - config.DefaultHTTPTimeout().Duration(), - time.Duration(jb.MaxTaskDuration), - } - if aTimeoutSet { - timeouts = append(timeouts, minTaskTimeout) - } - var minTimeout time.Duration = 1<<63 - 1 - for _, timeout := range timeouts { - if timeout < minTimeout { - minTimeout = timeout - } - } - - if jb.FluxMonitorSpec.DrumbeatEnabled { - err := utils.ValidateCronSchedule(jb.FluxMonitorSpec.DrumbeatSchedule) - if err != nil { - return jb, errors.Wrap(err, "while validating drumbeat schedule") - } - - if !spec.IdleTimerDisabled { - return jb, errors.Errorf("When the drumbeat ticker is enabled, the idle timer must be disabled. Please set IdleTimerDisabled to true") - } - } - - if !validatePollTimer(jb.FluxMonitorSpec.PollTimerDisabled, minTimeout, jb.FluxMonitorSpec.PollTimerPeriod) { - return jb, errors.Errorf("PollTimerPeriod (%v) must be equal or greater than the smallest value of MaxTaskDuration param, JobPipeline.HTTPRequest.DefaultTimeout config var, or MinTimeout of all tasks (%v)", jb.FluxMonitorSpec.PollTimerPeriod, minTimeout) - } - - return jb, nil -} - -// validatePollTime validates the period is greater than the min timeout for an -// enabled poll timer. -func validatePollTimer(disabled bool, minTimeout time.Duration, period time.Duration) bool { - // Disabled timers do not need to validate the period - if disabled { - return true - } - - return period >= minTimeout -} diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go deleted file mode 100644 index c3131592620..00000000000 --- a/core/services/fluxmonitorv2/validate_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package fluxmonitorv2 - -import ( - "testing" - "time" - - "github.com/smartcontractkit/quarantine" - - "github.com/smartcontractkit/chainlink-common/pkg/assets" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type testcfg struct{} - -func (testcfg) DefaultHTTPTimeout() commonconfig.Duration { - return *commonconfig.MustNewDuration(2 * time.Second) -} - -func TestValidate(t *testing.T) { - quarantine.Flaky(t, "DX-1852") - t.Parallel() - var tt = []struct { - name string - toml string - config ValidationConfig - assertion func(t *testing.T, os job.Job, err error) - }{ - { - name: "valid spec", - toml: ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerDisabled = true - -pollTimerPeriod = "1m" -pollTimerDisabled = false - -drumbeatEnabled = true -drumbeatSchedule = "@every 1m" -drumbeatRandomDelay = "10s" - -minPayment = 1000000000000000000 - -observationSource = """ -// data source 1 -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds1_parse [type=jsonparse path="latest"]; - -// data source 2 -ds2 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds2_parse [type=jsonparse path="latest"]; - -ds1 -> ds1_parse -> answer1; -ds2 -> ds2_parse -> answer1; - -answer1 [type=median index=0]; -""" -`, - assertion: func(t *testing.T, j job.Job, err error) { - require.NoError(t, err) - require.NotNil(t, j.FluxMonitorSpec) - spec := j.FluxMonitorSpec - assert.Equal(t, "example flux monitor spec", j.Name.String) - assert.Equal(t, "fluxmonitor", j.Type.String()) - assert.Equal(t, uint32(1), j.SchemaVersion) - assert.Equal(t, "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42", j.FluxMonitorSpec.ContractAddress.String()) - assert.Equal(t, tomlutils.Float32(0.5), spec.Threshold) - assert.Equal(t, tomlutils.Float32(0), spec.AbsoluteThreshold) - assert.True(t, spec.IdleTimerDisabled) - assert.Equal(t, 1*time.Minute, spec.PollTimerPeriod) - assert.False(t, spec.PollTimerDisabled) - assert.True(t, spec.DrumbeatEnabled) - assert.Equal(t, "@every 1m", spec.DrumbeatSchedule) - assert.Equal(t, 10*time.Second, spec.DrumbeatRandomDelay) - assert.False(t, spec.PollTimerDisabled) - assert.Equal(t, assets.NewLinkFromJuels(1000000000000000000), spec.MinPayment) - assert.NotZero(t, j.Pipeline) - }, - }, - { - name: "invalid contract addr", - toml: ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "0x3CCad4715152693fE3BC4460591e3D3Fbd071b42" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "1m" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds1_parse [type=jsonparse path="latest"]; -ds1 -> ds1_parse; -""" -`, - assertion: func(t *testing.T, s job.Job, err error) { - require.Nil(t, s.FluxMonitorSpec) - require.Error(t, err) - assert.Regexp(t, "^.*is not a valid EIP55 formatted address$", err.Error()) - }, - }, - { - name: "invalid poll interval", - toml: ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -maxTaskDuration = "1s" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "400ms" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}" timeout="500ms"]; -ds1_parse [type=jsonparse path="latest"]; -ds1 -> ds1_parse; -""" -`, - assertion: func(t *testing.T, s job.Job, err error) { - require.Error(t, err) - assert.EqualError(t, err, "PollTimerPeriod (400ms) must be equal or greater than the smallest value of MaxTaskDuration param, JobPipeline.HTTPRequest.DefaultTimeout config var, or MinTimeout of all tasks (500ms)") - }, - }, - { - name: "drumbeat and idle both active", - toml: ` -type = "fluxmonitor" -schemaVersion = 1 -name = "example flux monitor spec" -contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -maxTaskDuration = "1s" -threshold = 0.5 -absoluteThreshold = 0.0 - -idleTimerDisabled = false -idleTimerPeriod = "1s" - -drumbeatEnabled = true -drumbeatSchedule = "@every 1m" - -pollTimerPeriod = "800ms" -pollTimerDisabled = false - -observationSource = """ -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}" timeout="500ms"]; -ds1_parse [type=jsonparse path="latest"]; -ds1 -> ds1_parse; -""" -`, - assertion: func(t *testing.T, s job.Job, err error) { - require.Error(t, err) - assert.EqualError(t, err, "When the drumbeat ticker is enabled, the idle timer must be disabled. Please set IdleTimerDisabled to true") - }, - }, - { - name: "integer thresholds", - toml: ` -type = "fluxmonitor" -schemaVersion = 1 -name = "ADA / USD version 3 contract 0x3e4a23dB81D1F1268983f0CE78F1a9dC329A5b36 1624906849640" -contractAddress = "0x3e4a23dB81D1F1268983f0CE78F1a9dC329A5b36" -precision = 8 -threshold = 2 -idleTimerPeriod = "1m0s" -idleTimerDisabled = false -pollTimerPeriod = "1m0s" -pollTimerDisabled = false -maxTaskDuration = "0s" -observationSource = """ - // Node definitions. - feed0 [method=POST name="bridge-coinmarketcap" requestData="{\\"data\\":{\\"from\\":\\"ADA\\",\\"to\\":\\"USD\\"}}" type=bridge]; - jsonparse0 [ path="data,result" type=jsonparse ]; - feed0 -> jsonparse0; - jsonparse0 -> median; - feed1 [method=POST name="bridge-kaiko" requestData="{\\"data\\":{\\"from\\":\\"ADA\\",\\"to\\":\\"USD\\"}}" type=bridge]; - feed1 -> jsonparse1; - jsonparse1 -> median; - jsonparse1 [path="data,result" type=jsonparse]; - feed2 [method=POST name="bridge-nomics" requestData="{\\"data\\":{\\"from\\":\\"ADA\\",\\"to\\":\\"USD\\"}}" type=bridge]; - jsonparse2 [path="data,result" type=jsonparse]; - feed2 -> jsonparse2; - jsonparse2 -> median; - // Edge definitions. - median [type=median]; - multiply0 [times=100000000 type=multiply]; - median -> multiply0; -""" -externalJobID = "cfa3fa6b-2850-446b-b973-8f4c3b29d519" -`, - assertion: func(t *testing.T, s job.Job, err error) { - require.NoError(t, err) - }, - }, - } - for _, tc := range tt { - t.Run(tc.name, func(t *testing.T) { - s, err := ValidatedFluxMonitorSpec(testcfg{}, tc.toml) - tc.assertion(t, s, err) - }) - } -} diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 24455b054e3..a0d4eecfd66 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -40,7 +40,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" "github.com/smartcontractkit/chainlink/v2/core/services/blockheaderfeeder" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" @@ -251,28 +251,6 @@ func TestORM(t *testing.T) { assert.Equal(t, ocrSpecError2, dbSpecErr2.Description) }) - t.Run("creates a job with a direct request spec", func(t *testing.T) { - drSpec := fmt.Sprintf(` - type = "directrequest" - schemaVersion = 1 - evmChainID = "0" - name = "example eth request event spec" - contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" - externalJobID = "%s" - observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_merge [type=merge left="{}"] - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; - """ - `, uuid.New()) - - drJob, err := directrequest.ValidatedDirectRequestSpec(drSpec) - require.NoError(t, err) - err = orm.CreateJob(testutils.Context(t), &drJob) - require.NoError(t, err) - }) t.Run("creates webhook specs along with external_initiator_webhook_specs", func(t *testing.T) { ctx := testutils.Context(t) @@ -728,19 +706,27 @@ func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { }) t.Run("evm chain id validation for direct request works", func(t *testing.T) { + // DirectRequest has been removed; the job-type removal check fires + // before any EVM-chain-ID validation. jb := job.Job{ Type: job.DirectRequest, DirectRequestSpec: &job.DirectRequestSpec{}, } - assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(testutils.Context(t), &jb).Error()) + err := jobORM.CreateJob(testutils.Context(t), &jb) + require.Error(t, err) + assert.ErrorIs(t, err, job.ErrJobTypeRemoved) }) t.Run("evm chain id validation for flux monitor works", func(t *testing.T) { + // FluxMonitor has been removed; the job-type removal check fires + // before any EVM-chain-ID validation. jb := job.Job{ Type: job.FluxMonitor, FluxMonitorSpec: &job.FluxMonitorSpec{}, } - assert.Equal(t, "CreateJobFailed: evm chain id must be defined", jobORM.CreateJob(testutils.Context(t), &jb).Error()) + err := jobORM.CreateJob(testutils.Context(t), &jb) + require.Error(t, err) + assert.ErrorIs(t, err, job.ErrJobTypeRemoved) }) t.Run("evm chain id validation for vrf works", func(t *testing.T) { @@ -1135,9 +1121,7 @@ func Test_FindJobs(t *testing.T) { err = orm.CreateJob(ctx, &jb1) require.NoError(t, err) - jb2, err := directrequest.ValidatedDirectRequestSpec( - testspecs.GetDirectRequestSpec(), - ) + jb2, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) err = orm.CreateJob(ctx, &jb2) @@ -1434,9 +1418,8 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) - jb.DirectRequestSpec.EVMChainID = sqlutil.NewI(0) err = orm.CreateJob(testutils.Context(t), &jb) require.NoError(t, err) @@ -1813,7 +1796,7 @@ func Test_FindPipelineRunByID(t *testing.T) { bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) err = orm.CreateJob(testutils.Context(t), &jb) @@ -1859,7 +1842,7 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) err = orm.CreateJob(ctx, &jb) @@ -1897,7 +1880,7 @@ func Test_FindSpecErrorsByJobIDs(t *testing.T) { bridgesORM := bridges.NewORM(db) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) err = orm.CreateJob(ctx, &jb) diff --git a/core/services/job/kv_orm_test.go b/core/services/job/kv_orm_test.go index f355690093b..1d273228d49 100644 --- a/core/services/job/kv_orm_test.go +++ b/core/services/job/kv_orm_test.go @@ -2,6 +2,7 @@ package job_test import ( "context" + "fmt" "strconv" "testing" "time" @@ -9,13 +10,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/google/uuid" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" @@ -34,7 +37,7 @@ func TestJobKVStore(t *testing.T) { kvStore := job.NewKVStore(jobID, db) jobORM := NewTestORM(t, db, pipelineORM, bridgesORM, cltest.NewKeyStore(t, db)) - jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) jb.ID = jobID require.NoError(t, jobORM.CreateJob(testutils.Context(t), &jb)) @@ -90,12 +93,12 @@ func TestJobKVStore_PruneExpiredEntries(t *testing.T) { kvStore1 := job.NewKVStore(jobID1, db) kvStore2 := job.NewKVStore(jobID2, db) - jb1, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb1, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) jb1.ID = jobID1 require.NoError(t, jobORM.CreateJob(testutils.Context(t), &jb1)) - jb2, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) + jb2, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) require.NoError(t, err) jb2.ID = jobID2 require.NoError(t, jobORM.CreateJob(testutils.Context(t), &jb2)) diff --git a/core/services/job/orm.go b/core/services/job/orm.go index 6f11f3f90c6..0b104e0a709 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -166,11 +166,21 @@ func (o *orm) AssertBridgesExist(ctx context.Context, p pipeline.Pipeline) error return nil } +// ErrJobTypeRemoved is returned when attempting to create a job whose type has +// been permanently removed from this node. +var ErrJobTypeRemoved = errors.New("job type has been removed and is no longer supported") + // CreateJob creates the job, and it's associated spec record. // Expects an unmarshalled job spec as the jb argument i.e. output from ValidatedXX. // Scans all persisted records back into jb func (o *orm) CreateJob(ctx context.Context, jb *Job) error { - if slices.Contains([]Type{DirectRequest, FluxMonitor, LegacyGasStationServer, LegacyGasStationSidecar, Webhook}, jb.Type) { + // Permanently removed job types: reject all new submissions regardless of + // which code path reaches here (REST API, GraphQL, feeds manager, etc.). + if jb.Type == DirectRequest || jb.Type == FluxMonitor { + return fmt.Errorf("cannot create job of type %q: %w", jb.Type, ErrJobTypeRemoved) + } + + if slices.Contains([]Type{LegacyGasStationServer, LegacyGasStationSidecar, Webhook}, jb.Type) { o.lggr.Warnw("Job of this type will not be supported in chainlink v3", "type", jb.Type) } diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index e883fb23b47..cabb2533d1b 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -389,3 +389,29 @@ func (n *NullDelegate) BeforeJobDeleted(spec Job) {} func (n *NullDelegate) OnDeleteJob(context.Context, Job) error { return nil } + +var _ Delegate = &DeprecatedDelegate{} + +// DeprecatedDelegate is a Delegate for job types that have been removed. +// It surfaces a visible error via TryRecordError so operators can see the job +// is no longer supported rather than silently doing nothing. +type DeprecatedDelegate struct { + Type Type +} + +func (d *DeprecatedDelegate) JobType() Type { + return d.Type +} + +// ServicesForSpec returns an error so that the spawner records it as a job +// error, making the deprecation visible in the UI. +func (d *DeprecatedDelegate) ServicesForSpec(_ context.Context, _ Job) ([]ServiceCtx, error) { + return nil, fmt.Errorf("job type %q has been removed and is no longer supported; please delete this job", d.Type) +} + +func (d *DeprecatedDelegate) BeforeJobCreated(Job) {} +func (d *DeprecatedDelegate) AfterJobCreated(Job) {} +func (d *DeprecatedDelegate) BeforeJobDeleted(Job) {} +func (d *DeprecatedDelegate) OnDeleteJob(context.Context, Job) error { + return nil +} diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 4170be90317..a181b19ef4a 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -2,6 +2,7 @@ package job_test import ( "context" + "fmt" "math/big" "testing" "time" @@ -10,6 +11,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/loop" @@ -32,12 +34,14 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -133,7 +137,9 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { }) t.Run("starts and stops job services when jobs are added and removed", func(t *testing.T) { - jobA := cltest.MakeDirectRequestJobSpec(t) + cronJobTmp, cronErr := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) + require.NoError(t, cronErr) + jobA := &cronJobTmp jobB := makeOCRJobSpec(t, address, bridge.Name.String(), bridge2.Name.String()) lggr := logger.TestLogger(t) diff --git a/core/services/ocr/flags_test.go b/core/services/ocr/flags_test.go index a204bdde6be..a161fd46470 100644 --- a/core/services/ocr/flags_test.go +++ b/core/services/ocr/flags_test.go @@ -10,7 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-evm/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ) func TestFlags_IsLowered(t *testing.T) { @@ -34,7 +34,7 @@ func TestFlags_IsLowered(t *testing.T) { address = testutils.NewAddress() ) - flags := fluxmonitorv2.ContractFlags{FlagsInterface: flagsContract} + flags := ocr.ContractFlags{FlagsInterface: flagsContract} flagsContract.On("GetFlags", mock.Anything, mock.Anything). Run(func(args mock.Arguments) { diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 00c0f896dc4..c20e0883b84 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -2,6 +2,7 @@ package pipeline_test import ( "context" + "fmt" "testing" "time" @@ -24,8 +25,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" ) @@ -140,29 +143,9 @@ func mustInsertAsyncRun(t *testing.T, orm pipeline.ORM, jobORM job.ORM) *pipelin t.Helper() ctx := testutils.Context(t) - s := ` -ds1 [type=bridge async=true name="example-bridge" timeout=0 requestData=<{"data": {"coin": "BTC", "market": "USD"}}>] -ds1_parse [type=jsonparse lax=false path="data,result"] -ds1_multiply [type=multiply times=1000000000000000000] - -ds1->ds1_parse->ds1_multiply->answer1; - -answer1 [type=median index=0]; -answer2 [type=bridge name=election_winner index=1]; -` - jb := job.Job{ - Type: job.DirectRequest, - SchemaVersion: 1, - MaxTaskDuration: sqlutil.Interval(1 * time.Minute), - DirectRequestSpec: &job.DirectRequestSpec{ - ContractAddress: cltest.NewEIP55Address(), - EVMChainID: (*sqlutil.Big)(&cltest.FixtureChainID), - }, - PipelineSpec: &pipeline.Spec{ - DotDagSource: s, - }, - } - err := jobORM.CreateJob(ctx, &jb) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) + require.NoError(t, err) + err = jobORM.CreateJob(ctx, &jb) require.NoError(t, err) run := &pipeline.Run{ @@ -252,19 +235,9 @@ ds1->ds1_parse->ds1_multiply->answer1; answer1 [type=median index=0]; answer2 [type=bridge name=election_winner index=1]; ` - jb := job.Job{ - Type: job.DirectRequest, - SchemaVersion: 1, - MaxTaskDuration: sqlutil.Interval(1 * time.Minute), - DirectRequestSpec: &job.DirectRequestSpec{ - ContractAddress: cltest.NewEIP55Address(), - EVMChainID: (*sqlutil.Big)(&cltest.FixtureChainID), - }, - PipelineSpec: &pipeline.Spec{ - DotDagSource: s, - }, - } - err := jorm.CreateJob(ctx, &jb) + jb, err := cron.ValidatedCronSpec(fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New())) + require.NoError(t, err) + err = jorm.CreateJob(ctx, &jb) require.NoError(t, err) spec := pipeline.Spec{ DotDagSource: s, @@ -639,102 +612,6 @@ func Test_PipelineORM_DeleteRunsOlderThan(t *testing.T) { require.Error(t, err, "not found") } } - -func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { - t.Parallel() - ctx := testutils.Context(t) - - // The test configures single DR job with two task runs: one is running and one is suspended. - // GetUnfinishedRuns() expects to catch the one that is running. - - config := configtest.NewTestGeneralConfig(t) - lggr := logger.TestLogger(t) - db := pgtest.NewSqlxDB(t) - keyStore := cltest.NewKeyStore(t, db) - porm := pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()) - bridgeORM := bridges.NewORM(db) - - jorm := job.NewORM(db, porm, bridgeORM, keyStore, lggr) - defer func() { assert.NoError(t, jorm.Close()) }() - - timestamp := time.Now() - var drJob = job.Job{ - ID: 1, - DirectRequestSpec: &job.DirectRequestSpec{ - ContractAddress: cltest.NewEIP55Address(), - CreatedAt: timestamp, - UpdatedAt: timestamp, - EVMChainID: (*sqlutil.Big)(&cltest.FixtureChainID), - }, - ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), - PipelineSpec: &pipeline.Spec{ - ID: 1, - DotDagSource: `ds1 [type=http method=GET url="https://pricesource1.com"`, - }, - Type: job.DirectRequest, - SchemaVersion: 1, - Name: null.StringFrom("test"), - MaxTaskDuration: sqlutil.Interval(1 * time.Minute), - } - - err := jorm.CreateJob(ctx, &drJob) - require.NoError(t, err) - require.Equal(t, job.DirectRequest, drJob.Type) - - runningID := uuid.New() - - err = porm.CreateRun(ctx, &pipeline.Run{ - PipelineSpecID: drJob.PipelineSpecID, - PruningKey: drJob.ID, - State: pipeline.RunStatusRunning, - Outputs: jsonserializable.JSONSerializable{}, - CreatedAt: time.Now(), - PipelineTaskRuns: []pipeline.TaskRun{{ - ID: runningID, - Type: pipeline.TaskTypeHTTP, - Index: 0, - Output: jsonserializable.JSONSerializable{}, - CreatedAt: time.Now(), - DotID: "ds1", - }}, - }) - require.NoError(t, err) - - err = porm.CreateRun(ctx, &pipeline.Run{ - PipelineSpecID: drJob.PipelineSpecID, - PruningKey: drJob.ID, - State: pipeline.RunStatusSuspended, - Outputs: jsonserializable.JSONSerializable{}, - CreatedAt: time.Now(), - PipelineTaskRuns: []pipeline.TaskRun{{ - ID: uuid.New(), - Type: pipeline.TaskTypeHTTP, - Index: 1, - Output: jsonserializable.JSONSerializable{}, - CreatedAt: time.Now(), - DotID: "ds1", - }}, - }) - require.NoError(t, err) - - var counter int - - err = porm.GetUnfinishedRuns(testutils.Context(t), time.Now(), func(run pipeline.Run) error { - counter++ - - require.Equal(t, job.DirectRequest.String(), run.PipelineSpec.JobType) - require.NotEmpty(t, run.PipelineTaskRuns) - require.Equal(t, runningID, run.PipelineTaskRuns[0].ID) - - trun := run.ByDotID("ds1") - require.NotNil(t, trun) - - return nil - }) - require.NoError(t, err) - require.Equal(t, 1, counter) -} - func Test_Prune(t *testing.T) { t.Parallel() diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index f68aa30bf3e..06a6ce7e4e8 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -64,80 +64,6 @@ ds_parse [type=jsonparse path="data.price" separator="."]; ds_multiply [type=multiply times=100]; ds -> ds_parse -> ds_multiply; """ -` - DirectRequestSpecNoExternalJobID = ` -type = "directrequest" -schemaVersion = 1 -name = "%s" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -evmChainID = "%s" -observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; -""" -` - DirectRequestSpecTemplate = ` -type = "directrequest" -schemaVersion = 1 -name = "%s" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "%s" -evmChainID = "%s" -observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; -""" -` - DirectRequestSpecWithRequestersAndMinContractPaymentTemplate = ` -type = "directrequest" -schemaVersion = 1 -requesters = ["0xaaaa1F8ee20f5565510B84f9353F1E333E753B7a", "0xbbbb70F0e81C6F3430dfdC9fa02fB22BdD818C4e"] -minContractPaymentLinkJuels = "1000000000000000000000" -name = "%s" -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -externalJobID = "%s" -evmChainID = "%s" -observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; -""" -` - FluxMonitorSpecTemplate = ` -type = "fluxmonitor" -schemaVersion = 1 -name = "%s" -contractAddress = "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" -externalJobID = "%s" -evmChainID = "%s" -threshold = 0.5 -absoluteThreshold = 0.0 # optional - -idleTimerPeriod = "1s" -idleTimerDisabled = false - -pollTimerPeriod = "1m" -pollTimerDisabled = false - -observationSource = """ -// data source 1 -ds1 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds1_parse [type=jsonparse path="latest"]; - -// data source 2 -ds2 [type=http method=GET url="https://pricesource1.com" requestData="{\\"coin\\": \\"ETH\\", \\"market\\": \\"USD\\"}"]; -ds2_parse [type=jsonparse path="latest"]; - -ds1 -> ds1_parse -> answer1; -ds2 -> ds2_parse -> answer1; - -answer1 [type=median index=0]; -""" ` OCR2EVMSpecMinimalTemplate = `type = "offchainreporting2" @@ -274,15 +200,6 @@ func GetOCRBootstrapSpec() string { return fmt.Sprintf(OCRBootstrapSpec, uuid.New()) } -func GetDirectRequestSpec() string { - uuid := uuid.New() - return GetDirectRequestSpecWithUUID(uuid) -} - -func GetDirectRequestSpecWithUUID(u uuid.UUID) string { - return fmt.Sprintf(DirectRequestSpecTemplate, u, u, testutils.FixtureChainID.String()) -} - func GetOCR2EVMSpecMinimal() string { return fmt.Sprintf(OCR2EVMSpecMinimalTemplate, uuid.New(), testutils.NewAddress().Hex(), testutils.FixtureChainID.String()) } diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 7751027ae5c..4aad0bbf3c6 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -21,8 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/cresettings" "github.com/smartcontractkit/chainlink/v2/core/services/cron" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -236,9 +234,9 @@ func (jc *JobsController) validateJobSpec(ctx context.Context, tomlString string return jb, http.StatusNotImplemented, errors.New("The Offchain Reporting 2 feature is disabled by configuration") } case job.DirectRequest: - jb, err = directrequest.ValidatedDirectRequestSpec(tomlString) + return jb, http.StatusUnprocessableEntity, errors.New("job type directrequest has been removed and is no longer supported") case job.FluxMonitor: - jb, err = fluxmonitorv2.ValidatedFluxMonitorSpec(config.JobPipeline(), tomlString) + return jb, http.StatusUnprocessableEntity, errors.New("job type fluxmonitor has been removed and is no longer supported") case job.CRESettings: jb, err = cresettings.ValidatedCRESettingsSpec(tomlString) case job.Cron: diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index c1192b1bfd2..23d282e44c5 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -11,11 +11,8 @@ import ( "net/http" "net/url" "strconv" - "sync" "testing" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" @@ -36,10 +33,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -104,33 +100,6 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin } } -func TestJobController_Create_DirectRequest_Fast(t *testing.T) { - ctx := testutils.Context(t) - app, client := setupJobsControllerTests(t) - require.NoError(t, app.KeyStore.OCR().Add(ctx, cltest.DefaultOCRKey)) - - n := 10 - - var wg sync.WaitGroup - for i := range n { - wg.Add(1) - go func(i int) { - defer wg.Done() - - body, err := json.Marshal(web.CreateJobRequest{ - TOML: fmt.Sprintf(testspecs.DirectRequestSpecNoExternalJobID, i, cltest.FixtureChainID.String()), - }) - require.NoError(t, err) - - t.Logf("POSTing %d", i) - r, cleanup := client.Post("/v2/jobs", bytes.NewReader(body)) - defer cleanup() - require.Equal(t, http.StatusOK, r.StatusCode) - }(i) - } - wg.Wait() - cltest.AssertCount(t, app.GetDB(), "direct_request_specs", int64(n)) -} func mustInt32FromString(t *testing.T, s string) int32 { i, err := strconv.ParseInt(s, 10, 32) @@ -254,84 +223,9 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.NotNil(t, resource.PipelineSpec.DotDAGSource) require.Equal(t, sqlutil.NewI(42), jb.CronSpec.EVMChainID) }, - }, - { - name: "directrequest", - tomlTemplate: func(nameAndExternalJobID string) string { - return testspecs.GetDirectRequestSpecWithUUID(uuid.MustParse(nameAndExternalJobID)) - }, - assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { - require.Equal(t, http.StatusOK, r.StatusCode) - resource := presenters.JobResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) - assert.NoError(t, err) - - jb, err := jorm.FindJob(testutils.Context(t), mustInt32FromString(t, resource.ID)) - require.NoError(t, err) - require.NotNil(t, jb.DirectRequestSpec) - - assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) - assert.NotNil(t, resource.PipelineSpec.DotDAGSource) - // Sanity check to make sure it inserted correctly - require.Equal(t, types.EIP55Address("0x613a38AC1659769640aaE063C651F48E0250454C"), jb.DirectRequestSpec.ContractAddress) - require.Equal(t, jb.ExternalJobID.String(), nameAndExternalJobID) - }, - }, - { - name: "directrequest-with-requesters-and-min-contract-payment", - tomlTemplate: func(nameAndExternalJobID string) string { - return fmt.Sprintf(testspecs.DirectRequestSpecWithRequestersAndMinContractPaymentTemplate, nameAndExternalJobID, nameAndExternalJobID, cltest.FixtureChainID.String()) - }, - assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { - require.Equal(t, http.StatusOK, r.StatusCode) - resource := presenters.JobResource{} - err := web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, r), &resource) - assert.NoError(t, err) - - jb, err := jorm.FindJob(testutils.Context(t), mustInt32FromString(t, resource.ID)) - require.NoError(t, err) - require.NotNil(t, jb.DirectRequestSpec) - - assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) - assert.NotNil(t, resource.PipelineSpec.DotDAGSource) - assert.NotNil(t, resource.DirectRequestSpec.Requesters) - assert.Equal(t, "1000000000000000000000", resource.DirectRequestSpec.MinContractPayment.String()) - // Check requesters got saved properly - require.EqualValues(t, []common.Address{common.HexToAddress("0xAaAA1F8ee20f5565510b84f9353F1E333e753B7a"), common.HexToAddress("0xBbBb70f0E81c6F3430dfDc9fa02fB22bDD818c4E")}, jb.DirectRequestSpec.Requesters) - require.Equal(t, "1000000000000000000000", jb.DirectRequestSpec.MinContractPayment.String()) - require.Equal(t, jb.ExternalJobID.String(), nameAndExternalJobID) }, - }, - { - name: "fluxmonitor", - tomlTemplate: func(nameAndExternalJobID string) string { - return fmt.Sprintf(testspecs.FluxMonitorSpecTemplate, nameAndExternalJobID, nameAndExternalJobID, cltest.FixtureChainID.String()) - }, - assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { - require.Equal(t, http.StatusInternalServerError, r.StatusCode) - - errs := cltest.ParseJSONAPIErrors(t, r.Body) - require.NotNil(t, errs) - require.Len(t, errs.Errors, 1) - // services failed to start - require.Contains(t, errs.Errors[0].Detail, "no contract code at given address") - // but the job should still exist - ctx := testutils.Context(t) - jb, err := jorm.FindJobByExternalJobID(ctx, uuid.MustParse(nameAndExternalJobID)) - require.NoError(t, err) - require.NotNil(t, jb.FluxMonitorSpec) - - assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) - assert.NotNil(t, jb.PipelineSpec.DotDagSource) - assert.Equal(t, types.EIP55Address("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42"), jb.FluxMonitorSpec.ContractAddress) - assert.Equal(t, time.Second, jb.FluxMonitorSpec.IdleTimerPeriod) - assert.False(t, jb.FluxMonitorSpec.IdleTimerDisabled) - assert.Equal(t, tomlutils.Float32(0.5), jb.FluxMonitorSpec.Threshold) - assert.Equal(t, tomlutils.Float32(0), jb.FluxMonitorSpec.AbsoluteThreshold) - }, - }, - { - name: "vrf", + { + name: "vrf", tomlTemplate: func(_ string) string { return testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ PublicKey: pks[0].PublicKey.String(), @@ -518,7 +412,7 @@ func TestJobsController_FailToCreate_EmptyJsonAttribute(t *testing.T) { } func TestJobsController_Index_HappyPath(t *testing.T) { - _, client, ocrJobSpecFromFile, _, ereJobSpecFromFile, _ := setupJobSpecsControllerTestsWithJobs(t) + _, client, ocrJobSpecFromFile, _, cronJobSpecFromFile, _ := setupJobSpecsControllerTestsWithJobs(t) url := url.URL{Path: "/v2/jobs"} query := url.Query() @@ -535,12 +429,12 @@ func TestJobsController_Index_HappyPath(t *testing.T) { require.Len(t, resources, 2) - runDirectRequestJobSpecAssertions(t, ereJobSpecFromFile, resources[0]) + assert.Equal(t, cronJobSpecFromFile.ExternalJobID.String(), resources[0].ExternalJobID.String()) runOCRJobSpecAssertions(t, ocrJobSpecFromFile, resources[1]) } func TestJobsController_Show_HappyPath(t *testing.T) { - _, client, ocrJobSpecFromFile, jobID, ereJobSpecFromFile, jobID2 := setupJobSpecsControllerTestsWithJobs(t) + _, client, ocrJobSpecFromFile, jobID, cronJobSpecFromFile, jobID2 := setupJobSpecsControllerTestsWithJobs(t) response, cleanup := client.Get("/v2/jobs/" + strconv.Itoa(int(jobID))) t.Cleanup(cleanup) @@ -566,21 +460,21 @@ func TestJobsController_Show_HappyPath(t *testing.T) { t.Cleanup(cleanup) cltest.AssertServerResponse(t, response, http.StatusOK) - ereJob := presenters.JobResource{} - err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &ereJob) + cronJob := presenters.JobResource{} + err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &cronJob) assert.NoError(t, err) - runDirectRequestJobSpecAssertions(t, ereJobSpecFromFile, ereJob) + assert.Equal(t, cronJobSpecFromFile.ExternalJobID.String(), cronJob.ExternalJobID.String()) - response, cleanup = client.Get("/v2/jobs/" + ereJobSpecFromFile.ExternalJobID.String()) + response, cleanup = client.Get("/v2/jobs/" + cronJobSpecFromFile.ExternalJobID.String()) t.Cleanup(cleanup) cltest.AssertServerResponse(t, response, http.StatusOK) - ereJob = presenters.JobResource{} - err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &ereJob) + cronJob = presenters.JobResource{} + err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, response), &cronJob) assert.NoError(t, err) - runDirectRequestJobSpecAssertions(t, ereJobSpecFromFile, ereJob) + assert.Equal(t, cronJobSpecFromFile.ExternalJobID.String(), cronJob.ExternalJobID.String()) } func TestJobsController_Show_InvalidID(t *testing.T) { @@ -739,15 +633,6 @@ func runOCRJobSpecAssertions(t *testing.T, ocrJobSpecFromFileDB job.Job, ocrJobS assert.Contains(t, ocrJobSpecFromServer.OffChainReportingSpec.UpdatedAt.String(), "20") } -func runDirectRequestJobSpecAssertions(t *testing.T, ereJobSpecFromFile job.Job, ereJobSpecFromServer presenters.JobResource) { - assert.Equal(t, ereJobSpecFromFile.DirectRequestSpec.ContractAddress, ereJobSpecFromServer.DirectRequestSpec.ContractAddress) - assert.Equal(t, ereJobSpecFromFile.Pipeline.Source, ereJobSpecFromServer.PipelineSpec.DotDAGSource) - // Check that create and update dates are non empty values. - // Empty date value is "0001-01-01 00:00:00 +0000 UTC" so we are checking for the - // millennia and century characters to be present - assert.Contains(t, ereJobSpecFromServer.DirectRequestSpec.CreatedAt.String(), "20") - assert.Contains(t, ereJobSpecFromServer.DirectRequestSpec.UpdatedAt.String(), "20") -} func setupBridges(t *testing.T, ds sqlutil.DataSource) (b1, b2 string) { _, bridge := cltest.MustCreateBridge(t, ds, cltest.BridgeOpts{}) @@ -812,26 +697,11 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication err = app.AddJobV2(ctx, &jb) require.NoError(t, err) - drSpec := fmt.Sprintf(` - type = "directrequest" - schemaVersion = 1 - evmChainID = "%s" - name = "example eth request event spec" - contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" - externalJobID = "%s" - observationSource = """ - ds1 [type=http method=GET url="http://example.com" allowunrestrictednetworkaccess="true"]; - ds1_merge [type=merge left="{}"] - ds1_parse [type=jsonparse path="USD"]; - ds1_multiply [type=multiply times=100]; - ds1 -> ds1_parse -> ds1_multiply; - """ - `, cltest.FixtureChainID.String(), uuid.New()) - - erejb, err := directrequest.ValidatedDirectRequestSpec(drSpec) + cronSpec := fmt.Sprintf(testspecs.CronSpecTemplate, uuid.New()) + cronJb, err := cron.ValidatedCronSpec(cronSpec) require.NoError(t, err) - err = app.AddJobV2(ctx, &erejb) + err = app.AddJobV2(ctx, &cronJb) require.NoError(t, err) - return app, client, jb, jb.ID, erejb, erejb.ID + return app, client, jb, jb.ID, cronJb, cronJb.ID } diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 2d02582c3a2..b3d1af945ea 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink-common/keystore/corekeys" "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" - "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" evmassets "github.com/smartcontractkit/chainlink-evm/pkg/assets" "github.com/smartcontractkit/chainlink-evm/pkg/types" @@ -59,7 +58,6 @@ func TestJob(t *testing.T) { require.NoError(t, err) trustedBlockhashStoreBatchSize := int32(20) - var specGasLimit uint32 = 1000 vrfPubKey, _ := secp256k1.NewPublicKeyFromHex("0xede539e216e3a50e69d1c68aa9cc472085876c4002f6e1e6afee0ea63b50a78b00") testCases := []struct { @@ -67,158 +65,6 @@ func TestJob(t *testing.T) { job job.Job want string }{ - { - name: "direct request spec", - job: job.Job{ - ID: 1, - GasLimit: clnull.Uint32From(specGasLimit), - ForwardingAllowed: false, - DirectRequestSpec: &job.DirectRequestSpec{ - ContractAddress: contractAddress, - CreatedAt: timestamp, - UpdatedAt: timestamp, - EVMChainID: evmChainID, - }, - ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), - PipelineSpec: &pipeline.Spec{ - ID: 1, - DotDagSource: `ds1 [type=http method=GET url="https://pricesource1.com"`, - }, - Type: job.DirectRequest, - SchemaVersion: 1, - Name: null.StringFrom("test"), - MaxTaskDuration: sqlutil.Interval(1 * time.Minute), - }, - want: fmt.Sprintf(` - { - "data":{ - "type":"jobs", - "id":"1", - "attributes":{ - "name": "test", - "schemaVersion": 1, - "type": "directrequest", - "maxTaskDuration": "1m0s", - "externalJobID":"0eec7e1d-d0d2-476c-a1a8-72dfb6633f46", - "pipelineSpec": { - "id": 1, - "dotDagSource": "ds1 [type=http method=GET url=\"https://pricesource1.com\"", - "jobID": 0 - }, - "directRequestSpec": { - "contractAddress": "%s", - "minIncomingConfirmations": null, - "minContractPaymentLinkJuels": null, - "requesters": null, - "initiator": "runlog", - "createdAt":"2000-01-01T00:00:00Z", - "updatedAt":"2000-01-01T00:00:00Z", - "evmChainID": "42" - }, - "offChainReportingOracleSpec": null, - "offChainReporting2OracleSpec": null, - "fluxMonitorSpec": null, - "gasLimit": 1000, - "forwardingAllowed": false, - "cronSpec": null, - "vrfSpec": null, - "webhookSpec": null, - "workflowSpec": null, - "blockhashStoreSpec": null, - "blockHeaderFeederSpec": null, - "bootstrapSpec": null, - "gatewaySpec": null, - "standardCapabilitiesSpec": null, - "ccipSpec": null, - "ccvCommitteeVerifierSpec": null, - "ccvExecutorSpec": null, - "creSettingsSpec": null, - "errors": [] - } - } - }`, contractAddress), - }, - { - name: "fluxmonitor spec", - job: job.Job{ - ID: 1, - FluxMonitorSpec: &job.FluxMonitorSpec{ - ContractAddress: contractAddress, - Threshold: 0.5, - IdleTimerPeriod: 1 * time.Minute, - IdleTimerDisabled: false, - PollTimerPeriod: 1 * time.Second, - PollTimerDisabled: false, - MinPayment: assets.NewLinkFromJuels(1), - CreatedAt: timestamp, - UpdatedAt: timestamp, - EVMChainID: evmChainID, - }, - ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), - PipelineSpec: &pipeline.Spec{ - ID: 1, - DotDagSource: `ds1 [type=http method=GET url="https://pricesource1.com"`, - }, - Type: job.FluxMonitor, - SchemaVersion: 1, - Name: null.StringFrom("test"), - MaxTaskDuration: sqlutil.Interval(1 * time.Minute), - }, - want: fmt.Sprintf(` - { - "data":{ - "type":"jobs", - "id":"1", - "attributes":{ - "name": "test", - "schemaVersion": 1, - "type": "fluxmonitor", - "maxTaskDuration": "1m0s", - "externalJobID":"0eec7e1d-d0d2-476c-a1a8-72dfb6633f46", - "pipelineSpec": { - "id": 1, - "dotDagSource": "ds1 [type=http method=GET url=\"https://pricesource1.com\"", - "jobID": 0 - }, - "fluxMonitorSpec": { - "contractAddress": "%s", - "threshold": 0.5, - "absoluteThreshold": 0, - "idleTimerPeriod": "1m0s", - "idleTimerDisabled": false, - "pollTimerPeriod": "1s", - "pollTimerDisabled": false, - "drumbeatEnabled": false, - "drumbeatRandomDelay": null, - "drumbeatSchedule": null, - "minPayment": "1", - "createdAt":"2000-01-01T00:00:00Z", - "updatedAt":"2000-01-01T00:00:00Z", - "evmChainID": "42" - }, - "gasLimit": null, - "forwardingAllowed": false, - "offChainReportingOracleSpec": null, - "offChainReporting2OracleSpec": null, - "directRequestSpec": null, - "cronSpec": null, - "vrfSpec": null, - "webhookSpec": null, - "workflowSpec": null, - "blockhashStoreSpec": null, - "blockHeaderFeederSpec": null, - "bootstrapSpec": null, - "gatewaySpec": null, - "standardCapabilitiesSpec": null, - "ccipSpec": null, - "creSettingsSpec": null, - "ccvCommitteeVerifierSpec": null, - "ccvExecutorSpec": null, - "errors": [] - } - } - }`, contractAddress), - }, { name: "ocr spec", job: job.Job{ diff --git a/core/web/resolver/job_test.go b/core/web/resolver/job_test.go index 794e4960180..b8d03c26fad 100644 --- a/core/web/resolver/job_test.go +++ b/core/web/resolver/job_test.go @@ -17,9 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-evm/pkg/chains" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" clnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" + "github.com/smartcontractkit/chainlink/v2/core/services/cron" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" @@ -316,8 +315,8 @@ func TestResolver_CreateJob(t *testing.T) { } } }` - uuid := uuid.New() - spec := fmt.Sprintf(testspecs.DirectRequestSpecTemplate, uuid, uuid, testutils.FixtureChainID.String()) + jobName := uuid.New().String() + spec := fmt.Sprintf(testspecs.CronSpecTemplate, jobName) variables := map[string]any{ "input": map[string]any{ "TOML": spec, @@ -328,7 +327,7 @@ func TestResolver_CreateJob(t *testing.T) { "TOML": "some wrong value", }, } - jb, err := directrequest.ValidatedDirectRequestSpec(spec) + jb, err := cron.ValidatedCronSpec(spec) require.NoError(t, err) d, err := json.Marshal(map[string]any{ @@ -336,7 +335,7 @@ func TestResolver_CreateJob(t *testing.T) { "job": map[string]any{ "id": "0", "maxTaskDuration": "0s", - "name": jb.Name, + "name": jb.Name.ValueOrZero(), "schemaVersion": 1, "createdAt": "0001-01-01T00:00:00Z", "externalJobID": jb.ExternalJobID.String(), diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 08707393c22..d05a1053abf 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -31,9 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/cresettings" "github.com/smartcontractkit/chainlink/v2/core/services/cron" - "github.com/smartcontractkit/chainlink/v2/core/services/directrequest" "github.com/smartcontractkit/chainlink/v2/core/services/feeds" - "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" @@ -1089,9 +1087,9 @@ func (r *Resolver) CreateJob(ctx context.Context, args struct { return nil, errors.New("The Offchain Reporting 2 feature is disabled by configuration") } case job.DirectRequest: - jb, err = directrequest.ValidatedDirectRequestSpec(args.Input.TOML) + return nil, errors.New("job type directrequest has been removed and is no longer supported") case job.FluxMonitor: - jb, err = fluxmonitorv2.ValidatedFluxMonitorSpec(config.JobPipeline(), args.Input.TOML) + return nil, errors.New("job type fluxmonitor has been removed and is no longer supported") case job.CRESettings: jb, err = cresettings.ValidatedCRESettingsSpec(args.Input.TOML) case job.Cron: diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index cc85daf95a6..edfd5d2ed07 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -26,9 +26,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/store/models" ) -// Specs are only embedded on the job and are not fetchable by it's own id, so +// Specs are only embedded on the job and are not fetchable by its own id, so // we test the spec resolvers by fetching a job by id. - func TestResolver_CronSpec(t *testing.T) { var ( id = int32(1) diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 9fa49112c07..75ad5388606 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -149,8 +149,8 @@ DefaultTimeout = '1m0s' MaxSize = '100.00mb' [FluxMonitor] -DefaultTransactionQueueDepth = 100 -SimulateTransactions = true +DefaultTransactionQueueDepth = 1 +SimulateTransactions = false [OCR2] Enabled = true diff --git a/devenv/cmd/cl/completion.go b/devenv/cmd/cl/completion.go index da63fe4aa69..2a52813adff 100644 --- a/devenv/cmd/cl/completion.go +++ b/devenv/cmd/cl/completion.go @@ -28,7 +28,6 @@ func getSubCommands(parent string) []prompt.Suggest { case "test": return []prompt.Suggest{ {Text: "cron TestSmoke", Description: "Run Cron trigger test"}, - {Text: "directrequest TestSmoke", Description: "Run Direct Request test"}, {Text: "flux TestSmoke", Description: "Run Flux test"}, {Text: "ocr2 TestSmoke/rounds", Description: "Run OCR2 smoke test"}, {Text: "ocr2 TestOCR2Soak/clean", Description: "Run OCR2 soak test"}, @@ -64,8 +63,6 @@ func getSubCommands(parent string) []prompt.Suggest { {Text: "env.toml,products/cron/soak.toml", Description: "1 Anvil, 1 CL Node, 10 Cron triggers for soak testing"}, {Text: "env.toml,products/directrequest/basic.toml", Description: "1 Anvil, 1 CL Node, Runlog trigger"}, {Text: "env.toml,products/directrequest/soak.toml", Description: "1 Anvil, 1 CL Node, 10 Runlog triggers for soak testing"}, - {Text: "env.toml,products/flux/basic.toml", Description: "1 Anvil, 1 CL Node, Runlog trigger"}, - {Text: "env.toml,products/flux/soak.toml", Description: "1 Anvil, 1 CL Node, 10 Runlog triggers for soak testing"}, {Text: "env.toml,products/ocr2/basic.toml", Description: "2 Anvils, 5 CL nodes, 1 OCRv2 product"}, {Text: "env.toml,products/ocr2/basic.toml,products/ocr2/soak.toml", Description: "2 Anvils, 5 CL nodes, 10 OCRv2 product for soak testing"}, {Text: "env.toml,products/ocr2/basic.toml,env-cl-rebuild.toml", Description: "Spin OCR2 product + 5 CL nodes + build local CL image"}, diff --git a/devenv/tests/directrequest/smoke_test.go b/devenv/tests/directrequest/smoke_test.go deleted file mode 100644 index 7da22b666d3..00000000000 --- a/devenv/tests/directrequest/smoke_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package directrequest - -import ( - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink-evm/gethwrappers/generated/test_api_consumer_wrapper" - de "github.com/smartcontractkit/chainlink/devenv" - "github.com/smartcontractkit/chainlink/devenv/products" - "github.com/smartcontractkit/chainlink/devenv/products/directrequest" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestSmoke(t *testing.T) { - ctx := t.Context() - outputFile := "../../env-out.toml" - in, err := de.LoadOutput[de.Cfg](outputFile) - require.NoError(t, err) - productCfg, err := products.LoadOutput[directrequest.Configurator](outputFile) - require.NoError(t, err) - t.Cleanup(func() { - cleanupErr := products.CleanupContainerLogs(products.DefaultSettings()) - require.NoError(t, cleanupErr, "failed to process cleanup container logs") - }) - - c, auth, _, err := products.ETHClient( - ctx, - in.Blockchains[0].Out.Nodes[0].ExternalWSUrl, - productCfg.Config[0].GasSettings.FeeCapMultiplier, - productCfg.Config[0].GasSettings.TipCapMultiplier, - ) - require.NoError(t, err) - - consumer, err := test_api_consumer_wrapper.NewTestAPIConsumer(common.HexToAddress(productCfg.Config[0].Out.Consumer), c) - require.NoError(t, err) - - var jobIDBytes [32]byte - copy(jobIDBytes[:], []byte(productCfg.Config[0].Out.JobID)) - - tx, err := consumer.CreateRequestTo( - auth, - common.HexToAddress(productCfg.Config[0].Out.Oracle), - jobIDBytes, - big.NewInt(1e18), - in.FakeServer.Out.BaseURLDocker+"/direct_request_response", - "data,result", - big.NewInt(10), - ) - require.NoError(t, err) - _, err = products.WaitMinedFast(ctx, c, tx.Hash()) - require.NoError(t, err) - require.EventuallyWithT(t, func(c *assert.CollectT) { - d, err := consumer.Data(&bind.CallOpts{}) - assert.NoError(c, err) - assert.Equal(c, int64(200), d.Int64()) - }, 2*time.Minute, 2*time.Second) -} diff --git a/docs/CONFIG.md b/docs/CONFIG.md index d478556a668..a0fc285b285 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -987,20 +987,20 @@ MaxSize defines the maximum size for HTTP requests and responses made by `http` DefaultTransactionQueueDepth = 1 # Default SimulateTransactions = false # Default ``` - +Deprecated: FluxMonitor job type has been removed. These settings are accepted for backwards-compatible +config parsing only and have no effect. ### DefaultTransactionQueueDepth -:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ ```toml DefaultTransactionQueueDepth = 1 # Default ``` -DefaultTransactionQueueDepth controls the queue size for `DropOldestStrategy` in Flux Monitor. Set to 0 to use `SendEvery` strategy instead. +DefaultTransactionQueueDepth **DEPRECATED**: has no effect. The FluxMonitor job type has been removed. ### SimulateTransactions ```toml SimulateTransactions = false # Default ``` -SimulateTransactions enables transaction simulation for Flux Monitor. +SimulateTransactions **DEPRECATED**: has no effect. The FluxMonitor job type has been removed. ## OCR2 ```toml diff --git a/integration-tests/testconfig/testconfig_utils.go b/integration-tests/testconfig/testconfig_utils.go index 276c9f01f38..e9b50fc8330 100644 --- a/integration-tests/testconfig/testconfig_utils.go +++ b/integration-tests/testconfig/testconfig_utils.go @@ -51,7 +51,7 @@ Please refer to integration-tests/testconfig/README.md for more information. Or if you want to run your tests right now add following content to integration-tests/testconfig/overrides.toml: [Network] selected_networks=` - return fmt.Errorf("%s\n%s%s%s", errStr, intro, extraInfo, selectedNetworkStr) + return fmt.Errorf("%s\n%s%s%s", errStr, intro, extraInfo, selectedNetworkStr.String()) } return fmt.Errorf("%s\n%s", errStr, intro)