diff --git a/deployment/ccip/changeset/globals/config.go b/deployment/ccip/changeset/globals/config.go index a0ca800f1d7..c190d44fda1 100644 --- a/deployment/ccip/changeset/globals/config.go +++ b/deployment/ccip/changeset/globals/config.go @@ -2,6 +2,10 @@ package globals import ( "time" + + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" ) type ConfigType string @@ -10,28 +14,16 @@ const ( ConfigTypeActive ConfigType = "active" ConfigTypeCandidate ConfigType = "candidate" // ========= Changeset Defaults ========= - PermissionLessExecutionThreshold = 8 * time.Hour - RemoteGasPriceBatchWriteFrequency = 30 * time.Minute - TokenPriceBatchWriteFrequency = 30 * time.Minute - BatchGasLimit = 6_500_000 - InflightCacheExpiry = 10 * time.Minute - RootSnoozeTime = 30 * time.Minute - BatchingStrategyID = 0 - DeltaProgress = 10 * time.Second - DeltaResend = 10 * time.Second - DeltaInitial = 20 * time.Second - DeltaRound = 2 * time.Second - DeltaGrace = 2 * time.Second - DeltaCertifiedCommitRequest = 10 * time.Second - DeltaStage = 10 * time.Second - Rmax = 50 - MaxDurationQuery = 500 * time.Millisecond - MaxDurationObservation = 5 * time.Second - MaxDurationShouldAcceptAttestedReport = 10 * time.Second - MaxDurationShouldTransmitAcceptedReport = 10 * time.Second - GasPriceDeviationPPB = 1000 - DAGasPriceDeviationPPB = 0 - OptimisticConfirmations = 1 + PermissionLessExecutionThreshold = 8 * time.Hour + RemoteGasPriceBatchWriteFrequency = 30 * time.Minute + TokenPriceBatchWriteFrequency = 30 * time.Minute + BatchGasLimit = 6_500_000 + InflightCacheExpiry = 10 * time.Minute + RootSnoozeTime = 30 * time.Minute + BatchingStrategyID = 0 + GasPriceDeviationPPB = 1000 + DAGasPriceDeviationPPB = 0 + OptimisticConfirmations = 1 // ====================================== // ========= Onchain consts ========= @@ -40,3 +32,31 @@ const ( CCIPLockOrBurnV1RetBytes = 32 // ====================================== ) + +var ( + DefaultCommitOffChainCfg = pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(30 * time.Minute), + TokenPriceBatchWriteFrequency: *config.MustNewDuration(30 * time.Minute), + NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, + MaxReportTransmissionCheckAttempts: 5, + RMNSignaturesTimeout: 6900 * time.Millisecond, + RMNEnabled: true, + MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, + SignObservationPrefix: "chainlink ccip 1.6 rmn observation", + TransmissionDelayMultiplier: 1 * time.Minute, + InflightPriceCheckRetries: 10, + MerkleRootAsyncObserverDisabled: false, + MerkleRootAsyncObserverSyncFreq: 4 * time.Second, + MerkleRootAsyncObserverSyncTimeout: 12 * time.Second, + ChainFeeAsyncObserverSyncFreq: 10 * time.Second, + ChainFeeAsyncObserverSyncTimeout: 12 * time.Second, + } + DefaultExecuteOffChainCfg = pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: 6_500_000, // Building batches with 6.5m and transmit with 8m to account for overhead. Clarify with offchain + InflightCacheExpiry: *config.MustNewDuration(5 * time.Minute), + RootSnoozeTime: *config.MustNewDuration(5 * time.Minute), // does not work now + MessageVisibilityInterval: *config.MustNewDuration(8 * time.Hour), + BatchingStrategyID: 0, + TransmissionDelayMultiplier: 1 * time.Minute, // Clarify with offchain + } +) diff --git a/deployment/ccip/changeset/globals/ocr3.go b/deployment/ccip/changeset/globals/ocr3.go new file mode 100644 index 00000000000..903f9ab00ca --- /dev/null +++ b/deployment/ccip/changeset/globals/ocr3.go @@ -0,0 +1,97 @@ +package globals + +import ( + "fmt" + "time" + + "dario.cat/mergo" + + "github.com/smartcontractkit/chainlink/deployment/common/types" +) + +// Intention of this file is to be a single source of the truth for OCR3 parameters used by CCIP plugins. +// +// Assumptions: +// - Although, some values are similar between Commit and Execute, we should keep them separate, because +// these plugins have different requirements and characteristics. This way we can avoid misconfiguration +// by accidentally changing parameter for one plugin while adjusting it for the other +// - OCR3 parameters are chain agnostic and should be reused across different chains. There might be some use cases +// for overrides to accommodate specific chain characteristics (e.g. Ethereum). +// However, for most of the cases we should strive to rely on defaults under CommitOCRParams and ExecOCRParams. +// This makes the testing process much easier and increase our confidence that the configuration is safe to use. +// - The fewer overrides the better. Introducing new overrides should be done with caution and only if there's a strong +// justification for it. Moreover, it requires detailed chaos / load testing to ensure that the new parameters are safe to use +// and meet CCIP SLOs +// - Single params must not be stored under const or exposed outside of this file to limit the risk of +// accidental configuration or partial configuration +// - MaxDurations should be set on the latencies observed on various environments using p99 OCR3 latencies +// These values should be specific to the plugin type and should not depend on the chain family +// or the environment in which plugin runs +var ( + // CommitOCRParams represents the default OCR3 parameters for all chains (beside Ethereum, see CommitOCRParamsForEthereum). + // Most of the intervals here should be generic enough (and chain agnostic) to be reused across different chains. + CommitOCRParams = types.OCRParameters{ + DeltaProgress: 120 * time.Second, + DeltaResend: 30 * time.Second, + DeltaInitial: 20 * time.Second, + DeltaRound: 15 * time.Second, + DeltaGrace: 5 * time.Second, + DeltaCertifiedCommitRequest: 10 * time.Second, + // TransmissionDelayMultiplier overrides DeltaStage + DeltaStage: 25 * time.Second, + Rmax: 3, + MaxDurationQuery: 7 * time.Second, + MaxDurationObservation: 13 * time.Second, + MaxDurationShouldAcceptAttestedReport: 5 * time.Second, + MaxDurationShouldTransmitAcceptedReport: 10 * time.Second, + } + + // CommitOCRParamsForEthereum represents a dedicated set of OCR3 parameters for Ethereum. + // It's driven by the fact that Ethereum block time is slow (12 seconds) and chain is considered + // more expensive to other EVM compatible chains + CommitOCRParamsForEthereum = withOverrides( + CommitOCRParams, + types.OCRParameters{ + DeltaRound: 90 * time.Second, + DeltaStage: 60 * time.Second, + }, + ) +) + +var ( + // ExecOCRParams represents the default OCR3 parameters for all chains (beside Ethereum, see ExecOCRParamsForEthereum). + ExecOCRParams = types.OCRParameters{ + DeltaProgress: 100 * time.Second, + DeltaResend: 30 * time.Second, + DeltaInitial: 20 * time.Second, + DeltaRound: 15 * time.Second, + DeltaGrace: 5 * time.Second, + DeltaCertifiedCommitRequest: 10 * time.Second, + // TransmissionDelayMultiplier overrides DeltaStage + DeltaStage: 25 * time.Second, + Rmax: 3, + // MaxDurationQuery is set to very low value, because Execution plugin doesn't use Query + MaxDurationQuery: 200 * time.Millisecond, + MaxDurationObservation: 13 * time.Second, + MaxDurationShouldAcceptAttestedReport: 5 * time.Second, + MaxDurationShouldTransmitAcceptedReport: 10 * time.Second, + } + + // ExecOCRParamsForEthereum represents a dedicated set of OCR3 parameters for Ethereum. + // Similarly to Commit, it's here to accommodate Ethereum specific characteristics + ExecOCRParamsForEthereum = withOverrides( + ExecOCRParams, + types.OCRParameters{ + DeltaRound: 90 * time.Second, + DeltaStage: 60 * time.Second, + }, + ) +) + +func withOverrides(base types.OCRParameters, overrides types.OCRParameters) types.OCRParameters { + outcome := base + if err := mergo.Merge(&outcome, overrides, mergo.WithOverride); err != nil { + panic(fmt.Sprintf("error while building an OCR config %v", err)) + } + return outcome +} diff --git a/deployment/ccip/changeset/globals/ocr3_test.go b/deployment/ccip/changeset/globals/ocr3_test.go new file mode 100644 index 00000000000..672a67095a2 --- /dev/null +++ b/deployment/ccip/changeset/globals/ocr3_test.go @@ -0,0 +1,26 @@ +package globals + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_MergeWithOverrides(t *testing.T) { + assert.Equal(t, ExecOCRParams.DeltaProgress, ExecOCRParamsForEthereum.DeltaProgress) + assert.Equal(t, ExecOCRParams.DeltaResend, ExecOCRParamsForEthereum.DeltaResend) + assert.Equal(t, ExecOCRParams.DeltaInitial, ExecOCRParamsForEthereum.DeltaInitial) + assert.Equal(t, ExecOCRParams.DeltaGrace, ExecOCRParamsForEthereum.DeltaGrace) + assert.Equal(t, ExecOCRParams.DeltaCertifiedCommitRequest, ExecOCRParamsForEthereum.DeltaCertifiedCommitRequest) + assert.Equal(t, ExecOCRParams.MaxDurationQuery, ExecOCRParamsForEthereum.MaxDurationQuery) + assert.Equal(t, ExecOCRParams.MaxDurationObservation, ExecOCRParamsForEthereum.MaxDurationObservation) + assert.Equal(t, ExecOCRParams.MaxDurationShouldAcceptAttestedReport, ExecOCRParamsForEthereum.MaxDurationShouldAcceptAttestedReport) + assert.Equal(t, ExecOCRParams.MaxDurationShouldTransmitAcceptedReport, ExecOCRParamsForEthereum.MaxDurationShouldTransmitAcceptedReport) + assert.Equal(t, ExecOCRParams.MaxDurationQuery, ExecOCRParamsForEthereum.MaxDurationQuery) + + assert.Equal(t, 90*time.Second, ExecOCRParamsForEthereum.DeltaRound) + assert.Equal(t, 60*time.Second, ExecOCRParamsForEthereum.DeltaStage) + assert.Equal(t, 200*time.Millisecond, ExecOCRParams.MaxDurationQuery) + assert.Equal(t, 200*time.Millisecond, ExecOCRParamsForEthereum.MaxDurationQuery) +} diff --git a/deployment/ccip/changeset/testhelpers/test_environment.go b/deployment/ccip/changeset/testhelpers/test_environment.go index cd8f009060c..e8dca38d4ca 100644 --- a/deployment/ccip/changeset/testhelpers/test_environment.go +++ b/deployment/ccip/changeset/testhelpers/test_environment.go @@ -63,7 +63,7 @@ type TestConfigs struct { IsUSDCAttestationMissing bool IsMultiCall3 bool IsStaticLink bool - OCRConfigOverride func(*v1_6.CCIPOCRParams) + OCRConfigOverride func(v1_6.CCIPOCRParams) v1_6.CCIPOCRParams RMNEnabled bool NumOfRMNNodes int LinkPrice *big.Int @@ -174,7 +174,7 @@ func WithRMNEnabled(numOfNode int) TestOps { } } -func WithOCRConfigOverride(override func(*v1_6.CCIPOCRParams)) TestOps { +func WithOCRConfigOverride(override func(v1_6.CCIPOCRParams) v1_6.CCIPOCRParams) TestOps { return func(testCfg *TestConfigs) { testCfg.OCRConfigOverride = override } @@ -662,7 +662,8 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn require.NoError(t, err) // Build the per chain config. chainConfigs := make(map[uint64]v1_6.ChainConfig) - ocrConfigs := make(map[uint64]v1_6.CCIPOCRParams) + commitOCRConfigs := make(map[uint64]v1_6.CCIPOCRParams) + execOCRConfigs := make(map[uint64]v1_6.CCIPOCRParams) for _, chain := range evmChains { timelockContractsPerChain[chain] = &proposalutils.TimelockExecutionContracts{ Timelock: state.Chains[chain].Timelock, @@ -674,22 +675,23 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn } else { linkTokenAddr = state.Chains[chain].LinkToken.Address() } - tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, linkTokenAddr, state.Chains[chain].Weth9.Address()) - ocrOverride := tc.OCRConfigOverride - if tc.RMNEnabled { - ocrOverride = func(ocrParams *v1_6.CCIPOCRParams) { - if tc.OCRConfigOverride != nil { - tc.OCRConfigOverride(ocrParams) + ocrOverride := func(ocrParams v1_6.CCIPOCRParams) v1_6.CCIPOCRParams { + if tc.OCRConfigOverride != nil { + tc.OCRConfigOverride(ocrParams) + } + if tc.RMNEnabled { + if ocrParams.CommitOffChainConfig != nil { + ocrParams.CommitOffChainConfig.RMNEnabled = true + } + } else { + if ocrParams.CommitOffChainConfig != nil { + ocrParams.CommitOffChainConfig.RMNEnabled = false } - ocrParams.CommitOffChainConfig.RMNEnabled = true } + return ocrParams } - ocrParams := v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig(e.FeedChainSel, tokenInfo), - v1_6.WithDefaultExecuteOffChainConfig(tokenDataProviders), - v1_6.WithOCRParamOverride(ocrOverride), - ) - ocrConfigs[chain] = ocrParams + commitOCRConfigs[chain] = v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, e.FeedChainSel, tokenConfig.GetTokenInfo(e.Env.Logger, linkTokenAddr, state.Chains[chain].Weth9.Address()), ocrOverride) + execOCRConfigs[chain] = v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, tokenDataProviders, ocrOverride) chainConfigs[chain] = v1_6.ChainConfig{ Readers: nodeInfo.NonBootstraps().PeerIDs(), FChain: uint8(len(nodeInfo.NonBootstraps().PeerIDs()) / 3), @@ -703,13 +705,8 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn for _, chain := range solChains { ocrOverride := tc.OCRConfigOverride - ocrParams := v1_6.DeriveCCIPOCRParams( - // TODO: tokenInfo is nil for solana - v1_6.WithDefaultCommitOffChainConfig(e.FeedChainSel, nil), - v1_6.WithDefaultExecuteOffChainConfig(tokenDataProviders), - v1_6.WithOCRParamOverride(ocrOverride), - ) - ocrConfigs[chain] = ocrParams + commitOCRConfigs[chain] = v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, e.FeedChainSel, nil, ocrOverride) + execOCRConfigs[chain] = v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, tokenDataProviders, ocrOverride) chainConfigs[chain] = v1_6.ChainConfig{ Readers: nodeInfo.NonBootstraps().PeerIDs(), // #nosec G115 - Overflow is not a concern in this test scenario @@ -750,7 +747,7 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn MCMS: mcmsConfig, }, PluginInfo: v1_6.SetCandidatePluginInfo{ - OCRConfigPerRemoteChainSelector: ocrConfigs, + OCRConfigPerRemoteChainSelector: commitOCRConfigs, PluginType: types.PluginTypeCCIPCommit, }, }, @@ -767,7 +764,7 @@ func AddCCIPContractsToEnvironment(t *testing.T, allChains []uint64, tEnv TestEn }, PluginInfo: []v1_6.SetCandidatePluginInfo{ { - OCRConfigPerRemoteChainSelector: ocrConfigs, + OCRConfigPerRemoteChainSelector: execOCRConfigs, PluginType: types.PluginTypeCCIPExec, }, }, diff --git a/deployment/ccip/changeset/v1_6/config.go b/deployment/ccip/changeset/v1_6/config.go new file mode 100644 index 00000000000..7c2c4276862 --- /dev/null +++ b/deployment/ccip/changeset/v1_6/config.go @@ -0,0 +1,153 @@ +package v1_6 + +import ( + "time" + + chain_selectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" + + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/globals" + "github.com/smartcontractkit/chainlink/deployment/common/types" +) + +var ( + DefaultOCRParamsForCommitForNonETH = CCIPOCRParams{ + OCRParameters: globals.CommitOCRParams, + CommitOffChainConfig: &globals.DefaultCommitOffChainCfg, + } + + DefaultOCRParamsForCommitForETH = CCIPOCRParams{ + OCRParameters: globals.CommitOCRParamsForEthereum, + CommitOffChainConfig: &globals.DefaultCommitOffChainCfg, + } + + DefaultOCRParamsForExecForNonETH = CCIPOCRParams{ + OCRParameters: globals.ExecOCRParams, + ExecuteOffChainConfig: &globals.DefaultExecuteOffChainCfg, + } + + DefaultOCRParamsForExecForETH = CCIPOCRParams{ + OCRParameters: globals.ExecOCRParamsForEthereum, + ExecuteOffChainConfig: &globals.DefaultExecuteOffChainCfg, + } + + // Used for only testing with simulated chains + OcrParamsForTest = CCIPOCRParams{ + OCRParameters: types.OCRParameters{ + DeltaProgress: 10 * time.Second, + DeltaResend: 10 * time.Second, + DeltaInitial: 20 * time.Second, + DeltaRound: 2 * time.Second, + DeltaGrace: 2 * time.Second, + DeltaCertifiedCommitRequest: 10 * time.Second, + DeltaStage: 10 * time.Second, + Rmax: 50, + MaxDurationQuery: 10 * time.Second, + MaxDurationObservation: 10 * time.Second, + MaxDurationShouldAcceptAttestedReport: 10 * time.Second, + MaxDurationShouldTransmitAcceptedReport: 10 * time.Second, + }, + CommitOffChainConfig: &pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(globals.RemoteGasPriceBatchWriteFrequency), + TokenPriceBatchWriteFrequency: *config.MustNewDuration(globals.TokenPriceBatchWriteFrequency), + NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, + MaxReportTransmissionCheckAttempts: 5, + RMNEnabled: false, + RMNSignaturesTimeout: 30 * time.Minute, + MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, + SignObservationPrefix: "chainlink ccip 1.6 rmn observation", + MerkleRootAsyncObserverDisabled: false, + MerkleRootAsyncObserverSyncFreq: 4 * time.Second, + MerkleRootAsyncObserverSyncTimeout: 12 * time.Second, + ChainFeeAsyncObserverSyncFreq: 10 * time.Second, + ChainFeeAsyncObserverSyncTimeout: 12 * time.Second, + }, + ExecuteOffChainConfig: &pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: globals.BatchGasLimit, + InflightCacheExpiry: *config.MustNewDuration(globals.InflightCacheExpiry), + RootSnoozeTime: *config.MustNewDuration(globals.RootSnoozeTime), + MessageVisibilityInterval: *config.MustNewDuration(globals.PermissionLessExecutionThreshold), + BatchingStrategyID: globals.BatchingStrategyID, + }, + } +) + +type OCRConfigChainType int + +const ( + Default OCRConfigChainType = iota + 1 + Ethereum + // SimulationTest is kept only for backward compatibility. Tests probably should + // migrate to using Default or Ethereum + SimulationTest +) + +func DeriveOCRConfigTypeFromSelector(chainsel uint64) OCRConfigChainType { + switch chainsel { + case chain_selectors.ETHEREUM_TESTNET_SEPOLIA.Selector, + chain_selectors.ETHEREUM_TESTNET_HOLESKY.Selector, + chain_selectors.ETHEREUM_MAINNET.Selector: + return Ethereum + default: + return Default + } +} + +func (c OCRConfigChainType) CommitOCRParams() CCIPOCRParams { + switch c { + case Ethereum: + return DefaultOCRParamsForCommitForETH.Copy() + case Default: + return DefaultOCRParamsForCommitForNonETH.Copy() + case SimulationTest: + return OcrParamsForTest.Copy() + default: + panic("unknown OCRConfigChainType") + } +} + +func (c OCRConfigChainType) ExecuteOCRParams() CCIPOCRParams { + switch c { + case Ethereum: + return DefaultOCRParamsForExecForETH.Copy() + case Default: + return DefaultOCRParamsForExecForNonETH.Copy() + case SimulationTest: + return OcrParamsForTest.Copy() + default: + panic("unknown OCRConfigChainType") + } +} + +func DeriveOCRParamsForCommit( + ocrChainType OCRConfigChainType, + feedChain uint64, + feeTokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, + override func(params CCIPOCRParams) CCIPOCRParams, +) CCIPOCRParams { + params := ocrChainType.CommitOCRParams() + params.CommitOffChainConfig.TokenInfo = feeTokenInfo + params.CommitOffChainConfig.PriceFeedChainSelector = ccipocr3.ChainSelector(feedChain) + if override == nil { + return params + } + return override(params) +} + +func DeriveOCRParamsForExec( + ocrChainType OCRConfigChainType, + observerConfig []pluginconfig.TokenDataObserverConfig, + override func(params CCIPOCRParams) CCIPOCRParams, +) CCIPOCRParams { + params := ocrChainType.ExecuteOCRParams() + params.ExecuteOffChainConfig.TokenDataObservers = observerConfig + if override == nil { + return params + } + return override(params) +} diff --git a/deployment/ccip/changeset/v1_6/cs_active_candidate_test.go b/deployment/ccip/changeset/v1_6/cs_active_candidate_test.go index 55326fd7111..f9f668c3906 100644 --- a/deployment/ccip/changeset/v1_6/cs_active_candidate_test.go +++ b/deployment/ccip/changeset/v1_6/cs_active_candidate_test.go @@ -210,21 +210,16 @@ func Test_ActiveCandidate(t *testing.T) { { // NOTE: this is technically not a new chain, but needed for validation. OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig(tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), - state.Chains[dest].LinkToken.Address(), - state.Chains[dest].Weth9.Address())), - ), + dest: v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address()), nil), }, PluginType: types.PluginTypeCCIPCommit, }, { // NOTE: this is technically not a new chain, but needed for validation. OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultExecuteOffChainConfig(nil), - ), + dest: v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, nil, nil), }, PluginType: types.PluginTypeCCIPExec, }, diff --git a/deployment/ccip/changeset/v1_6/cs_ccip_home.go b/deployment/ccip/changeset/v1_6/cs_ccip_home.go index ca8fe58e13b..aebac81c54b 100644 --- a/deployment/ccip/changeset/v1_6/cs_ccip_home.go +++ b/deployment/ccip/changeset/v1_6/cs_ccip_home.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "math/big" - "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -17,17 +16,13 @@ import ( mcmsevmsdk "github.com/smartcontractkit/mcms/sdk/evm" mcmstypes "github.com/smartcontractkit/mcms/types" - "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" - "github.com/smartcontractkit/chainlink-ccip/chainconfig" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/globals" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -124,7 +119,7 @@ func validateCommitOffchainConfig(c *pluginconfig.CommitOffchainConfig, selector tokenInfos = append(tokenInfos, onchainState.Weth9) symbol, decimal, err := findTokenInfo(tokenInfos, token) if err != nil { - return err + return fmt.Errorf("chain %d- %w", selector, err) } if decimal != tokenConfig.Decimals { return fmt.Errorf("token %s -address %s has %d decimals in provided token config, expected %d", @@ -173,6 +168,21 @@ type CCIPOCRParams struct { ExecuteOffChainConfig *pluginconfig.ExecuteOffchainConfig } +func (c CCIPOCRParams) Copy() CCIPOCRParams { + newC := CCIPOCRParams{ + OCRParameters: c.OCRParameters, + } + if c.CommitOffChainConfig != nil { + commit := *c.CommitOffChainConfig + newC.CommitOffChainConfig = &commit + } + if c.ExecuteOffChainConfig != nil { + exec := *c.ExecuteOffChainConfig + newC.ExecuteOffChainConfig = &exec + } + return newC +} + func (c CCIPOCRParams) Validate(e deployment.Environment, selector uint64, feedChainSel uint64, state changeset.CCIPOnChainState) error { if err := c.OCRParameters.Validate(); err != nil { return fmt.Errorf("invalid OCR parameters: %w", err) @@ -193,93 +203,6 @@ func (c CCIPOCRParams) Validate(e deployment.Environment, selector uint64, feedC return nil } -type CCIPOCROpts func(params *CCIPOCRParams) - -// WithOCRParamOverride can be used if you want to override the default OCR parameters with your custom function. -func WithOCRParamOverride(override func(params *CCIPOCRParams)) CCIPOCROpts { - return func(params *CCIPOCRParams) { - if override != nil { - override(params) - } - } -} - -// WithDefaultCommitOffChainConfig can be used to add token info to the existing commit off-chain config. If no commit off-chain config is set, it will be created with default values. -func WithDefaultCommitOffChainConfig(feedChainSel uint64, tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo) CCIPOCROpts { - return func(params *CCIPOCRParams) { - if params.CommitOffChainConfig == nil { - params.CommitOffChainConfig = &pluginconfig.CommitOffchainConfig{ - RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(globals.RemoteGasPriceBatchWriteFrequency), - TokenPriceBatchWriteFrequency: *config.MustNewDuration(globals.TokenPriceBatchWriteFrequency), - TokenInfo: tokenInfo, - PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), - NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, - MaxReportTransmissionCheckAttempts: 5, - RMNEnabled: false, - RMNSignaturesTimeout: 30 * time.Minute, - MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, - SignObservationPrefix: "chainlink ccip 1.6 rmn observation", - MerkleRootAsyncObserverDisabled: false, - MerkleRootAsyncObserverSyncFreq: 4 * time.Second, - MerkleRootAsyncObserverSyncTimeout: 12 * time.Second, - ChainFeeAsyncObserverSyncFreq: 10 * time.Second, - ChainFeeAsyncObserverSyncTimeout: 12 * time.Second, - } - } else { - if params.CommitOffChainConfig.TokenInfo == nil { - params.CommitOffChainConfig.TokenInfo = make(map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo) - } - for k, v := range tokenInfo { - params.CommitOffChainConfig.TokenInfo[k] = v - } - } - } -} - -// WithDefaultExecuteOffChainConfig can be used to add token data observers to the execute off-chain config. If no execute off-chain config is set, it will be created with default values. -func WithDefaultExecuteOffChainConfig(tokenDataObservers []pluginconfig.TokenDataObserverConfig) CCIPOCROpts { - return func(params *CCIPOCRParams) { - if params.ExecuteOffChainConfig == nil { - params.ExecuteOffChainConfig = &pluginconfig.ExecuteOffchainConfig{ - BatchGasLimit: globals.BatchGasLimit, - InflightCacheExpiry: *config.MustNewDuration(globals.InflightCacheExpiry), - RootSnoozeTime: *config.MustNewDuration(globals.RootSnoozeTime), - MessageVisibilityInterval: *config.MustNewDuration(globals.PermissionLessExecutionThreshold), - BatchingStrategyID: globals.BatchingStrategyID, - TokenDataObservers: tokenDataObservers, - } - } else if tokenDataObservers != nil { - params.ExecuteOffChainConfig.TokenDataObservers = append(params.ExecuteOffChainConfig.TokenDataObservers, tokenDataObservers...) - } - } -} - -// DeriveCCIPOCRParams derives the default OCR parameters for a chain, with the option to override them. -func DeriveCCIPOCRParams( - opts ...CCIPOCROpts, -) CCIPOCRParams { - params := CCIPOCRParams{ - OCRParameters: commontypes.OCRParameters{ - DeltaProgress: globals.DeltaProgress, - DeltaResend: globals.DeltaResend, - DeltaInitial: globals.DeltaInitial, - DeltaRound: globals.DeltaRound, - DeltaGrace: globals.DeltaGrace, - DeltaCertifiedCommitRequest: globals.DeltaCertifiedCommitRequest, - DeltaStage: globals.DeltaStage, - Rmax: globals.Rmax, - MaxDurationQuery: globals.MaxDurationQuery, - MaxDurationObservation: globals.MaxDurationObservation, - MaxDurationShouldAcceptAttestedReport: globals.MaxDurationShouldAcceptAttestedReport, - MaxDurationShouldTransmitAcceptedReport: globals.MaxDurationShouldTransmitAcceptedReport, - }, - } - for _, opt := range opts { - opt(¶ms) - } - return params -} - type PromoteCandidatePluginInfo struct { // RemoteChainSelectors is the chain selector of the DONs that we want to promote the candidate config of. // Note that each (chain, ccip capability version) pair has a unique DON ID. diff --git a/deployment/ccip/changeset/v1_6/cs_ccip_home_test.go b/deployment/ccip/changeset/v1_6/cs_ccip_home_test.go index 254c69e37c1..33a01dd8990 100644 --- a/deployment/ccip/changeset/v1_6/cs_ccip_home_test.go +++ b/deployment/ccip/changeset/v1_6/cs_ccip_home_test.go @@ -71,10 +71,8 @@ func TestInvalidOCR3Params(t *testing.T) { require.NoError(t, err) nodes, err := deployment.NodeInfo(e.Env.NodeIDs, e.Env.Offchain) require.NoError(t, err) - params := v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig(e.FeedChainSel, nil), - v1_6.WithDefaultExecuteOffChainConfig(nil), - ) + params := v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, e.FeedChainSel, nil, nil) + // tweak params to have invalid config // make DeltaRound greater than DeltaProgress params.OCRParameters.DeltaRound = params.OCRParameters.DeltaProgress + time.Duration(1) @@ -87,7 +85,7 @@ func TestInvalidOCR3Params(t *testing.T) { state.Chains[e.HomeChainSel].RMNHome.Address(), params.OCRParameters, params.CommitOffChainConfig, - params.ExecuteOffChainConfig, + &globals.DefaultExecuteOffChainCfg, ) require.Errorf(t, err, "expected error") pattern := `DeltaRound \(\d+\.\d+s\) must be less than DeltaProgress \(\d+s\)` @@ -270,31 +268,24 @@ func Test_SetCandidate(t *testing.T) { PluginInfo: []v1_6.SetCandidatePluginInfo{ { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), - state.Chains[dest].LinkToken.Address(), - state.Chains[dest].Weth9.Address())), - ), + dest: v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address()), nil), }, PluginType: types.PluginTypeCCIPCommit, }, { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultExecuteOffChainConfig(nil), - // change the default config to make MessageVisibilityInterval != PermissionLessExecutionThresholdSeconds - v1_6.WithOCRParamOverride(func(params *v1_6.CCIPOCRParams) { - dCfg, err := state.Chains[dest].OffRamp.GetDynamicConfig(&bind.CallOpts{ - Context: ctx, - }) - require.NoError(t, err) - params.ExecuteOffChainConfig.MessageVisibilityInterval = - *config.MustNewDuration( - time.Duration(dCfg.PermissionLessExecutionThresholdSeconds + uint32(time.Second))) - }), - ), + dest: v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, nil, func(params v1_6.CCIPOCRParams) v1_6.CCIPOCRParams { + dCfg, err := state.Chains[dest].OffRamp.GetDynamicConfig(&bind.CallOpts{ + Context: ctx, + }) + require.NoError(t, err) + params.ExecuteOffChainConfig.MessageVisibilityInterval = + *config.MustNewDuration( + time.Duration(dCfg.PermissionLessExecutionThresholdSeconds + uint32(time.Second))) + return params + }), }, PluginType: types.PluginTypeCCIPExec, }, @@ -324,21 +315,15 @@ func Test_SetCandidate(t *testing.T) { PluginInfo: []v1_6.SetCandidatePluginInfo{ { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), - state.Chains[dest].LinkToken.Address(), - state.Chains[dest].Weth9.Address())), - ), + dest: v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address()), nil), }, PluginType: types.PluginTypeCCIPCommit, }, { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultExecuteOffChainConfig(nil), - ), + dest: v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, nil, nil), }, PluginType: types.PluginTypeCCIPExec, }, @@ -441,21 +426,15 @@ func Test_RevokeCandidate(t *testing.T) { PluginInfo: []v1_6.SetCandidatePluginInfo{ { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), - state.Chains[dest].LinkToken.Address(), - state.Chains[dest].Weth9.Address())), - ), + dest: v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, tenv.FeedChainSel, tokenConfig.GetTokenInfo(logger.TestLogger(t), + state.Chains[dest].LinkToken.Address(), + state.Chains[dest].Weth9.Address()), nil), }, PluginType: types.PluginTypeCCIPCommit, }, { OCRConfigPerRemoteChainSelector: map[uint64]v1_6.CCIPOCRParams{ - dest: v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultExecuteOffChainConfig(nil), - ), + dest: v1_6.DeriveOCRParamsForExec(v1_6.SimulationTest, nil, nil), }, PluginType: types.PluginTypeCCIPExec, }, diff --git a/deployment/ccip/changeset/v1_6/cs_chain_contracts_test.go b/deployment/ccip/changeset/v1_6/cs_chain_contracts_test.go index b8430355012..a067bb45250 100644 --- a/deployment/ccip/changeset/v1_6/cs_chain_contracts_test.go +++ b/deployment/ccip/changeset/v1_6/cs_chain_contracts_test.go @@ -859,13 +859,9 @@ func TestSetOCR3ConfigValidations(t *testing.T) { // Build the per chain config. wrongChainConfigs := make(map[uint64]v1_6.ChainConfig) - ocrConfigs := make(map[uint64]v1_6.CCIPOCRParams) + commitOCRConfigs := make(map[uint64]v1_6.CCIPOCRParams) for _, chain := range allChains { - ocrParams := v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig(e.FeedChainSel, nil), - v1_6.WithDefaultExecuteOffChainConfig(nil), - ) - ocrConfigs[chain] = ocrParams + commitOCRConfigs[chain] = v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, e.FeedChainSel, nil, nil) // set wrong chain config with incorrect value of FChain wrongChainConfigs[chain] = v1_6.ChainConfig{ Readers: envNodes.NonBootstraps().PeerIDs(), @@ -898,7 +894,7 @@ func TestSetOCR3ConfigValidations(t *testing.T) { FeedChainSelector: e.FeedChainSel, }, PluginInfo: v1_6.SetCandidatePluginInfo{ - OCRConfigPerRemoteChainSelector: ocrConfigs, + OCRConfigPerRemoteChainSelector: commitOCRConfigs, PluginType: types.PluginTypeCCIPCommit, }, }, diff --git a/deployment/ccip/changeset/v1_6/cs_home_chain_test.go b/deployment/ccip/changeset/v1_6/cs_home_chain_test.go index cbcccb52d86..d63cec2b501 100644 --- a/deployment/ccip/changeset/v1_6/cs_home_chain_test.go +++ b/deployment/ccip/changeset/v1_6/cs_home_chain_test.go @@ -207,10 +207,6 @@ func TestAddDonAfterRemoveDons(t *testing.T) { allChains := e.Env.AllChainSelectors() homeChain := s.Chains[e.HomeChainSel] ocrConfigs := make(map[uint64]v1_6.CCIPOCRParams) - ocrParams := v1_6.DeriveCCIPOCRParams( - v1_6.WithDefaultCommitOffChainConfig(e.FeedChainSel, nil), - v1_6.WithDefaultExecuteOffChainConfig(nil), - ) // Remove a don donsBefore, err := homeChain.CapabilityRegistry.GetDONs(nil) require.NoError(t, err) @@ -254,7 +250,7 @@ func TestAddDonAfterRemoveDons(t *testing.T) { break } } - ocrConfigs[donRemovedForChain] = ocrParams + ocrConfigs[donRemovedForChain] = v1_6.DeriveOCRParamsForCommit(v1_6.SimulationTest, e.FeedChainSel, nil, nil) // try to add the another don e.Env, err = commoncs.Apply(t, e.Env, nil, commoncs.Configure( diff --git a/deployment/environment/crib/ccip_deployer.go b/deployment/environment/crib/ccip_deployer.go index 1d1ef80167d..598b2285a8f 100644 --- a/deployment/environment/crib/ccip_deployer.go +++ b/deployment/environment/crib/ccip_deployer.go @@ -530,11 +530,17 @@ func setupLanes(e *deployment.Environment, state changeset.CCIPOnChainState) (de func mustOCR(e *deployment.Environment, homeChainSel uint64, feedChainSel uint64, newDons bool) (deployment.Environment, error) { chainSelectors := e.AllChainSelectors() - var ocrConfigPerSelector = make(map[uint64]v1_6.CCIPOCRParams) + var commitOCRConfigPerSelector = make(map[uint64]v1_6.CCIPOCRParams) + var execOCRConfigPerSelector = make(map[uint64]v1_6.CCIPOCRParams) + // Should be configured in the future based on the load test scenario + // chainType := v1_6.Default + + // TODO Passing SimulationTest to reduce number of changes in the CRIB (load test setup) + // @Austin please flip it back to Default once we reach a stable state + chainType := v1_6.SimulationTest for selector := range e.Chains { - ocrConfigPerSelector[selector] = v1_6.DeriveCCIPOCRParams(v1_6.WithDefaultCommitOffChainConfig(feedChainSel, nil), - v1_6.WithDefaultExecuteOffChainConfig(nil), - ) + commitOCRConfigPerSelector[selector] = v1_6.DeriveOCRParamsForCommit(chainType, feedChainSel, nil, nil) + execOCRConfigPerSelector[selector] = v1_6.DeriveOCRParamsForExec(chainType, nil, nil) } var commitChangeset commonchangeset.ConfiguredChangeSet @@ -548,7 +554,7 @@ func mustOCR(e *deployment.Environment, homeChainSel uint64, feedChainSel uint64 FeedChainSelector: feedChainSel, }, PluginInfo: v1_6.SetCandidatePluginInfo{ - OCRConfigPerRemoteChainSelector: ocrConfigPerSelector, + OCRConfigPerRemoteChainSelector: commitOCRConfigPerSelector, PluginType: types.PluginTypeCCIPCommit, }, }, @@ -564,7 +570,7 @@ func mustOCR(e *deployment.Environment, homeChainSel uint64, feedChainSel uint64 }, PluginInfo: []v1_6.SetCandidatePluginInfo{ { - OCRConfigPerRemoteChainSelector: ocrConfigPerSelector, + OCRConfigPerRemoteChainSelector: commitOCRConfigPerSelector, PluginType: types.PluginTypeCCIPCommit, }, }, @@ -584,7 +590,7 @@ func mustOCR(e *deployment.Environment, homeChainSel uint64, feedChainSel uint64 }, PluginInfo: []v1_6.SetCandidatePluginInfo{ { - OCRConfigPerRemoteChainSelector: ocrConfigPerSelector, + OCRConfigPerRemoteChainSelector: execOCRConfigPerSelector, PluginType: types.PluginTypeCCIPExec, }, }, diff --git a/deployment/go.mod b/deployment/go.mod index 861b7e8515e..b12dfce7300 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -12,6 +12,7 @@ replace github.com/smartcontractkit/chainlink/v2 => ../ require github.com/smartcontractkit/chainlink/v2 v2.0.0-20250221182743-098d1b0a763a require ( + dario.cat/mergo v1.0.1 github.com/Khan/genqlient v0.7.0 github.com/Masterminds/semver/v3 v3.3.1 github.com/aptos-labs/aptos-go-sdk v1.5.0 @@ -58,7 +59,6 @@ require ( require ( cosmossdk.io/errors v1.0.1 // indirect cosmossdk.io/math v1.3.0 // indirect - dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect diff --git a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go index 96e99ec4929..5f49c15e4a4 100644 --- a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go @@ -29,8 +29,11 @@ func Test_CCIPGasPriceUpdates(t *testing.T) { var gasPriceExpiry = 5 * time.Second e, _, _ := testsetups.NewIntegrationEnvironment(t, - testhelpers.WithOCRConfigOverride(func(params *v1_6.CCIPOCRParams) { - params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(gasPriceExpiry) + testhelpers.WithOCRConfigOverride(func(params v1_6.CCIPOCRParams) v1_6.CCIPOCRParams { + if params.CommitOffChainConfig != nil { + params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(gasPriceExpiry) + } + return params }), ) state, err := changeset.LoadOnchainState(e.Env) diff --git a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go index 12ada106764..f299b36b35c 100644 --- a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go @@ -31,8 +31,11 @@ func Test_CCIPTokenPriceUpdates(t *testing.T) { var tokenPriceExpiry = 5 * time.Second e, _, _ := testsetups.NewIntegrationEnvironment(t, - testhelpers.WithOCRConfigOverride(func(params *v1_6.CCIPOCRParams) { - params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(tokenPriceExpiry) + testhelpers.WithOCRConfigOverride(func(params v1_6.CCIPOCRParams) v1_6.CCIPOCRParams { + if params.CommitOffChainConfig != nil { + params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(tokenPriceExpiry) + } + return params })) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err)