Skip to content

Commit

Permalink
Add p2pv2_bootstrappers field to OCR1 job spec (#6754)
Browse files Browse the repository at this point in the history
* peer_wrapper.go OCR1:  P2PV2_BOOTSTRAPPERS no longer required at startup

* services/ocr/delegate.go:  Update validation of v1 & v2 bootstrap peers

* Add p2pv2Bootstrappers field to OCR1 job spec

- Add corresponding p2pv2_bootstrappers column to ocr_oracle_specs table
- Update web / ui / presenter / resolver with new field
- Update tests

* Fix bug in develop branch which was causing several tests to fail with:

ERROR: null value in column "p2pv2_bootstrappers" of relation "ocr_oracle_specs" violates not-null constraint (SQLSTATE 23502)
  • Loading branch information
reductionista authored Jun 17, 2022
1 parent c476fa8 commit 0d622c9
Show file tree
Hide file tree
Showing 24 changed files with 133 additions and 28 deletions.
2 changes: 1 addition & 1 deletion core/cmd/remote_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ func TestClient_RunOCRJob_HappyPath(t *testing.T) {
err := toml.Unmarshal([]byte(ocrspec.Toml()), &jb)
require.NoError(t, err)
var ocrSpec job.OCROracleSpec
err = toml.Unmarshal([]byte(ocrspec.Toml()), &ocrspec)
err = toml.Unmarshal([]byte(ocrspec.Toml()), &ocrSpec)
require.NoError(t, err)
jb.OCROracleSpec = &ocrSpec
key, _ := cltest.MustInsertRandomKey(t, app.KeyStore.Eth())
Expand Down
6 changes: 6 additions & 0 deletions core/services/job/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ contractAddress = "%s"
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2Bootstrappers = []
isBootstrapPeer = false
keyBundleID = "%s"
monitoringEndpoint = "chain.link:4321"
Expand Down Expand Up @@ -98,6 +99,7 @@ p2pPeerID = "%s"
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2Bootstrappers = []
isBootstrapPeer = false
keyBundleID = "%s"
monitoringEndpoint = "chain.link:4321"
Expand Down Expand Up @@ -168,6 +170,7 @@ func compareOCRJobSpecs(t *testing.T, expected, actual job.Job) {
func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg config.GeneralConfig, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout string) *job.Job {
var ocrSpec = job.OCROracleSpec{
P2PBootstrapPeers: pq.StringArray{},
P2PV2Bootstrappers: pq.StringArray{},
ObservationTimeout: models.Interval(10 * time.Second),
BlockchainTimeout: models.Interval(20 * time.Second),
ContractConfigTrackerSubscribeInterval: models.Interval(2 * time.Minute),
Expand Down Expand Up @@ -226,6 +229,9 @@ func makeOCRJobSpecFromToml(t *testing.T, jobSpecToml string) *job.Job {
var ocrspec job.OCROracleSpec
err = toml.Unmarshal([]byte(jobSpecToml), &ocrspec)
require.NoError(t, err)
if ocrspec.P2PV2Bootstrappers == nil {
ocrspec.P2PV2Bootstrappers = pq.StringArray{}
}
jb.OCROracleSpec = &ocrspec

return &jb
Expand Down
2 changes: 2 additions & 0 deletions core/services/job/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ type OCROracleSpec struct {
ID int32 `toml:"-"`
ContractAddress ethkey.EIP55Address `toml:"contractAddress"`
P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers" db:"p2p_bootstrap_peers"`
P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"`
IsBootstrapPeer bool `toml:"isBootstrapPeer"`
EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"`
EncryptedOCRKeyBundleIDEnv bool
Expand Down Expand Up @@ -513,5 +514,6 @@ func (s BootstrapSpec) AsOCR2Spec() OCR2OracleSpec {
ContractConfigConfirmations: s.ContractConfigConfirmations,
CreatedAt: s.CreatedAt,
UpdatedAt: s.UpdatedAt,
P2PV2Bootstrappers: pq.StringArray{},
}
}
4 changes: 2 additions & 2 deletions core/services/job/orm.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,10 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error {
}
}

sql := `INSERT INTO ocr_oracle_specs (contract_address, p2p_bootstrap_peers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address,
sql := `INSERT INTO ocr_oracle_specs (contract_address, p2p_bootstrap_peers, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address,
observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, evm_chain_id,
created_at, updated_at, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout)
VALUES (:contract_address, :p2p_bootstrap_peers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address,
VALUES (:contract_address, :p2p_bootstrap_peers, :p2pv2_bootstrappers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address,
:observation_timeout, :blockchain_timeout, :contract_config_tracker_subscribe_interval, :contract_config_tracker_poll_interval, :contract_config_confirmations, :evm_chain_id,
NOW(), NOW(), :database_timeout, :observation_grace_period, :contract_transmitter_transmit_timeout)
RETURNING id;`
Expand Down
4 changes: 4 additions & 0 deletions core/services/job/runner_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"testing"
"time"

"github.com/smartcontractkit/libocr/commontypes"

evmconfigmocks "github.com/smartcontractkit/chainlink/core/chains/evm/config/mocks"
evmmocks "github.com/smartcontractkit/chainlink/core/chains/evm/mocks"
"github.com/smartcontractkit/chainlink/core/logger"
Expand Down Expand Up @@ -514,6 +516,7 @@ ds1 -> ds1_parse;
s = fmt.Sprintf(s, cltest.NewEIP55Address(), "http://blah.com", "")
tAddress := ethkey.EIP55AddressFromAddress(transmitterAddress)
config.Overrides.P2PBootstrapPeers = []string{"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", "/dns4/chain.link/tcp/1235/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"}
config.Overrides.P2PV2Bootstrappers = []commontypes.BootstrapperLocator{}
config.Overrides.OCRKeyBundleID = null.NewString(kb.ID(), true)
config.Overrides.OCRTransmitterAddress = &tAddress
jb, err := ocr.ValidatedOracleSpecToml(cc, s)
Expand Down Expand Up @@ -626,6 +629,7 @@ ds1 -> ds1_parse;

// Required to create job spawner delegate.
config.Overrides.P2PListenPort = null.IntFrom(2000)
config.Overrides.P2PV2Bootstrappers = []commontypes.BootstrapperLocator{}
lggr := logger.TestLogger(t)
pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config, db, lggr)
require.NoError(t, pw.Start(testutils.Context(t)))
Expand Down
28 changes: 21 additions & 7 deletions core/services/ocr/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,16 @@ func (d Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err er
}
}

// OCR1 job spec does not support overriding v2 bootstrap nodes, they must be set in env var
v2BootstrapPeers := chain.Config().P2PV2Bootstrappers()
v2Bootstrappers, err := ocrcommon.ParseBootstrapPeers(concreteSpec.P2PV2Bootstrappers)
if err != nil {
return nil, err
} else if len(v2Bootstrappers) == 0 {
// ParseBootstrapPeers() does not distinguish between no p2pv2Bootstrappers field
// present in job spec, and p2pv2Bootstrappers = []. So even if an empty list is
// passed explicitly, this will still fall back to using the V2 bootstappers defined
// in P2PV2_BOOTSTRAPPERS config var. Only a non-empty list will override the default list.
v2Bootstrappers = peerWrapper.Config().P2PV2Bootstrappers()
}

ocrLogger := logger.NewOCRWrapper(lggr, chain.Config().OCRTraceLogging(), func(msg string) {
d.jobORM.TryRecordError(jb.ID, msg)
Expand All @@ -160,7 +168,7 @@ func (d Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err er
bootstrapper, err = ocr.NewBootstrapNode(ocr.BootstrapNodeArgs{
BootstrapperFactory: peerWrapper.Peer,
V1Bootstrappers: v1BootstrapPeers,
V2Bootstrappers: v2BootstrapPeers,
V2Bootstrappers: v2Bootstrappers,
ContractConfigTracker: tracker,
Database: ocrDB,
LocalConfig: lc,
Expand All @@ -172,12 +180,18 @@ func (d Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err er
bootstrapperCtx := job.NewServiceAdapter(bootstrapper)
services = append(services, bootstrapperCtx)
} else {
if peerWrapper.Config().P2PNetworkingStack() == ocrnetworking.NetworkingStackV1 {
// In V1 or V1V2 mode, p2pv1BootstrapPeers must be defined either in
// node config or in job spec
if peerWrapper.Config().P2PNetworkingStack() != ocrnetworking.NetworkingStackV2 {
if len(v1BootstrapPeers) < 1 {
return nil, errors.New("Need at least one v1 bootstrap peer defined")
}
} else {
if len(v2BootstrapPeers) < 1 {
}

// In V1V2 or V2 mode, p2pv2Bootstrappers must be defined either in
// node config or in job spec
if peerWrapper.Config().P2PNetworkingStack() != ocrnetworking.NetworkingStackV1 {
if len(v2Bootstrappers) < 1 {
return nil, errors.New("Need at least one v2 bootstrap peer defined")
}
}
Expand Down Expand Up @@ -251,7 +265,7 @@ func (d Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err er
BinaryNetworkEndpointFactory: peerWrapper.Peer,
Logger: ocrLogger,
V1Bootstrappers: v1BootstrapPeers,
V2Bootstrappers: v2BootstrapPeers,
V2Bootstrappers: v2Bootstrappers,
MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(concreteSpec.ContractAddress.String()),
ConfigOverrider: configOverrider,
})
Expand Down
13 changes: 13 additions & 0 deletions core/services/ocr/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ocr
import (
"time"

"github.com/lib/pq"
"github.com/multiformats/go-multiaddr"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
Expand Down Expand Up @@ -52,6 +53,11 @@ func ValidatedOracleSpecToml(chainSet evm.ChainSet, tomlString string) (job.Job,
}
jb.OCROracleSpec = &spec

if jb.OCROracleSpec.P2PV2Bootstrappers == nil {
// Empty but non-null, field is non-nullable.
jb.OCROracleSpec.P2PV2Bootstrappers = pq.StringArray{}
}

if jb.Type != job.OffchainReporting {
return jb, errors.Errorf("the only supported type is currently 'offchainreporting', got %s", jb.Type)
}
Expand All @@ -64,6 +70,13 @@ func ValidatedOracleSpecToml(chainSet evm.ChainSet, tomlString string) (job.Job,
}
}

if len(spec.P2PV2Bootstrappers) > 0 {
_, err = ocrcommon.ParseBootstrapPeers(spec.P2PV2Bootstrappers)
if err != nil {
return jb, err
}
}

chain, err := chainSet.Get(jb.OCROracleSpec.EVMChainID.ToInt())
if err != nil {
return jb, err
Expand Down
38 changes: 33 additions & 5 deletions core/services/ocr/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/manyminds/api2go/jsonapi"
"github.com/smartcontractkit/chainlink/core/internal/testutils/configtest"
"github.com/smartcontractkit/chainlink/core/internal/testutils/evmtest"
"github.com/smartcontractkit/chainlink/core/services/job"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/guregu/null.v4"

"github.com/smartcontractkit/chainlink/core/internal/testutils/configtest"
"github.com/smartcontractkit/chainlink/core/internal/testutils/evmtest"
"github.com/smartcontractkit/chainlink/core/services/job"
)

func TestValidateOracleSpec(t *testing.T) {
Expand Down Expand Up @@ -155,7 +156,7 @@ observationSource = """
},
},
{
name: "invalid peer address",
name: "invalid v1 bootstrap peer address",
toml: `
type = "offchainreporting"
schemaVersion = 1
Expand All @@ -166,6 +167,26 @@ isBootstrapPeer = false
observationSource = """
blah
"""
`,
assertion: func(t *testing.T, os job.Job, err error) {
require.Error(t, err)
},
},
{
name: "invalid v2 bootstrapper address",
toml: `
type = "offchainreporting"
schemaVersion = 1
contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C"
p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq"
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2Bootstrappers = ["invalid bootstrapper /#@ address"]
isBootstrapPeer = false
observationSource = """
blah
"""
`,
assertion: func(t *testing.T, os job.Job, err error) {
require.Error(t, err)
Expand All @@ -179,6 +200,9 @@ schemaVersion = 1
contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C"
p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq"
p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"]
p2pv2Bootstrappers = [
"[email protected]:5001",
]
isBootstrapPeer = false
blockchainTimeout = "0s"
observationSource = """
Expand All @@ -197,6 +221,9 @@ schemaVersion = 1
contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C"
p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq"
p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"]
p2pv2Bootstrappers = [
"[email protected]:5001",
]
isBootstrapPeer = false
databaseTimeout = "0s"
observationSource = """
Expand Down Expand Up @@ -269,11 +296,12 @@ schemaVersion = 1
contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C"
p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq"
p2pBootstrapPeers = []
p2pv2Bootstrappers = []
isBootstrapPeer = true
monitoringEndpoint = "\t/fd\2ff )(*&^%$#@"
`,
assertion: func(t *testing.T, os job.Job, err error) {
require.EqualError(t, err, "toml error on load: (8, 23): invalid escape sequence: \\2")
require.EqualError(t, err, "toml error on load: (9, 23): invalid escape sequence: \\2")
},
},
{
Expand Down
10 changes: 0 additions & 10 deletions core/services/ocrcommon/peer_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,13 @@ func ValidatePeerWrapperConfig(config PeerWrapperConfig) error {
if len(config.P2PV2ListenAddresses()) == 0 {
return errors.New("networking stack v2 selected but no P2PV2_LISTEN_ADDRESSES specified")
}
// In V2 mode, OCR2 jobs don't need a default list of v2 bootstrappers, but OCR jobs do if enabled
// since there is no way to override it for them.
if config.FeatureOffchainReporting() && len(config.P2PV2Bootstrappers()) == 0 {
return errors.New("FEATURE_OFFCHAIN_REPORTING enabled in v2 networking mode, but no P2PV2Bootstrappers specified")
}
case ocrnetworking.NetworkingStackV1V2:
if config.P2PListenPort() == 0 {
return errors.New("networking stack v1v2 selected but no P2P_LISTEN_PORT specified")
}
if len(config.P2PV2ListenAddresses()) == 0 {
return errors.New("networking stack v1v2 selected but no P2PV2_LISTEN_ADDRESSES specified")
}
// Because there is no way to specify v2 bootstrappers in OCR jobs, we require they be set
// in the environment. v1 bootstrap peers can be specified either here or in the OCR jobspec
if len(config.P2PV2Bootstrappers()) == 0 {
return errors.New("networking stack v1v2 selected but no P2PV2Bootstrappers specified")
}
default:
return errors.New("unknown networking stack")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- +goose Up
ALTER TABLE ocr_oracle_specs
ADD COLUMN p2pv2_bootstrappers text[] NOT NULL DEFAULT '{}';

-- +goose Down
ALTER TABLE ocr_oracle_specs
DROP COLUMN p2pv2_bootstrappers;
1 change: 1 addition & 0 deletions core/testdata/testspecs/v2_specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ externalJobID = "%s"
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2Bootstrappers = []
isBootstrapPeer = false
keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5"
monitoringEndpoint = "chain.link:4321"
Expand Down
3 changes: 2 additions & 1 deletion core/testdata/tomlspecs/ocr-spec-local-test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ contractAddress = "0x934F3b67915BFbc98d5204122e0BE0ea69F91268"
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2BootstrapPeers = []
isBootstrapPeer = false
monitoringEndpoint = "test:101"
# Below graph will succeed to run through the pipeline
Expand All @@ -16,4 +17,4 @@ ds1->jp;
"""
keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5"
transmitterAddress= "0x2901c8E3BD2D219Ca3c8f4af2f119883b6155219"
p2pPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X"
p2pPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X"
2 changes: 1 addition & 1 deletion core/web/jobs_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication
err := toml.Unmarshal([]byte(ocrspec.Toml()), &jb)
require.NoError(t, err)
var ocrSpec job.OCROracleSpec
err = toml.Unmarshal([]byte(ocrspec.Toml()), &ocrspec)
err = toml.Unmarshal([]byte(ocrspec.Toml()), &ocrSpec)
require.NoError(t, err)
jb.OCROracleSpec = &ocrSpec
jb.OCROracleSpec.TransmitterAddress = &app.Key.Address
Expand Down
1 change: 1 addition & 0 deletions core/web/pipeline_runs_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i
p2pBootstrapPeers = [
"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju",
]
p2pv2Bootstrappers = []
keyBundleID = "%s"
transmitterAddress = "%s"
observationSource = """
Expand Down
2 changes: 2 additions & 0 deletions core/web/presenters/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec {
type OffChainReportingSpec struct {
ContractAddress ethkey.EIP55Address `json:"contractAddress"`
P2PBootstrapPeers pq.StringArray `json:"p2pBootstrapPeers"`
P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"`
IsBootstrapPeer bool `json:"isBootstrapPeer"`
EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"`
TransmitterAddress *ethkey.EIP55Address `json:"transmitterAddress"`
Expand Down Expand Up @@ -150,6 +151,7 @@ func NewOffChainReportingSpec(spec *job.OCROracleSpec) *OffChainReportingSpec {
return &OffChainReportingSpec{
ContractAddress: spec.ContractAddress,
P2PBootstrapPeers: spec.P2PBootstrapPeers,
P2PV2Bootstrappers: spec.P2PV2Bootstrappers,
IsBootstrapPeer: spec.IsBootstrapPeer,
EncryptedOCRKeyBundleID: spec.EncryptedOCRKeyBundleID,
TransmitterAddress: spec.TransmitterAddress,
Expand Down
2 changes: 2 additions & 0 deletions core/web/presenters/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ func TestJob(t *testing.T) {
OCROracleSpec: &job.OCROracleSpec{
ContractAddress: contractAddress,
P2PBootstrapPeers: pq.StringArray{"/dns4/chain.link/tcp/1234/p2p/xxx"},
P2PV2Bootstrappers: pq.StringArray{"xxx:5001"},
IsBootstrapPeer: true,
EncryptedOCRKeyBundleID: &ocrKeyID,
TransmitterAddress: &transmitterAddress,
Expand Down Expand Up @@ -233,6 +234,7 @@ func TestJob(t *testing.T) {
"offChainReportingOracleSpec": {
"contractAddress": "%s",
"p2pBootstrapPeers": ["/dns4/chain.link/tcp/1234/p2p/xxx"],
"p2pv2Bootstrappers": ["xxx:5001"],
"isBootstrapPeer": true,
"keyBundleID": "%s",
"transmitterAddress": "%s",
Expand Down
1 change: 1 addition & 0 deletions core/web/resolver/job_proposal_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package resolver
import (
"github.com/graph-gophers/graphql-go"
"github.com/pkg/errors"

"github.com/smartcontractkit/chainlink/core/services/feeds"
)

Expand Down
Loading

0 comments on commit 0d622c9

Please sign in to comment.