Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cool-goats-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

Node operators can now specify in `PollSuccessThreshold` how many successful polls in a row must an unreachable RPC pass to become Alive again, on EVM chains. #added #nops
5 changes: 5 additions & 0 deletions .changeset/tall-tigers-fear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

RPCs that sustain polling error rates above 50% will now eventually be marked as unreachable, in addition to previous behaviour of `PollFailureThreshold` failures in a row. #updated #nops
2 changes: 2 additions & 0 deletions ccip/config/evm/fallback.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ SafeTagSupported = true
LogBackfillBatchSize = 1000
LogPollInterval = '15s'
LogKeepBlocksDepth = 100000
LogPollerSkipEmptyBlocks = false
LogPrunePageSize = 10000
BackupLogPollerBlockDelay = 100
MinContractPayment = '.00001 link'
Expand Down Expand Up @@ -78,6 +79,7 @@ PersistenceBatchSize = 100

[NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 5
Expand Down
9 changes: 8 additions & 1 deletion core/config/docs/chains-evm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ LogPollInterval = '15s' # Default
# LogKeepBlocksDepth works in conjunction with Feature.LogPoller. Controls how many blocks the poller will keep, must be greater than FinalityDepth+1.
LogKeepBlocksDepth = 100000 # Default
# **ADVANCED**
# LogPollerSkipEmptyBlocks defines if LogPoller should persist or skip blocks that do not contain logs matching any of registered filters. Setting this to true can reduce the load on the database and improve performance for fast chains.
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar: "logs matching any of registered filters" is missing "the". Consider changing to "logs matching any of the registered filters".

Suggested change
# LogPollerSkipEmptyBlocks defines if LogPoller should persist or skip blocks that do not contain logs matching any of registered filters. Setting this to true can reduce the load on the database and improve performance for fast chains.
# LogPollerSkipEmptyBlocks defines if LogPoller should persist or skip blocks that do not contain logs matching any of the registered filters. Setting this to true can reduce the load on the database and improve performance for fast chains.

Copilot uses AI. Check for mistakes.
LogPollerSkipEmptyBlocks = false # Default
# **ADVANCED**
# LogPrunePageSize defines size of the page for pruning logs. Controls how many logs/blocks (at most) are deleted in a single prune tick. Default value 0 means no paging, delete everything at once.
LogPrunePageSize = 0 # Default
# **ADVANCED**
Expand Down Expand Up @@ -426,10 +429,14 @@ GasEstimator.PriceMax = '79 gwei' # Example
#
# In addition to these settings, `EVM.NoNewHeadsThreshold` controls how long to wait after receiving no new heads before marking the node as out-of-sync.
[EVM.NodePool]
# PollFailureThreshold indicates how many consecutive polls must fail in order to mark a node as unreachable.
# PollFailureThreshold indicates how many polls must fail beyond those that succeed in order to mark a node as unreachable.
#
# Set to zero to disable poll checking.
PollFailureThreshold = 5 # Default
# PollSuccessThreshold indicates how many consecutive polls must succeed in order to mark a node as alive once it has been marked as unreachable.
#
# Set to zero to require no successful polls (previous behavior).
PollSuccessThreshold = 0 # Default
# PollInterval controls how often to poll the node to check for liveness.
#
# Set to zero to disable poll checking.
Expand Down
2 changes: 1 addition & 1 deletion core/config/docs/chains-solana.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ TxAcceptanceState = 3 # Default
[Solana.MultiNode]
# Enabled enables the multinode feature.
Enabled = false # Default
# PollFailureThreshold is the number of consecutive poll failures before a node is considered unhealthy.
# PollFailureThreshold is the number of poll failures beyond poll successes before a node is considered unhealthy.
PollFailureThreshold = 5 # Default
# PollInterval is the rate to poll for node health.
PollInterval = '10s' # Default
Expand Down
12 changes: 6 additions & 6 deletions core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ require (
github.com/smartcontractkit/chainlink-common/keystore v1.1.0
github.com/smartcontractkit/chainlink-data-streams v0.1.13
github.com/smartcontractkit/chainlink-deployments-framework v0.98.0
github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260416173445-80f6efde0a03
github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260428180431-40447a80e681
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260421142741-9c7fbaf7c828
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877
github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0
Expand Down Expand Up @@ -493,14 +493,14 @@ require (
github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260415165642-49f23e4d76cc // indirect
github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260415165642-49f23e4d76cc // indirect
github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260415165642-49f23e4d76cc // indirect
github.com/smartcontractkit/chainlink-ccv v0.0.0-20260423133643-8d6a915c04b3 // indirect
github.com/smartcontractkit/chainlink-ccv v0.0.2-0.20260428133800-3b1484e8b1fd // indirect
github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 // indirect
github.com/smartcontractkit/chainlink-evm/contracts/cre/gobindings v0.0.0-20260403151002-2c91155b5501 // indirect
github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect
github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563 // indirect
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260326122810-b657beadfb57 // indirect
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260410144512-ca02ad6ed16a // indirect
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260410144512-ca02ad6ed16a // indirect
github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20260423135514-5b1a7565a99c // indirect
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260423135514-5b1a7565a99c // indirect
github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20260423135514-5b1a7565a99c // indirect
github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20260423135514-5b1a7565a99c // indirect
github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 // indirect
github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d // indirect
github.com/smartcontractkit/chainlink-protos/chainlink-ccv/heartbeat v0.0.0-20260115142640-f6b99095c12e // indirect
Expand Down
24 changes: 12 additions & 12 deletions core/scripts/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions core/services/chainlink/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ func TestConfig_Marshal(t *testing.T) {
LogBackfillBatchSize: ptr[uint32](17),
LogPollInterval: &minute,
LogKeepBlocksDepth: ptr[uint32](100000),
LogPollerSkipEmptyBlocks: ptr(false),
LogPrunePageSize: ptr[uint32](0),
BackupLogPollerBlockDelay: ptr[uint64](532),
MinContractPayment: commonassets.NewLinkFromJuels(math.MaxInt64),
Expand Down Expand Up @@ -809,6 +810,7 @@ func TestConfig_Marshal(t *testing.T) {

NodePool: evmcfg.NodePool{
PollFailureThreshold: ptr[uint32](5),
PollSuccessThreshold: ptr[uint32](0),
PollInterval: &minute,
SelectionMode: &selectionMode,
SyncThreshold: ptr[uint32](13),
Expand Down Expand Up @@ -1249,6 +1251,7 @@ FlagsContractAddress = '0xae4E781a6218A8031764928E88d457937A954fC3'
LinkContractAddress = '0x538aAaB4ea120b2bC2fe5D296852D948F07D849e'
LogBackfillBatchSize = 17
LogPollInterval = '1m0s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 532
Expand Down Expand Up @@ -1339,6 +1342,7 @@ PriceMax = '79.228162514264337593543950335 gether'

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '1m0s'
SelectionMode = 'HighestHead'
SyncThreshold = 13
Expand Down
2 changes: 2 additions & 0 deletions core/services/chainlink/testdata/config-full.toml
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ FlagsContractAddress = '0xae4E781a6218A8031764928E88d457937A954fC3'
LinkContractAddress = '0x538aAaB4ea120b2bC2fe5D296852D948F07D849e'
LogBackfillBatchSize = 17
LogPollInterval = '1m0s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 532
Expand Down Expand Up @@ -554,6 +555,7 @@ PriceMax = '79.228162514264337593543950335 gether'

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '1m0s'
SelectionMode = 'HighestHead'
SyncThreshold = 13
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ SafeTagSupported = true
LinkContractAddress = '0x514910771AF9Ca656af840dff83E8264EcF986CA'
LogBackfillBatchSize = 1000
LogPollInterval = '15s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -495,6 +496,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 5
Expand Down Expand Up @@ -546,6 +548,7 @@ SafeTagSupported = true
LinkContractAddress = '0xa36085F69e2889c224210F603D836748e7dC0088'
LogBackfillBatchSize = 1000
LogPollInterval = '15s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -618,6 +621,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 5
Expand Down Expand Up @@ -664,6 +668,7 @@ SafeTagSupported = true
LinkContractAddress = '0xb0897686c545045aFc77CF20eC7A532E3120E0F1'
LogBackfillBatchSize = 1000
LogPollInterval = '1s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -735,6 +740,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ func TestIntegration_LogEventProvider(t *testing.T) {
n := 10

backend.Commit()
lp.PollAndSaveLogs(ctx, 1) // Ensure log poller has a latest block
lp.PollAndSaveLogs(ctx, 1, false) // Ensure log poller has a latest block

ids, addrs, contracts := deployUpkeepCounter(ctx, t, n, ethClient, backend, carrol, logProvider)
lp.PollAndSaveLogs(ctx, int64(n))
lp.PollAndSaveLogs(ctx, int64(n), false)

go func() {
if err := logProvider.Start(ctx); err != nil {
Expand Down Expand Up @@ -145,9 +145,9 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) {
logProvider := provider.(logprovider.LogEventProviderTest)

backend.Commit()
lp.PollAndSaveLogs(ctx, 1) // Ensure log poller has a latest block
lp.PollAndSaveLogs(ctx, 1, false) // Ensure log poller has a latest block
_, addrs, contracts := deployUpkeepCounter(ctx, t, 1, ethClient, backend, carrol, logProvider)
lp.PollAndSaveLogs(ctx, int64(5))
lp.PollAndSaveLogs(ctx, int64(5), false)
require.Len(t, contracts, 1)
require.Len(t, addrs, 1)

Expand Down Expand Up @@ -222,7 +222,7 @@ func TestIntegration_LogEventProvider_Backfill(t *testing.T) {
n := 10

backend.Commit()
lp.PollAndSaveLogs(ctx, 1) // Ensure log poller has a latest block
lp.PollAndSaveLogs(ctx, 1, false) // Ensure log poller has a latest block
_, _, contracts := deployUpkeepCounter(ctx, t, n, ethClient, backend, carrol, logProvider)

poll := pollFn(ctx, t, lp, ethClient)
Expand Down Expand Up @@ -278,7 +278,7 @@ func TestIntegration_LogRecoverer_Backfill(t *testing.T) {
logProvider := provider.(logprovider.LogEventProviderTest)

backend.Commit()
lp.PollAndSaveLogs(ctx, 1) // Ensure log poller has a latest block
lp.PollAndSaveLogs(ctx, 1, false) // Ensure log poller has a latest block

n := 10
_, _, contracts := deployUpkeepCounter(ctx, t, n, ethClient, backend, carrol, logProvider)
Expand Down Expand Up @@ -372,7 +372,7 @@ func waitLogPoller(ctx context.Context, t *testing.T, commit func() common.Hash,
if latestPolled.BlockNumber >= latestBlock {
break
}
lp.PollAndSaveLogs(ctx, latestBlock)
lp.PollAndSaveLogs(ctx, latestBlock, false)
}
}

Expand All @@ -381,7 +381,7 @@ func pollFn(ctx context.Context, t *testing.T, lp logpoller.LogPollerTest, ethCl
b, err := ethClient.BlockByHash(ctx, blockHash)
require.NoError(t, err)
bn := b.Number()
lp.PollAndSaveLogs(ctx, bn.Int64())
lp.PollAndSaveLogs(ctx, bn.Int64(), false)
}
}

Expand Down
2 changes: 2 additions & 0 deletions core/web/resolver/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ FlagsContractAddress = '0xae4E781a6218A8031764928E88d457937A954fC3'
LinkContractAddress = '0x538aAaB4ea120b2bC2fe5D296852D948F07D849e'
LogBackfillBatchSize = 17
LogPollInterval = '1m0s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -184,6 +185,7 @@ FlagsContractAddress = '0xae4E781a6218A8031764928E88d457937A954fC3'
LinkContractAddress = '0x538aAaB4ea120b2bC2fe5D296852D948F07D849e'
LogBackfillBatchSize = 17
LogPollInterval = '1m0s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down
2 changes: 2 additions & 0 deletions core/web/resolver/testdata/config-full.toml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ FlagsContractAddress = '0xae4E781a6218A8031764928E88d457937A954fC3'
LinkContractAddress = '0x538aAaB4ea120b2bC2fe5D296852D948F07D849e'
LogBackfillBatchSize = 17
LogPollInterval = '1m0s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -530,6 +531,7 @@ PriceMax = '79.228162514264337593543950335 gether'

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '1m0s'
SelectionMode = 'HighestHead'
SyncThreshold = 13
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ SafeTagSupported = true
LinkContractAddress = '0x514910771AF9Ca656af840dff83E8264EcF986CA'
LogBackfillBatchSize = 1000
LogPollInterval = '15s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -495,6 +496,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 5
Expand Down Expand Up @@ -546,6 +548,7 @@ SafeTagSupported = true
LinkContractAddress = '0xa36085F69e2889c224210F603D836748e7dC0088'
LogBackfillBatchSize = 1000
LogPollInterval = '15s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -618,6 +621,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 5
Expand Down Expand Up @@ -664,6 +668,7 @@ SafeTagSupported = true
LinkContractAddress = '0xb0897686c545045aFc77CF20eC7A532E3120E0F1'
LogBackfillBatchSize = 1000
LogPollInterval = '1s'
LogPollerSkipEmptyBlocks = false
LogKeepBlocksDepth = 100000
LogPrunePageSize = 0
BackupLogPollerBlockDelay = 100
Expand Down Expand Up @@ -735,6 +740,7 @@ PersistenceBatchSize = 100

[EVM.NodePool]
PollFailureThreshold = 5
PollSuccessThreshold = 0
PollInterval = '10s'
SelectionMode = 'HighestHead'
SyncThreshold = 10
Expand Down
Loading
Loading