From 6350464ac037032df227bd5628f0aca015a76a71 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 6 Jul 2021 20:34:56 +0100 Subject: [PATCH] Implement networking V2 for libocr (#4597) --- core/internal/cltest/cltest.go | 14 + core/services/offchainreporting/delegate.go | 6 +- .../offchainreporting/discoverer_database.go | 62 ++++ .../discoverer_database_test.go | 83 +++++ .../offchainreporting/peer_wrapper.go | 28 +- ...44_create_table_ocr_discoverer_database.go | 31 ++ core/store/orm/config.go | 68 +++- core/store/orm/schema.go | 297 +++++++++--------- core/store/orm/schema_test.go | 11 +- core/store/presenters/presenters.go | 20 +- docs/CHANGELOG.md | 15 + go.mod | 2 +- go.sum | 4 +- 13 files changed, 476 insertions(+), 165 deletions(-) create mode 100644 core/services/offchainreporting/discoverer_database.go create mode 100644 core/services/offchainreporting/discoverer_database_test.go create mode 100644 core/store/migrations/0044_create_table_ocr_discoverer_database.go diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index a45b5ee5e9a..081e2fc6c3a 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -33,6 +33,7 @@ import ( "github.com/smartcontractkit/chainlink/core/static" "github.com/smartcontractkit/chainlink/core/store/dialects" + cryptop2p "github.com/libp2p/go-libp2p-core/crypto" p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/smartcontractkit/chainlink/core/assets" "github.com/smartcontractkit/chainlink/core/auth" @@ -119,6 +120,7 @@ var ( FluxAggAddress = common.HexToAddress("0x3cCad4715152693fE3BC4460591e3D3Fbd071b42") storeCounter uint64 minimumContractPayment = assets.NewLink(100) + source rand.Source ) func init() { @@ -154,6 +156,9 @@ func init() { logger.Debugf("Using seed: %v", seed) rand.Seed(seed) + // Also seed the local source + source = rand.NewSource(seed) + defaultP2PPeerID, err := p2ppeer.Decode(DefaultPeerID) if err != nil { panic(err) @@ -2120,3 +2125,12 @@ func MustSendingKeys(t *testing.T, ethKeyStore *keystore.Eth) (keys []ethkey.Key require.NoError(t, err) return keys } + +func MustRandomP2PPeerID(t *testing.T) p2ppeer.ID { + reader := rand.New(source) + p2pPrivkey, _, err := cryptop2p.GenerateEd25519Key(reader) + require.NoError(t, err) + id, err := p2ppeer.IDFromPrivateKey(p2pPrivkey) + require.NoError(t, err) + return id +} diff --git a/core/services/offchainreporting/delegate.go b/core/services/offchainreporting/delegate.go index d96391dd221..99999405eec 100644 --- a/core/services/offchainreporting/delegate.go +++ b/core/services/offchainreporting/delegate.go @@ -138,6 +138,7 @@ func (d Delegate) ServicesForSpec(jobSpec job.Job) (services []job.Service, err if err != nil { return nil, err } + v2BootstrapPeers := d.config.P2PV2Bootstrappers() loggerWith := logger.CreateLogger(logger.Default.With( "contractAddress", concreteSpec.ContractAddress, @@ -171,7 +172,7 @@ func (d Delegate) ServicesForSpec(jobSpec job.Job) (services []job.Service, err if concreteSpec.IsBootstrapPeer { bootstrapper, err := ocr.NewBootstrapNode(ocr.BootstrapNodeArgs{ BootstrapperFactory: peerWrapper.Peer, - Bootstrappers: bootstrapPeers, + V1Bootstrappers: bootstrapPeers, ContractConfigTracker: tracker, Database: ocrdb, LocalConfig: lc, @@ -233,7 +234,8 @@ func (d Delegate) ServicesForSpec(jobSpec job.Job) (services []job.Service, err PrivateKeys: &ocrkey, BinaryNetworkEndpointFactory: peerWrapper.Peer, Logger: ocrLogger, - Bootstrappers: bootstrapPeers, + V1Bootstrappers: bootstrapPeers, + V2Bootstrappers: v2BootstrapPeers, MonitoringEndpoint: d.monitoringEndpoint, }) if err != nil { diff --git a/core/services/offchainreporting/discoverer_database.go b/core/services/offchainreporting/discoverer_database.go new file mode 100644 index 00000000000..0410edcd7c4 --- /dev/null +++ b/core/services/offchainreporting/discoverer_database.go @@ -0,0 +1,62 @@ +package offchainreporting + +import ( + "context" + "database/sql" + + "github.com/lib/pq" + p2ppeer "github.com/libp2p/go-libp2p-core/peer" + "github.com/pkg/errors" + ocrnetworking "github.com/smartcontractkit/libocr/networking" + "go.uber.org/multierr" +) + +var _ ocrnetworking.DiscovererDatabase = &DiscovererDatabase{} + +type DiscovererDatabase struct { + db *sql.DB + peerID string +} + +func NewDiscovererDatabase(db *sql.DB, peerID p2ppeer.ID) *DiscovererDatabase { + return &DiscovererDatabase{ + db, + peerID.Pretty(), + } +} + +// StoreAnnouncement has key-value-store semantics and stores a peerID (key) and an associated serialized +// announcement (value). +func (d *DiscovererDatabase) StoreAnnouncement(ctx context.Context, peerID string, ann []byte) error { + _, err := d.db.ExecContext(ctx, ` +INSERT INTO offchainreporting_discoverer_announcements (local_peer_id, remote_peer_id, ann, created_at, updated_at) +VALUES ($1,$2,$3,NOW(),NOW()) ON CONFLICT (local_peer_id, remote_peer_id) DO UPDATE SET +ann = EXCLUDED.ann, +updated_at = EXCLUDED.updated_at +;`, d.peerID, peerID, ann) + return errors.Wrap(err, "DiscovererDatabase failed to StoreAnnouncement") +} + +// ReadAnnouncements returns one serialized announcement (if available) for each of the peerIDs in the form of a map +// keyed by each announcement's corresponding peer ID. +func (d *DiscovererDatabase) ReadAnnouncements(ctx context.Context, peerIDs []string) (map[string][]byte, error) { + rows, err := d.db.QueryContext(ctx, ` +SELECT remote_peer_id, ann FROM offchainreporting_discoverer_announcements WHERE remote_peer_id = ANY($1) AND local_peer_id = $2`, pq.Array(peerIDs), d.peerID) + if err != nil { + return nil, errors.Wrap(err, "DiscovererDatabase failed to ReadAnnouncements") + } + results := make(map[string][]byte) + for rows.Next() { + var peerID string + var ann []byte + err := rows.Scan(&peerID, &ann) + if err != nil { + return nil, multierr.Combine(err, rows.Close()) + } + results[peerID] = ann + } + if err := rows.Close(); err != nil { + return nil, errors.WithStack(err) + } + return results, nil +} diff --git a/core/services/offchainreporting/discoverer_database_test.go b/core/services/offchainreporting/discoverer_database_test.go new file mode 100644 index 00000000000..908a874bc89 --- /dev/null +++ b/core/services/offchainreporting/discoverer_database_test.go @@ -0,0 +1,83 @@ +package offchainreporting_test + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/core/internal/cltest" + "github.com/smartcontractkit/chainlink/core/services/offchainreporting" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_DiscovererDatabase(t *testing.T) { + store, cleanup := cltest.NewStore(t) + defer cleanup() + + db := store.DB + require.NoError(t, db.Exec(`SET CONSTRAINTS offchainreporting_discoverer_announcements_local_peer_id_fkey DEFERRED`).Error) + + sqlDB := store.MustSQLDB() + + localPeerID1 := cltest.MustRandomP2PPeerID(t) + localPeerID2 := cltest.MustRandomP2PPeerID(t) + + dd1 := offchainreporting.NewDiscovererDatabase(sqlDB, localPeerID1) + dd2 := offchainreporting.NewDiscovererDatabase(sqlDB, localPeerID2) + + t.Run("StoreAnnouncement writes a value", func(t *testing.T) { + ann := []byte{1, 2, 3} + err := dd1.StoreAnnouncement(ctx, "remote1", ann) + assert.NoError(t, err) + + // test upsert + ann = []byte{4, 5, 6} + err = dd1.StoreAnnouncement(ctx, "remote1", ann) + assert.NoError(t, err) + + // write a different value + ann = []byte{7, 8, 9} + err = dd1.StoreAnnouncement(ctx, "remote2", ann) + assert.NoError(t, err) + }) + + t.Run("ReadAnnouncements reads values filtered by given peerIDs", func(t *testing.T) { + announcements, err := dd1.ReadAnnouncements(ctx, []string{"remote1", "remote2"}) + require.NoError(t, err) + + assert.Len(t, announcements, 2) + assert.Equal(t, []byte{4, 5, 6}, announcements["remote1"]) + assert.Equal(t, []byte{7, 8, 9}, announcements["remote2"]) + + announcements, err = dd1.ReadAnnouncements(ctx, []string{"remote1"}) + require.NoError(t, err) + + assert.Len(t, announcements, 1) + assert.Equal(t, []byte{4, 5, 6}, announcements["remote1"]) + }) + + t.Run("is scoped to local peer ID", func(t *testing.T) { + ann := []byte{10, 11, 12} + err := dd2.StoreAnnouncement(ctx, "remote1", ann) + assert.NoError(t, err) + + announcements, err := dd2.ReadAnnouncements(ctx, []string{"remote1"}) + require.NoError(t, err) + assert.Len(t, announcements, 1) + assert.Equal(t, []byte{10, 11, 12}, announcements["remote1"]) + + announcements, err = dd1.ReadAnnouncements(ctx, []string{"remote1"}) + require.NoError(t, err) + assert.Len(t, announcements, 1) + assert.Equal(t, []byte{4, 5, 6}, announcements["remote1"]) + }) + + t.Run("persists data across restarts", func(t *testing.T) { + dd3 := offchainreporting.NewDiscovererDatabase(sqlDB, localPeerID1) + + announcements, err := dd3.ReadAnnouncements(ctx, []string{"remote1"}) + require.NoError(t, err) + assert.Len(t, announcements, 1) + assert.Equal(t, []byte{4, 5, 6}, announcements["remote1"]) + + }) +} diff --git a/core/services/offchainreporting/peer_wrapper.go b/core/services/offchainreporting/peer_wrapper.go index 96d8a7ce324..721b2f17cd7 100644 --- a/core/services/offchainreporting/peer_wrapper.go +++ b/core/services/offchainreporting/peer_wrapper.go @@ -3,6 +3,7 @@ package offchainreporting import ( "strings" + p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/core/logger" "github.com/smartcontractkit/chainlink/core/services/keystore" @@ -99,6 +100,11 @@ func (p *SingletonPeerWrapper) Start() error { if err != nil { return errors.Wrap(err, "could not make new pstorewrapper") } + sqlDB, err := p.db.DB() + if err != nil { + return err + } + discovererDB := NewDiscovererDatabase(sqlDB, p2ppeer.ID(p.PeerID)) // If the P2PAnnounceIP is set we must also set the P2PAnnouncePort // Fallback to P2PListenPort if it wasn't made explicit @@ -112,13 +118,19 @@ func (p *SingletonPeerWrapper) Start() error { peerLogger := NewLogger(logger.Default, p.config.OCRTraceLogging(), func(string) {}) p.Peer, err = ocrnetworking.NewPeer(ocrnetworking.PeerConfig{ - PrivKey: key.PrivKey, - ListenIP: p.config.P2PListenIP(), - ListenPort: listenPort, - AnnounceIP: p.config.P2PAnnounceIP(), - AnnouncePort: announcePort, - Logger: peerLogger, - Peerstore: p.pstoreWrapper.Peerstore, + NetworkingStack: p.config.P2PNetworkingStack(), + PrivKey: key.PrivKey, + V1ListenIP: p.config.P2PListenIP(), + V1ListenPort: listenPort, + V1AnnounceIP: p.config.P2PAnnounceIP(), + V1AnnouncePort: announcePort, + Logger: peerLogger, + V1Peerstore: p.pstoreWrapper.Peerstore, + V2ListenAddresses: p.config.P2PV2ListenAddresses(), + V2AnnounceAddresses: p.config.P2PV2AnnounceAddresses(), + V2DeltaReconcile: p.config.P2PV2DeltaReconcile().Duration(), + V2DeltaDial: p.config.P2PV2DeltaDial().Duration(), + V2DiscovererDatabase: discovererDB, EndpointConfig: ocrnetworking.EndpointConfig{ IncomingMessageBufferSize: p.config.OCRIncomingMessageBufferSize(), OutgoingMessageBufferSize: p.config.OCROutgoingMessageBufferSize(), @@ -126,7 +138,7 @@ func (p *SingletonPeerWrapper) Start() error { DHTLookupInterval: p.config.OCRDHTLookupInterval(), BootstrapCheckInterval: p.config.OCRBootstrapCheckInterval(), }, - DHTAnnouncementCounterUserPrefix: p.config.P2PDHTAnnouncementCounterUserPrefix(), + V1DHTAnnouncementCounterUserPrefix: p.config.P2PDHTAnnouncementCounterUserPrefix(), }) if err != nil { return errors.Wrap(err, "error calling NewPeer") diff --git a/core/store/migrations/0044_create_table_ocr_discoverer_database.go b/core/store/migrations/0044_create_table_ocr_discoverer_database.go new file mode 100644 index 00000000000..b06d159318a --- /dev/null +++ b/core/store/migrations/0044_create_table_ocr_discoverer_database.go @@ -0,0 +1,31 @@ +package migrations + +import ( + "gorm.io/gorm" +) + +const up44 = ` +CREATE TABLE offchainreporting_discoverer_announcements ( + local_peer_id text NOT NULL REFERENCES encrypted_p2p_keys (peer_id) DEFERRABLE INITIALLY IMMEDIATE, + remote_peer_id text NOT NULL, + ann bytea NOT NULL, + created_at timestamptz not null, + updated_at timestamptz not null, + PRIMARY KEY(local_peer_id, remote_peer_id) +); +` +const down44 = ` +DROP TABLE offchainreporting_discoverer_announcements; +` + +func init() { + Migrations = append(Migrations, &Migration{ + ID: "0044_create_table_offchainreporting_discoverer_announcements", + Migrate: func(db *gorm.DB) error { + return db.Exec(up44).Error + }, + Rollback: func(db *gorm.DB) error { + return db.Exec(down44).Error + }, + }) +} diff --git a/core/store/orm/config.go b/core/store/orm/config.go index c4c455a9f06..00e2674e1c0 100644 --- a/core/store/orm/config.go +++ b/core/store/orm/config.go @@ -28,6 +28,7 @@ import ( "github.com/multiformats/go-multiaddr" + ocrnetworking "github.com/smartcontractkit/libocr/networking" ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -1357,6 +1358,71 @@ func (c Config) P2PBootstrapPeers(override []string) ([]string, error) { return []string{}, nil } +// P2PNetworkingStack returns the preferred networking stack for libocr +func (c Config) P2PNetworkingStack() (n ocrnetworking.NetworkingStack) { + str := c.P2PNetworkingStackRaw() + err := n.UnmarshalText([]byte(str)) + if err != nil { + logger.Fatalf("P2PNetworkingStack failed to unmarshal '%s': %s", str, err) + } + return n +} + +// P2PNetworkingStackRaw returns the raw string passed as networking stack +func (c Config) P2PNetworkingStackRaw() string { + return c.viper.GetString(EnvVarName("P2PNetworkingStack")) +} + +// P2PV2ListenAddresses contains the addresses the peer will listen to on the network in : form as +// accepted by net.Listen, but host and port must be fully specified and cannot be empty. +func (c Config) P2PV2ListenAddresses() []string { + return c.viper.GetStringSlice(EnvVarName("P2PV2ListenAddresses")) +} + +// P2PV2AnnounceAddresses contains the addresses the peer will advertise on the network in : form as +// accepted by net.Dial. The addresses should be reachable by peers of interest. +func (c Config) P2PV2AnnounceAddresses() []string { + if c.viper.IsSet(EnvVarName("P2PV2AnnounceAddresses")) { + return c.viper.GetStringSlice(EnvVarName("P2PV2AnnounceAddresses")) + } + return c.P2PV2ListenAddresses() +} + +// P2PV2AnnounceAddressesRaw returns the raw value passed in +func (c Config) P2PV2AnnounceAddressesRaw() []string { + return c.viper.GetStringSlice(EnvVarName("P2PV2AnnounceAddresses")) +} + +// P2PV2Bootstrappers returns the default bootstrapper peers for libocr's v2 +// networking stack +func (c Config) P2PV2Bootstrappers() (locators []ocrtypes.BootstrapperLocator) { + bootstrappers := c.P2PV2BootstrappersRaw() + for _, s := range bootstrappers { + var locator ocrtypes.BootstrapperLocator + err := locator.UnmarshalText([]byte(s)) + if err != nil { + logger.Fatalf("invalid format for bootstrapper '%s', got error: %s", s, err) + } + locators = append(locators, locator) + } + return +} + +// P2PV2BootstrappersRaw returns the raw strings for v2 bootstrap peers +func (c Config) P2PV2BootstrappersRaw() []string { + return c.viper.GetStringSlice(EnvVarName("P2PV2Bootstrappers")) +} + +// P2PV2DeltaDial controls how far apart Dial attempts are +func (c Config) P2PV2DeltaDial() models.Duration { + return models.MustMakeDuration(c.getWithFallback("P2PV2DeltaDial", parseDuration).(time.Duration)) +} + +// P2PV2DeltaReconcile controls how often a Reconcile message is sent to every peer. +func (c Config) P2PV2DeltaReconcile() models.Duration { + return models.MustMakeDuration(c.getWithFallback("P2PV2DeltaReconcile", parseDuration).(time.Duration)) +} + // Port represents the port Chainlink should listen on for client requests. func (c Config) Port() uint16 { return c.getWithFallback("Port", parseUint16).(uint16) @@ -1498,7 +1564,7 @@ func (c Config) getWithFallback(name string, parser func(string) (interface{}, e v, err := parser(defaultValue) if err != nil { - log.Fatalf(fmt.Sprintf(`Invalid default for %s: "%s"`, name, defaultValue)) + log.Fatalf(`Invalid default for %s: "%s" (%s)`, name, defaultValue, err) } return v } diff --git a/core/store/orm/schema.go b/core/store/orm/schema.go index e5df1adc7e3..85962cc78ad 100644 --- a/core/store/orm/schema.go +++ b/core/store/orm/schema.go @@ -12,155 +12,162 @@ import ( "github.com/smartcontractkit/chainlink/core/assets" "github.com/smartcontractkit/chainlink/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/core/store/models" + ocrnetworking "github.com/smartcontractkit/libocr/networking" ) // ConfigSchema records the schema of configuration at the type level type ConfigSchema struct { - AdminCredentialsFile string `env:"ADMIN_CREDENTIALS_FILE" default:"$ROOT/apicredentials"` - AllowOrigins string `env:"ALLOW_ORIGINS" default:"http://localhost:3000,http://localhost:6688"` - AuthenticatedRateLimit int64 `env:"AUTHENTICATED_RATE_LIMIT" default:"1000"` - AuthenticatedRateLimitPeriod time.Duration `env:"AUTHENTICATED_RATE_LIMIT_PERIOD" default:"1m"` - BalanceMonitorEnabled bool `env:"BALANCE_MONITOR_ENABLED" default:"true"` - BlockBackfillDepth string `env:"BLOCK_BACKFILL_DEPTH" default:"10"` - BlockHistoryEstimatorBatchSize uint32 `env:"BLOCK_HISTORY_ESTIMATOR_BATCH_SIZE"` - BlockHistoryEstimatorBlockDelay uint16 `env:"BLOCK_HISTORY_ESTIMATOR_BLOCK_DELAY"` - BlockHistoryEstimatorBlockHistorySize uint16 `env:"BLOCK_HISTORY_ESTIMATOR_BLOCK_HISTORY_SIZE"` - BlockHistoryEstimatorTransactionPercentile uint16 `env:"BLOCK_HISTORY_ESTIMATOR_TRANSACTION_PERCENTILE" default:"60"` - BridgeResponseURL url.URL `env:"BRIDGE_RESPONSE_URL"` - ChainID big.Int `env:"ETH_CHAIN_ID" default:"1"` - ClientNodeURL string `env:"CLIENT_NODE_URL" default:"http://localhost:6688"` - DatabaseBackupDir string `env:"DATABASE_BACKUP_DIR" default:""` - DatabaseBackupFrequency time.Duration `env:"DATABASE_BACKUP_FREQUENCY" default:"1h"` - DatabaseBackupMode string `env:"DATABASE_BACKUP_MODE" default:"none"` - DatabaseBackupURL *url.URL `env:"DATABASE_BACKUP_URL" default:""` - DatabaseListenerMaxReconnectDuration time.Duration `env:"DATABASE_LISTENER_MAX_RECONNECT_DURATION" default:"10m"` - DatabaseListenerMinReconnectInterval time.Duration `env:"DATABASE_LISTENER_MIN_RECONNECT_INTERVAL" default:"1m"` - DatabaseMaximumTxDuration time.Duration `env:"DATABASE_MAXIMUM_TX_DURATION" default:"30m"` - DatabaseTimeout models.Duration `env:"DATABASE_TIMEOUT" default:"0"` - DatabaseURL string `env:"DATABASE_URL"` - DefaultHTTPAllowUnrestrictedNetworkAccess bool `env:"DEFAULT_HTTP_ALLOW_UNRESTRICTED_NETWORK_ACCESS" default:"false"` - DefaultHTTPLimit int64 `env:"DEFAULT_HTTP_LIMIT" default:"32768"` - DefaultHTTPTimeout models.Duration `env:"DEFAULT_HTTP_TIMEOUT" default:"15s"` - DefaultMaxHTTPAttempts uint `env:"MAX_HTTP_ATTEMPTS" default:"5"` - Dev bool `env:"CHAINLINK_DEV" default:"false"` - EnableExperimentalAdapters bool `env:"ENABLE_EXPERIMENTAL_ADAPTERS" default:"false"` - EnableLegacyJobPipeline bool `env:"ENABLE_LEGACY_JOB_PIPELINE" default:"true"` - EthBalanceMonitorBlockDelay uint16 `env:"ETH_BALANCE_MONITOR_BLOCK_DELAY"` - EthFinalityDepth uint `env:"ETH_FINALITY_DEPTH"` - EthGasBumpPercent uint16 `env:"ETH_GAS_BUMP_PERCENT" default:"20"` - EthGasBumpThreshold uint64 `env:"ETH_GAS_BUMP_THRESHOLD"` - EthGasBumpTxDepth uint16 `env:"ETH_GAS_BUMP_TX_DEPTH" default:"10"` - EthGasBumpWei big.Int `env:"ETH_GAS_BUMP_WEI"` - EthGasLimitDefault uint64 `env:"ETH_GAS_LIMIT_DEFAULT"` - EthGasLimitMultiplier float32 `env:"ETH_GAS_LIMIT_MULTIPLIER" default:"1.0"` - EthGasLimitTransfer uint64 `env:"ETH_GAS_LIMIT_TRANSFER"` - EthGasPriceDefault big.Int `env:"ETH_GAS_PRICE_DEFAULT"` - EthHeadTrackerHistoryDepth uint `env:"ETH_HEAD_TRACKER_HISTORY_DEPTH"` - EthHeadTrackerMaxBufferSize uint `env:"ETH_HEAD_TRACKER_MAX_BUFFER_SIZE" default:"3"` - EthHeadTrackerSamplingInterval time.Duration `env:"ETH_HEAD_TRACKER_SAMPLING_INTERVAL" default:"1s"` - EthLogBackfillBatchSize uint32 `env:"ETH_LOG_BACKFILL_BATCH_SIZE" default:"100"` - EthMaxGasPriceWei big.Int `env:"ETH_MAX_GAS_PRICE_WEI"` - EthMaxInFlightTransactions uint64 `env:"ETH_MAX_IN_FLIGHT_TRANSACTIONS"` - EthMaxQueuedTransactions uint64 `env:"ETH_MAX_QUEUED_TRANSACTIONS"` - EthMinGasPriceWei big.Int `env:"ETH_MIN_GAS_PRICE_WEI"` - EthNonceAutoSync bool `env:"ETH_NONCE_AUTO_SYNC" default:"true"` - EthRPCDefaultBatchSize uint32 `env:"ETH_RPC_DEFAULT_BATCH_SIZE" default:"100"` - EthTxReaperInterval time.Duration `env:"ETH_TX_REAPER_INTERVAL" default:"1h"` - EthTxReaperThreshold time.Duration `env:"ETH_TX_REAPER_THRESHOLD" default:"168h"` - EthTxResendAfterThreshold time.Duration `env:"ETH_TX_RESEND_AFTER_THRESHOLD"` - EthereumDisabled bool `env:"ETH_DISABLED" default:"false"` - EthereumHTTPURL string `env:"ETH_HTTP_URL"` - EthereumSecondaryURL string `env:"ETH_SECONDARY_URL" default:""` - EthereumSecondaryURLs string `env:"ETH_SECONDARY_URLS" default:""` - EthereumURL string `env:"ETH_URL" default:"ws://localhost:8546"` - ExplorerAccessKey string `env:"EXPLORER_ACCESS_KEY"` - ExplorerSecret string `env:"EXPLORER_SECRET"` - ExplorerURL *url.URL `env:"EXPLORER_URL"` - FMDefaultTransactionQueueDepth uint32 `env:"FM_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` - FeatureCronV2 bool `env:"FEATURE_CRON_V2" default:"true"` - FeatureExternalInitiators bool `env:"FEATURE_EXTERNAL_INITIATORS" default:"false"` - FeatureFluxMonitor bool `env:"FEATURE_FLUX_MONITOR" default:"true"` - FeatureFluxMonitorV2 bool `env:"FEATURE_FLUX_MONITOR_V2" default:"true"` - FeatureOffchainReporting bool `env:"FEATURE_OFFCHAIN_REPORTING" default:"false"` - FeatureWebhookV2 bool `env:"FEATURE_WEBHOOK_V2" default:"false"` - FlagsContractAddress string `env:"FLAGS_CONTRACT_ADDRESS"` - GasEstimatorMode string `env:"GAS_ESTIMATOR_MODE"` - GasUpdaterBatchSize uint32 `env:"GAS_UPDATER_BATCH_SIZE"` - GasUpdaterBlockDelay uint16 `env:"GAS_UPDATER_BLOCK_DELAY"` - GasUpdaterBlockHistorySize uint16 `env:"GAS_UPDATER_BLOCK_HISTORY_SIZE"` - GasUpdaterEnabled bool `env:"GAS_UPDATER_ENABLED"` - GasUpdaterTransactionPercentile uint16 `env:"GAS_UPDATER_TRANSACTION_PERCENTILE" default:"60"` - GlobalLockRetryInterval models.Duration `env:"GLOBAL_LOCK_RETRY_INTERVAL" default:"1s"` - HTTPServerWriteTimeout time.Duration `env:"HTTP_SERVER_WRITE_TIMEOUT" default:"10s"` - InsecureFastScrypt bool `env:"INSECURE_FAST_SCRYPT" default:"false"` - InsecureSkipVerify bool `env:"INSECURE_SKIP_VERIFY" default:"false"` - JSONConsole bool `env:"JSON_CONSOLE" default:"false"` - JobPipelineMaxRunDuration time.Duration `env:"JOB_PIPELINE_MAX_RUN_DURATION" default:"10m"` - JobPipelineReaperInterval time.Duration `env:"JOB_PIPELINE_REAPER_INTERVAL" default:"1h"` - JobPipelineReaperThreshold time.Duration `env:"JOB_PIPELINE_REAPER_THRESHOLD" default:"24h"` - JobPipelineResultWriteQueueDepth uint64 `env:"JOB_PIPELINE_RESULT_WRITE_QUEUE_DEPTH" default:"100"` - KeeperDefaultTransactionQueueDepth uint32 `env:"KEEPER_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` - KeeperMaximumGracePeriod int64 `env:"KEEPER_MAXIMUM_GRACE_PERIOD" default:"100"` - KeeperMinimumRequiredConfirmations uint64 `env:"KEEPER_MINIMUM_REQUIRED_CONFIRMATIONS" default:"12"` - KeeperRegistryCheckGasOverhead uint64 `env:"KEEPER_REGISTRY_CHECK_GAS_OVERHEAD" default:"200000"` - KeeperRegistryPerformGasOverhead uint64 `env:"KEEPER_REGISTRY_PERFORM_GAS_OVERHEAD" default:"150000"` - KeeperRegistrySyncInterval time.Duration `env:"KEEPER_REGISTRY_SYNC_INTERVAL" default:"30m"` - LinkContractAddress string `env:"LINK_CONTRACT_ADDRESS"` - LogLevel LogLevel `env:"LOG_LEVEL" default:"info"` - LogSQLMigrations bool `env:"LOG_SQL_MIGRATIONS" default:"true"` - LogSQLStatements bool `env:"LOG_SQL" default:"false"` - LogToDisk bool `env:"LOG_TO_DISK" default:"true"` - MaximumServiceDuration models.Duration `env:"MAXIMUM_SERVICE_DURATION" default:"8760h" ` - MigrateDatabase bool `env:"MIGRATE_DATABASE" default:"true"` - MinIncomingConfirmations uint32 `env:"MIN_INCOMING_CONFIRMATIONS"` - MinRequiredOutgoingConfirmations uint64 `env:"MIN_OUTGOING_CONFIRMATIONS"` - MinimumContractPayment assets.Link `env:"MINIMUM_CONTRACT_PAYMENT_LINK_JUELS"` - MinimumRequestExpiration uint64 `env:"MINIMUM_REQUEST_EXPIRATION" default:"300"` - MinimumServiceDuration models.Duration `env:"MINIMUM_SERVICE_DURATION" default:"0s" ` - OCRBlockchainTimeout time.Duration `env:"OCR_BLOCKCHAIN_TIMEOUT" default:"20s"` - OCRBootstrapCheckInterval time.Duration `env:"OCR_BOOTSTRAP_CHECK_INTERVAL" default:"20s"` - OCRContractConfirmations uint `env:"OCR_CONTRACT_CONFIRMATIONS"` - OCRContractPollInterval time.Duration `env:"OCR_CONTRACT_POLL_INTERVAL" default:"1m"` - OCRContractSubscribeInterval time.Duration `env:"OCR_CONTRACT_SUBSCRIBE_INTERVAL" default:"2m"` - OCRContractTransmitterTransmitTimeout time.Duration `env:"OCR_CONTRACT_TRANSMITTER_TRANSMIT_TIMEOUT" default:"10s"` - OCRDHTLookupInterval int `env:"OCR_DHT_LOOKUP_INTERVAL" default:"10"` - OCRDatabaseTimeout time.Duration `env:"OCR_DATABASE_TIMEOUT" default:"10s"` - OCRDefaultTransactionQueueDepth uint32 `env:"OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` - OCRIncomingMessageBufferSize int `env:"OCR_INCOMING_MESSAGE_BUFFER_SIZE" default:"10"` - OCRKeyBundleID string `env:"OCR_KEY_BUNDLE_ID"` - OCRMonitoringEndpoint string `env:"OCR_MONITORING_ENDPOINT"` - OCRNewStreamTimeout time.Duration `env:"OCR_NEW_STREAM_TIMEOUT" default:"10s"` - OCRObservationGracePeriod time.Duration `env:"OCR_OBSERVATION_GRACE_PERIOD" default:"1s"` - OCRObservationTimeout time.Duration `env:"OCR_OBSERVATION_TIMEOUT" default:"12s"` - OCROutgoingMessageBufferSize int `env:"OCR_OUTGOING_MESSAGE_BUFFER_SIZE" default:"10"` - OCRTraceLogging bool `env:"OCR_TRACE_LOGGING" default:"false"` - OCRTransmitterAddress string `env:"OCR_TRANSMITTER_ADDRESS"` - ORMMaxIdleConns int `env:"ORM_MAX_IDLE_CONNS" default:"10"` - ORMMaxOpenConns int `env:"ORM_MAX_OPEN_CONNS" default:"20"` - OperatorContractAddress common.Address `env:"OPERATOR_CONTRACT_ADDRESS"` - P2PAnnounceIP net.IP `env:"P2P_ANNOUNCE_IP"` - P2PAnnouncePort uint16 `env:"P2P_ANNOUNCE_PORT"` - P2PBootstrapPeers []string `env:"P2P_BOOTSTRAP_PEERS"` - P2PDHTAnnouncementCounterUserPrefix uint32 `env:"P2P_DHT_ANNOUNCEMENT_COUNTER_USER_PREFIX" default:"0"` - P2PListenIP net.IP `env:"P2P_LISTEN_IP" default:"0.0.0.0"` - P2PListenPort uint16 `env:"P2P_LISTEN_PORT"` - P2PPeerID p2pkey.PeerID `env:"P2P_PEER_ID"` - P2PPeerstoreWriteInterval time.Duration `env:"P2P_PEERSTORE_WRITE_INTERVAL" default:"5m"` - Port uint16 `env:"CHAINLINK_PORT" default:"6688"` - ReaperExpiration models.Duration `env:"REAPER_EXPIRATION" default:"240h"` - ReplayFromBlock int64 `env:"REPLAY_FROM_BLOCK" default:"-1"` - RootDir string `env:"ROOT" default:"~/.chainlink"` - SecureCookies bool `env:"SECURE_COOKIES" default:"true"` - SessionTimeout models.Duration `env:"SESSION_TIMEOUT" default:"15m"` - StatsPusherLogging string `env:"STATS_PUSHER_LOGGING" default:"false"` - TLSCertPath string `env:"TLS_CERT_PATH" ` - TLSHost string `env:"CHAINLINK_TLS_HOST" ` - TLSKeyPath string `env:"TLS_KEY_PATH" ` - TLSPort uint16 `env:"CHAINLINK_TLS_PORT" default:"6689"` - TLSRedirect bool `env:"CHAINLINK_TLS_REDIRECT" default:"false"` - TriggerFallbackDBPollInterval time.Duration `env:"TRIGGER_FALLBACK_DB_POLL_INTERVAL" default:"30s"` - UnAuthenticatedRateLimit int64 `env:"UNAUTHENTICATED_RATE_LIMIT" default:"5"` - UnAuthenticatedRateLimitPeriod time.Duration `env:"UNAUTHENTICATED_RATE_LIMIT_PERIOD" default:"20s"` + AdminCredentialsFile string `env:"ADMIN_CREDENTIALS_FILE" default:"$ROOT/apicredentials"` + AllowOrigins string `env:"ALLOW_ORIGINS" default:"http://localhost:3000,http://localhost:6688"` + AuthenticatedRateLimit int64 `env:"AUTHENTICATED_RATE_LIMIT" default:"1000"` + AuthenticatedRateLimitPeriod time.Duration `env:"AUTHENTICATED_RATE_LIMIT_PERIOD" default:"1m"` + BalanceMonitorEnabled bool `env:"BALANCE_MONITOR_ENABLED" default:"true"` + BlockBackfillDepth string `env:"BLOCK_BACKFILL_DEPTH" default:"10"` + BlockHistoryEstimatorBatchSize uint32 `env:"BLOCK_HISTORY_ESTIMATOR_BATCH_SIZE"` + BlockHistoryEstimatorBlockDelay uint16 `env:"BLOCK_HISTORY_ESTIMATOR_BLOCK_DELAY"` + BlockHistoryEstimatorBlockHistorySize uint16 `env:"BLOCK_HISTORY_ESTIMATOR_BLOCK_HISTORY_SIZE"` + BlockHistoryEstimatorTransactionPercentile uint16 `env:"BLOCK_HISTORY_ESTIMATOR_TRANSACTION_PERCENTILE" default:"60"` + BridgeResponseURL url.URL `env:"BRIDGE_RESPONSE_URL"` + ChainID big.Int `env:"ETH_CHAIN_ID" default:"1"` + ClientNodeURL string `env:"CLIENT_NODE_URL" default:"http://localhost:6688"` + DatabaseBackupDir string `env:"DATABASE_BACKUP_DIR" default:""` + DatabaseBackupFrequency time.Duration `env:"DATABASE_BACKUP_FREQUENCY" default:"1h"` + DatabaseBackupMode string `env:"DATABASE_BACKUP_MODE" default:"none"` + DatabaseBackupURL *url.URL `env:"DATABASE_BACKUP_URL" default:""` + DatabaseListenerMaxReconnectDuration time.Duration `env:"DATABASE_LISTENER_MAX_RECONNECT_DURATION" default:"10m"` + DatabaseListenerMinReconnectInterval time.Duration `env:"DATABASE_LISTENER_MIN_RECONNECT_INTERVAL" default:"1m"` + DatabaseMaximumTxDuration time.Duration `env:"DATABASE_MAXIMUM_TX_DURATION" default:"30m"` + DatabaseTimeout models.Duration `env:"DATABASE_TIMEOUT" default:"0"` + DatabaseURL string `env:"DATABASE_URL"` + DefaultHTTPAllowUnrestrictedNetworkAccess bool `env:"DEFAULT_HTTP_ALLOW_UNRESTRICTED_NETWORK_ACCESS" default:"false"` + DefaultHTTPLimit int64 `env:"DEFAULT_HTTP_LIMIT" default:"32768"` + DefaultHTTPTimeout models.Duration `env:"DEFAULT_HTTP_TIMEOUT" default:"15s"` + DefaultMaxHTTPAttempts uint `env:"MAX_HTTP_ATTEMPTS" default:"5"` + Dev bool `env:"CHAINLINK_DEV" default:"false"` + EnableExperimentalAdapters bool `env:"ENABLE_EXPERIMENTAL_ADAPTERS" default:"false"` + EnableLegacyJobPipeline bool `env:"ENABLE_LEGACY_JOB_PIPELINE" default:"true"` + EthBalanceMonitorBlockDelay uint16 `env:"ETH_BALANCE_MONITOR_BLOCK_DELAY"` + EthFinalityDepth uint `env:"ETH_FINALITY_DEPTH"` + EthGasBumpPercent uint16 `env:"ETH_GAS_BUMP_PERCENT" default:"20"` + EthGasBumpThreshold uint64 `env:"ETH_GAS_BUMP_THRESHOLD"` + EthGasBumpTxDepth uint16 `env:"ETH_GAS_BUMP_TX_DEPTH" default:"10"` + EthGasBumpWei big.Int `env:"ETH_GAS_BUMP_WEI"` + EthGasLimitDefault uint64 `env:"ETH_GAS_LIMIT_DEFAULT"` + EthGasLimitMultiplier float32 `env:"ETH_GAS_LIMIT_MULTIPLIER" default:"1.0"` + EthGasLimitTransfer uint64 `env:"ETH_GAS_LIMIT_TRANSFER"` + EthGasPriceDefault big.Int `env:"ETH_GAS_PRICE_DEFAULT"` + EthHeadTrackerHistoryDepth uint `env:"ETH_HEAD_TRACKER_HISTORY_DEPTH"` + EthHeadTrackerMaxBufferSize uint `env:"ETH_HEAD_TRACKER_MAX_BUFFER_SIZE" default:"3"` + EthHeadTrackerSamplingInterval time.Duration `env:"ETH_HEAD_TRACKER_SAMPLING_INTERVAL" default:"1s"` + EthLogBackfillBatchSize uint32 `env:"ETH_LOG_BACKFILL_BATCH_SIZE" default:"100"` + EthMaxGasPriceWei big.Int `env:"ETH_MAX_GAS_PRICE_WEI"` + EthMaxInFlightTransactions uint64 `env:"ETH_MAX_IN_FLIGHT_TRANSACTIONS"` + EthMaxQueuedTransactions uint64 `env:"ETH_MAX_QUEUED_TRANSACTIONS"` + EthMinGasPriceWei big.Int `env:"ETH_MIN_GAS_PRICE_WEI"` + EthNonceAutoSync bool `env:"ETH_NONCE_AUTO_SYNC" default:"true"` + EthRPCDefaultBatchSize uint32 `env:"ETH_RPC_DEFAULT_BATCH_SIZE" default:"100"` + EthTxReaperInterval time.Duration `env:"ETH_TX_REAPER_INTERVAL" default:"1h"` + EthTxReaperThreshold time.Duration `env:"ETH_TX_REAPER_THRESHOLD" default:"168h"` + EthTxResendAfterThreshold time.Duration `env:"ETH_TX_RESEND_AFTER_THRESHOLD"` + EthereumDisabled bool `env:"ETH_DISABLED" default:"false"` + EthereumHTTPURL string `env:"ETH_HTTP_URL"` + EthereumSecondaryURL string `env:"ETH_SECONDARY_URL" default:""` + EthereumSecondaryURLs string `env:"ETH_SECONDARY_URLS" default:""` + EthereumURL string `env:"ETH_URL" default:"ws://localhost:8546"` + ExplorerAccessKey string `env:"EXPLORER_ACCESS_KEY"` + ExplorerSecret string `env:"EXPLORER_SECRET"` + ExplorerURL *url.URL `env:"EXPLORER_URL"` + FMDefaultTransactionQueueDepth uint32 `env:"FM_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` + FeatureCronV2 bool `env:"FEATURE_CRON_V2" default:"true"` + FeatureExternalInitiators bool `env:"FEATURE_EXTERNAL_INITIATORS" default:"false"` + FeatureFluxMonitor bool `env:"FEATURE_FLUX_MONITOR" default:"true"` + FeatureFluxMonitorV2 bool `env:"FEATURE_FLUX_MONITOR_V2" default:"true"` + FeatureOffchainReporting bool `env:"FEATURE_OFFCHAIN_REPORTING" default:"false"` + FeatureWebhookV2 bool `env:"FEATURE_WEBHOOK_V2" default:"false"` + FlagsContractAddress string `env:"FLAGS_CONTRACT_ADDRESS"` + GasEstimatorMode string `env:"GAS_ESTIMATOR_MODE"` + GasUpdaterBatchSize uint32 `env:"GAS_UPDATER_BATCH_SIZE"` + GasUpdaterBlockDelay uint16 `env:"GAS_UPDATER_BLOCK_DELAY"` + GasUpdaterBlockHistorySize uint16 `env:"GAS_UPDATER_BLOCK_HISTORY_SIZE"` + GasUpdaterEnabled bool `env:"GAS_UPDATER_ENABLED"` + GasUpdaterTransactionPercentile uint16 `env:"GAS_UPDATER_TRANSACTION_PERCENTILE" default:"60"` + GlobalLockRetryInterval models.Duration `env:"GLOBAL_LOCK_RETRY_INTERVAL" default:"1s"` + HTTPServerWriteTimeout time.Duration `env:"HTTP_SERVER_WRITE_TIMEOUT" default:"10s"` + InsecureFastScrypt bool `env:"INSECURE_FAST_SCRYPT" default:"false"` + InsecureSkipVerify bool `env:"INSECURE_SKIP_VERIFY" default:"false"` + JSONConsole bool `env:"JSON_CONSOLE" default:"false"` + JobPipelineMaxRunDuration time.Duration `env:"JOB_PIPELINE_MAX_RUN_DURATION" default:"10m"` + JobPipelineReaperInterval time.Duration `env:"JOB_PIPELINE_REAPER_INTERVAL" default:"1h"` + JobPipelineReaperThreshold time.Duration `env:"JOB_PIPELINE_REAPER_THRESHOLD" default:"24h"` + JobPipelineResultWriteQueueDepth uint64 `env:"JOB_PIPELINE_RESULT_WRITE_QUEUE_DEPTH" default:"100"` + KeeperDefaultTransactionQueueDepth uint32 `env:"KEEPER_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` + KeeperMaximumGracePeriod int64 `env:"KEEPER_MAXIMUM_GRACE_PERIOD" default:"100"` + KeeperMinimumRequiredConfirmations uint64 `env:"KEEPER_MINIMUM_REQUIRED_CONFIRMATIONS" default:"12"` + KeeperRegistryCheckGasOverhead uint64 `env:"KEEPER_REGISTRY_CHECK_GAS_OVERHEAD" default:"200000"` + KeeperRegistryPerformGasOverhead uint64 `env:"KEEPER_REGISTRY_PERFORM_GAS_OVERHEAD" default:"150000"` + KeeperRegistrySyncInterval time.Duration `env:"KEEPER_REGISTRY_SYNC_INTERVAL" default:"30m"` + LinkContractAddress string `env:"LINK_CONTRACT_ADDRESS"` + LogLevel LogLevel `env:"LOG_LEVEL" default:"info"` + LogSQLMigrations bool `env:"LOG_SQL_MIGRATIONS" default:"true"` + LogSQLStatements bool `env:"LOG_SQL" default:"false"` + LogToDisk bool `env:"LOG_TO_DISK" default:"true"` + MaximumServiceDuration models.Duration `env:"MAXIMUM_SERVICE_DURATION" default:"8760h" ` + MigrateDatabase bool `env:"MIGRATE_DATABASE" default:"true"` + MinIncomingConfirmations uint32 `env:"MIN_INCOMING_CONFIRMATIONS"` + MinRequiredOutgoingConfirmations uint64 `env:"MIN_OUTGOING_CONFIRMATIONS"` + MinimumContractPayment assets.Link `env:"MINIMUM_CONTRACT_PAYMENT_LINK_JUELS"` + MinimumRequestExpiration uint64 `env:"MINIMUM_REQUEST_EXPIRATION" default:"300"` + MinimumServiceDuration models.Duration `env:"MINIMUM_SERVICE_DURATION" default:"0s" ` + OCRBlockchainTimeout time.Duration `env:"OCR_BLOCKCHAIN_TIMEOUT" default:"20s"` + OCRBootstrapCheckInterval time.Duration `env:"OCR_BOOTSTRAP_CHECK_INTERVAL" default:"20s"` + OCRContractConfirmations uint `env:"OCR_CONTRACT_CONFIRMATIONS"` + OCRContractPollInterval time.Duration `env:"OCR_CONTRACT_POLL_INTERVAL" default:"1m"` + OCRContractSubscribeInterval time.Duration `env:"OCR_CONTRACT_SUBSCRIBE_INTERVAL" default:"2m"` + OCRContractTransmitterTransmitTimeout time.Duration `env:"OCR_CONTRACT_TRANSMITTER_TRANSMIT_TIMEOUT" default:"10s"` + OCRDHTLookupInterval int `env:"OCR_DHT_LOOKUP_INTERVAL" default:"10"` + OCRDatabaseTimeout time.Duration `env:"OCR_DATABASE_TIMEOUT" default:"10s"` + OCRDefaultTransactionQueueDepth uint32 `env:"OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH" default:"1"` + OCRIncomingMessageBufferSize int `env:"OCR_INCOMING_MESSAGE_BUFFER_SIZE" default:"10"` + OCRKeyBundleID string `env:"OCR_KEY_BUNDLE_ID"` + OCRMonitoringEndpoint string `env:"OCR_MONITORING_ENDPOINT"` + OCRNewStreamTimeout time.Duration `env:"OCR_NEW_STREAM_TIMEOUT" default:"10s"` + OCRObservationGracePeriod time.Duration `env:"OCR_OBSERVATION_GRACE_PERIOD" default:"1s"` + OCRObservationTimeout time.Duration `env:"OCR_OBSERVATION_TIMEOUT" default:"12s"` + OCROutgoingMessageBufferSize int `env:"OCR_OUTGOING_MESSAGE_BUFFER_SIZE" default:"10"` + OCRTraceLogging bool `env:"OCR_TRACE_LOGGING" default:"false"` + OCRTransmitterAddress string `env:"OCR_TRANSMITTER_ADDRESS"` + ORMMaxIdleConns int `env:"ORM_MAX_IDLE_CONNS" default:"10"` + ORMMaxOpenConns int `env:"ORM_MAX_OPEN_CONNS" default:"20"` + OperatorContractAddress common.Address `env:"OPERATOR_CONTRACT_ADDRESS"` + P2PAnnounceIP net.IP `env:"P2P_ANNOUNCE_IP"` + P2PAnnouncePort uint16 `env:"P2P_ANNOUNCE_PORT"` + P2PBootstrapPeers []string `env:"P2P_BOOTSTRAP_PEERS"` + P2PDHTAnnouncementCounterUserPrefix uint32 `env:"P2P_DHT_ANNOUNCEMENT_COUNTER_USER_PREFIX" default:"0"` + P2PListenIP net.IP `env:"P2P_LISTEN_IP" default:"0.0.0.0"` + P2PListenPort uint16 `env:"P2P_LISTEN_PORT"` + P2PNetworkingStack ocrnetworking.NetworkingStack `env:"P2P_NETWORKING_STACK" default:"V1"` + P2PPeerID p2pkey.PeerID `env:"P2P_PEER_ID"` + P2PPeerstoreWriteInterval time.Duration `env:"P2P_PEERSTORE_WRITE_INTERVAL" default:"5m"` + P2PV2AnnounceAddresses []string `env:"P2PV2_ANNOUNCE_ADDRESSES"` + P2PV2Bootstrappers []string `env:"P2PV2_BOOTSTRAPPERS"` + P2PV2DeltaDial models.Duration `env:"P2PV2_DELTA_DIAL" default:"15s"` + P2PV2DeltaReconcile models.Duration `env:"P2PV2_DELTA_RECONCILE" default:"1m"` + P2PV2ListenAddresses []string `env:"P2PV2_LISTEN_ADDRESSES"` + Port uint16 `env:"CHAINLINK_PORT" default:"6688"` + ReaperExpiration models.Duration `env:"REAPER_EXPIRATION" default:"240h"` + ReplayFromBlock int64 `env:"REPLAY_FROM_BLOCK" default:"-1"` + RootDir string `env:"ROOT" default:"~/.chainlink"` + SecureCookies bool `env:"SECURE_COOKIES" default:"true"` + SessionTimeout models.Duration `env:"SESSION_TIMEOUT" default:"15m"` + StatsPusherLogging string `env:"STATS_PUSHER_LOGGING" default:"false"` + TLSCertPath string `env:"TLS_CERT_PATH" ` + TLSHost string `env:"CHAINLINK_TLS_HOST" ` + TLSKeyPath string `env:"TLS_KEY_PATH" ` + TLSPort uint16 `env:"CHAINLINK_TLS_PORT" default:"6689"` + TLSRedirect bool `env:"CHAINLINK_TLS_REDIRECT" default:"false"` + TriggerFallbackDBPollInterval time.Duration `env:"TRIGGER_FALLBACK_DB_POLL_INTERVAL" default:"30s"` + UnAuthenticatedRateLimit int64 `env:"UNAUTHENTICATED_RATE_LIMIT" default:"5"` + UnAuthenticatedRateLimitPeriod time.Duration `env:"UNAUTHENTICATED_RATE_LIMIT_PERIOD" default:"20s"` } // EnvVarName gets the environment variable name for a config schema field diff --git a/core/store/orm/schema_test.go b/core/store/orm/schema_test.go index 806fb2b3db0..171ed5af66b 100644 --- a/core/store/orm/schema_test.go +++ b/core/store/orm/schema_test.go @@ -82,8 +82,8 @@ func TestConfigSchema(t *testing.T) { "GasUpdaterBatchSize": "GAS_UPDATER_BATCH_SIZE", "GasUpdaterBlockDelay": "GAS_UPDATER_BLOCK_DELAY", "GasUpdaterBlockHistorySize": "GAS_UPDATER_BLOCK_HISTORY_SIZE", - "GasUpdaterTransactionPercentile": "GAS_UPDATER_TRANSACTION_PERCENTILE", "GasUpdaterEnabled": "GAS_UPDATER_ENABLED", + "GasUpdaterTransactionPercentile": "GAS_UPDATER_TRANSACTION_PERCENTILE", "GlobalLockRetryInterval": "GLOBAL_LOCK_RETRY_INTERVAL", "HTTPServerWriteTimeout": "HTTP_SERVER_WRITE_TIMEOUT", "InsecureFastScrypt": "INSECURE_FAST_SCRYPT", @@ -119,6 +119,7 @@ func TestConfigSchema(t *testing.T) { "OCRContractTransmitterTransmitTimeout": "OCR_CONTRACT_TRANSMITTER_TRANSMIT_TIMEOUT", "OCRDHTLookupInterval": "OCR_DHT_LOOKUP_INTERVAL", "OCRDatabaseTimeout": "OCR_DATABASE_TIMEOUT", + "OCRDefaultTransactionQueueDepth": "OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH", "OCRIncomingMessageBufferSize": "OCR_INCOMING_MESSAGE_BUFFER_SIZE", "OCRKeyBundleID": "OCR_KEY_BUNDLE_ID", "OCRMonitoringEndpoint": "OCR_MONITORING_ENDPOINT", @@ -127,7 +128,6 @@ func TestConfigSchema(t *testing.T) { "OCRObservationTimeout": "OCR_OBSERVATION_TIMEOUT", "OCROutgoingMessageBufferSize": "OCR_OUTGOING_MESSAGE_BUFFER_SIZE", "OCRTraceLogging": "OCR_TRACE_LOGGING", - "OCRDefaultTransactionQueueDepth": "OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH", "OCRTransmitterAddress": "OCR_TRANSMITTER_ADDRESS", "ORMMaxIdleConns": "ORM_MAX_IDLE_CONNS", "ORMMaxOpenConns": "ORM_MAX_OPEN_CONNS", @@ -139,8 +139,15 @@ func TestConfigSchema(t *testing.T) { "P2PDHTAnnouncementCounterUserPrefix": "P2P_DHT_ANNOUNCEMENT_COUNTER_USER_PREFIX", "P2PListenIP": "P2P_LISTEN_IP", "P2PListenPort": "P2P_LISTEN_PORT", + "P2PNetworkingStack": "P2P_NETWORKING_STACK", "P2PPeerID": "P2P_PEER_ID", "P2PPeerstoreWriteInterval": "P2P_PEERSTORE_WRITE_INTERVAL", + "P2PV2AccountAddresses": "P2PV2_ANNOUNCE_ADDRESSES", + "P2PV2AnnounceAddresses": "P2PV2_ANNOUNCE_ADDRESSES", + "P2PV2Bootstrappers": "P2PV2_BOOTSTRAPPERS", + "P2PV2DeltaDial": "P2PV2_DELTA_DIAL", + "P2PV2DeltaReconcile": "P2PV2_DELTA_RECONCILE", + "P2PV2ListenAddresses": "P2PV2_LISTEN_ADDRESSES", "Port": "CHAINLINK_PORT", "ReaperExpiration": "REAPER_EXPIRATION", "ReplayFromBlock": "REPLAY_FROM_BLOCK", diff --git a/core/store/presenters/presenters.go b/core/store/presenters/presenters.go index e6d27f58387..115b5fab444 100644 --- a/core/store/presenters/presenters.go +++ b/core/store/presenters/presenters.go @@ -96,12 +96,18 @@ type EnvPrinter struct { TriggerFallbackDBPollInterval time.Duration `json:"JOB_PIPELINE_DB_POLL_INTERVAL"` OCRContractTransmitterTransmitTimeout time.Duration `json:"OCR_CONTRACT_TRANSMITTER_TRANSMIT_TIMEOUT"` OCRDatabaseTimeout time.Duration `json:"OCR_DATABASE_TIMEOUT"` + OCRDefaultTransactionQueueDepth uint32 `json:"OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH"` + OCRIncomingMessageBufferSize int `json:"OCR_INCOMING_MESSAGE_BUFFER_SIZE"` + P2PBootstrapPeers []string `json:"P2P_BOOTSTRAP_PEERS"` P2PListenIP string `json:"P2P_LISTEN_IP"` P2PListenPort string `json:"P2P_LISTEN_PORT"` + P2PNetworkingStack string `json:"P2P_NETWORKING_STACK"` P2PPeerID string `json:"P2P_PEER_ID"` - P2PBootstrapPeers []string `json:"P2P_BOOTSTRAP_PEERS"` - OCRDefaultTransactionQueueDepth uint32 `json:"OCR_DEFAULT_TRANSACTION_QUEUE_DEPTH"` - OCRIncomingMessageBufferSize int `json:"OCR_INCOMING_MESSAGE_BUFFER_SIZE"` + P2PV2AnnounceAddresses []string `json:"P2PV2_ANNOUNCE_ADDRESSES"` + P2PV2Bootstrappers []string `json:"P2PV2_BOOTSTRAPPERS"` + P2PV2DeltaDial models.Duration `json:"P2PV2_DELTA_DIAL"` + P2PV2DeltaReconcile models.Duration `json:"P2PV2_DELTA_RECONCILE"` + P2PV2ListenAddresses []string `json:"P2PV2_LISTEN_ADDRESSES"` OCROutgoingMessageBufferSize int `json:"OCR_OUTGOING_MESSAGE_BUFFER_SIZE"` OCRNewStreamTimeout time.Duration `json:"OCR_NEW_STREAM_TIMEOUT"` OCRDHTLookupInterval int `json:"OCR_DHT_LOOKUP_INTERVAL"` @@ -197,12 +203,18 @@ func NewConfigPrinter(store *store.Store) (ConfigPrinter, error) { OCRIncomingMessageBufferSize: config.OCRIncomingMessageBufferSize(), OCRNewStreamTimeout: config.OCRNewStreamTimeout(), OCROutgoingMessageBufferSize: config.OCROutgoingMessageBufferSize(), + OCRTraceLogging: config.OCRTraceLogging(), P2PBootstrapPeers: p2pBootstrapPeers, P2PListenIP: config.P2PListenIP().String(), P2PListenPort: config.P2PListenPortRaw(), + P2PNetworkingStack: config.P2PNetworkingStackRaw(), P2PPeerID: config.P2PPeerIDRaw(), + P2PV2AnnounceAddresses: config.P2PV2AnnounceAddressesRaw(), + P2PV2Bootstrappers: config.P2PV2BootstrappersRaw(), + P2PV2DeltaDial: config.P2PV2DeltaDial(), + P2PV2DeltaReconcile: config.P2PV2DeltaReconcile(), + P2PV2ListenAddresses: config.P2PV2ListenAddresses(), TriggerFallbackDBPollInterval: config.TriggerFallbackDBPollInterval(), - OCRTraceLogging: config.OCRTraceLogging(), OperatorContractAddress: config.OperatorContractAddress(), Port: config.Port(), ReaperExpiration: config.ReaperExpiration(), diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 51ed0e7c940..3153a033340 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -57,6 +57,21 @@ New gas estimator modes may be added in future. In addition, a minor annoyance has been fixed whereby previously if you enabled the gas updater, it would overwrite the locally stored value for gas price and continue to use this even if it was disabled after a reboot. This will no longer happen: BlockHistory mode will not clobber the locally stored value for fixed gas price, which can still be adjusted via remote API call or using `chainlink config setgasprice XXX`. In order to use this manually fixed gas price, you must enable FixedPrice estimator mode. +### Added + +Added support for latest version of libocr with the V2 networking stack. New env vars to configure this are: + +``` +P2P_NETWORKING_STACK +P2PV2_ANNOUNCE_ADDRESSES +P2PV2_BOOTSTRAPPERS +P2PV2_DELTA_DIAL +P2PV2_DELTA_RECONCILE +P2PV2_LISTEN_ADDRESSES +``` + +All of these are currently optional, by default OCR will continue to use the existing V1 stack. The new env vars will be used internally for OCR testing. + ## [0.10.8] - 2021-06-21 ### Fixed diff --git a/go.mod b/go.mod index 6e24742ea9c..a6f24dab0ae 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.8.1 // indirect - github.com/smartcontractkit/libocr v0.0.0-20210617175326-472ada9f2eb2 + github.com/smartcontractkit/libocr v0.0.0-20210706082215-22f0f4e09528 github.com/smartcontractkit/wsrpc v0.3.0 github.com/spf13/viper v1.8.1 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index 74f6ed43fb7..cc101b20c88 100644 --- a/go.sum +++ b/go.sum @@ -1383,8 +1383,8 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/smartcontractkit/chainlink v0.8.10-0.20200825114219-81dd2fc95bac/go.mod h1:j7qIYHGCN4QqMXdO8g8A9dmUT5vKFmkxPSbjAIfrfNU= github.com/smartcontractkit/chainlink v0.9.5-0.20201207211610-6c7fee37d5b7/go.mod h1:kmdLJbVZRCnBLiL6gG+U+1+0ofT3bB48DOF8tjQvcoI= github.com/smartcontractkit/libocr v0.0.0-20201203233047-5d9b24f0cbb5/go.mod h1:bfdSuLnBWCkafDvPGsQ1V6nrXhg046gh227MKi4zkpc= -github.com/smartcontractkit/libocr v0.0.0-20210617175326-472ada9f2eb2 h1:XMzwQx+IPEOSOwkydtkQqD6vrb55YO7ui9mH7hES9ng= -github.com/smartcontractkit/libocr v0.0.0-20210617175326-472ada9f2eb2/go.mod h1:AQktwBooI+Y/8NWdvIzU+EgGoLzpe3mo+o+jluMonTw= +github.com/smartcontractkit/libocr v0.0.0-20210706082215-22f0f4e09528 h1:7xIvYXcZqqfiPEwwZ0SnNdkrSNz66Kl2HF7fh28uwoc= +github.com/smartcontractkit/libocr v0.0.0-20210706082215-22f0f4e09528/go.mod h1:AQktwBooI+Y/8NWdvIzU+EgGoLzpe3mo+o+jluMonTw= github.com/smartcontractkit/wsrpc v0.3.0 h1:VLoNqxtOhfdofAH8a5bbgtjmNl5yn9Cf+WtpyiKWq5g= github.com/smartcontractkit/wsrpc v0.3.0/go.mod h1:9ciG9g+0Hb9FgqUmt7MHz3EhTbLjbEoftcq8McErZN0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=