Skip to content

Commit

Permalink
Ccip-5024 setDynamicConfig on offRamp (#16158)
Browse files Browse the repository at this point in the history
* remove deployCCIPContracts

* deprecate existing add lane

* add setDynamicConfig on offRamp
  • Loading branch information
AnieeG authored Jan 30, 2025
1 parent 68c6c9c commit 935d854
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 10 deletions.
130 changes: 123 additions & 7 deletions deployment/ccip/changeset/cs_chain_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ import (
)

var (
_ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDestsChangeset
_ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSourcesChangeset
_ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRampsChangeset
_ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDestsChangeset
_ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRampChangeset
_ deployment.ChangeSet[UpdateFeeQuoterPricesConfig] = UpdateFeeQuoterPricesChangeset
_ deployment.ChangeSet[UpdateNonceManagerConfig] = UpdateNonceManagersChangeset
_ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDestsChangeset
_ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSourcesChangeset
_ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRampsChangeset
_ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDestsChangeset
_ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRampChangeset
_ deployment.ChangeSet[UpdateDynamicConfigOffRampConfig] = UpdateDynamicConfigOffRampChangeset
_ deployment.ChangeSet[UpdateFeeQuoterPricesConfig] = UpdateFeeQuoterPricesChangeset
_ deployment.ChangeSet[UpdateNonceManagerConfig] = UpdateNonceManagersChangeset
)

type UpdateNonceManagerConfig struct {
Expand Down Expand Up @@ -1082,6 +1083,121 @@ func SetOCR3OffRampChangeset(e deployment.Environment, cfg SetOCR3OffRampConfig)
}}, nil
}

type UpdateDynamicConfigOffRampConfig struct {
Updates map[uint64]OffRampParams
MCMS *MCMSConfig
}

func (cfg UpdateDynamicConfigOffRampConfig) Validate(e deployment.Environment) error {
state, err := LoadOnchainState(e)
if err != nil {
return err
}
for chainSel, params := range cfg.Updates {
if deployment.IsValidChainSelector(chainSel) != nil {
return fmt.Errorf("invalid chain selector %d", chainSel)
}
if _, ok := state.Chains[chainSel]; !ok {
return fmt.Errorf("chain %d not found in onchain state", chainSel)
}
if state.Chains[chainSel].OffRamp == nil {
return fmt.Errorf("missing offramp for chain %d", chainSel)
}
if state.Chains[chainSel].FeeQuoter == nil {
return fmt.Errorf("missing fee quoter for chain %d", chainSel)
}
if state.Chains[chainSel].Timelock == nil {
return fmt.Errorf("missing timelock for chain %d", chainSel)
}
if params.GasForCallExactCheck > 0 {
e.Logger.Infow(
"GasForCallExactCheck is set, please note it's a static config and will be ignored for this changeset",
"chain", chainSel, "gas", params.GasForCallExactCheck)
}
if err := commoncs.ValidateOwnership(
e.GetContext(),
cfg.MCMS != nil,
e.Chains[chainSel].DeployerKey.From,
state.Chains[chainSel].Timelock.Address(),
state.Chains[chainSel].OffRamp,
); err != nil {
return err
}
if err := params.Validate(true); err != nil {
return fmt.Errorf("chain %d: %w", chainSel, err)
}
}
return nil
}

func UpdateDynamicConfigOffRampChangeset(e deployment.Environment, cfg UpdateDynamicConfigOffRampConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}
state, err := LoadOnchainState(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}
var batches []timelock.BatchChainOperation
timelocks := make(map[uint64]common.Address)
proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig)
for chainSel, params := range cfg.Updates {
chain := e.Chains[chainSel]
txOpts := e.Chains[chainSel].DeployerKey
if cfg.MCMS != nil {
txOpts = deployment.SimTransactOpts()
}
offRamp := state.Chains[chainSel].OffRamp
dCfg := offramp.OffRampDynamicConfig{
FeeQuoter: state.Chains[chainSel].FeeQuoter.Address(),
PermissionLessExecutionThresholdSeconds: params.PermissionLessExecutionThresholdSeconds,
IsRMNVerificationDisabled: params.IsRMNVerificationDisabled,
MessageInterceptor: params.MessageInterceptor,
}
tx, err := offRamp.SetDynamicConfig(txOpts, dCfg)
if err != nil {
return deployment.ChangesetOutput{}, err
}
if cfg.MCMS == nil {
if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil {
return deployment.ChangesetOutput{}, deployment.DecodedErrFromABIIfDataErr(err, offramp.OffRampABI)
}
e.Logger.Infow("Updated offramp dynamic config", "chain", chain.String(), "config", dCfg)
} else {
batches = append(batches, timelock.BatchChainOperation{
ChainIdentifier: mcms.ChainIdentifier(chainSel),
Batch: []mcms.Operation{
{
To: offRamp.Address(),
Data: tx.Data(),
Value: big.NewInt(0),
},
},
})
timelocks[chainSel] = state.Chains[chainSel].Timelock.Address()
proposers[chainSel] = state.Chains[chainSel].ProposerMcm
}
}
if cfg.MCMS == nil {
return deployment.ChangesetOutput{}, nil
}
p, err := proposalutils.BuildProposalFromBatches(
timelocks,
proposers,
batches,
"Update offramp dynamic config",
cfg.MCMS.MinDelay,
)

if err != nil {
return deployment.ChangesetOutput{}, err
}
e.Logger.Infow("Proposing offramp dynamic config update", "config", cfg.Updates)
return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{
*p,
}}, nil
}

func isOCR3ConfigSetOnOffRamp(
lggr logger.Logger,
chain deployment.Chain,
Expand Down
63 changes: 63 additions & 0 deletions deployment/ccip/changeset/cs_chain_contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter"
"github.com/smartcontractkit/chainlink/v2/evm/utils"
)

func TestUpdateOnRampsDests(t *testing.T) {
Expand Down Expand Up @@ -307,6 +308,68 @@ func TestUpdateRouterRamps(t *testing.T) {
}
}

func TestUpdateDynamicConfigOffRampChangeset(t *testing.T) {
for _, tc := range []struct {
name string
mcmsEnabled bool
}{
{
name: "MCMS enabled",
mcmsEnabled: true,
},
{
name: "MCMS disabled",
mcmsEnabled: false,
},
} {
t.Run(tc.name, func(t *testing.T) {
tenv, _ := testhelpers.NewMemoryEnvironment(t)
state, err := changeset.LoadOnchainState(tenv.Env)
require.NoError(t, err)

allChains := maps.Keys(tenv.Env.Chains)
source := allChains[0]
dest := allChains[1]

if tc.mcmsEnabled {
// Transfer ownership to timelock so that we can promote the zero digest later down the line.
transferToTimelock(t, tenv, state, source, dest)
}

var mcmsConfig *changeset.MCMSConfig
if tc.mcmsEnabled {
mcmsConfig = &changeset.MCMSConfig{
MinDelay: 0,
}
}
msgInterceptor := utils.RandomAddress()
_, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(changeset.UpdateDynamicConfigOffRampChangeset),
Config: changeset.UpdateDynamicConfigOffRampConfig{
Updates: map[uint64]changeset.OffRampParams{
source: {
PermissionLessExecutionThresholdSeconds: uint32(2 * 60 * 60),
IsRMNVerificationDisabled: false,
MessageInterceptor: msgInterceptor,
},
},
MCMS: mcmsConfig,
},
},
})
require.NoError(t, err)
// Assert the nonce manager configuration is as we expect.
actualConfig, err := state.Chains[source].OffRamp.GetDynamicConfig(nil)
require.NoError(t, err)
require.Equal(t, uint32(2*60*60), actualConfig.PermissionLessExecutionThresholdSeconds)
require.False(t, actualConfig.IsRMNVerificationDisabled)
require.Equal(t, msgInterceptor, actualConfig.MessageInterceptor)
require.Equal(t, state.Chains[source].FeeQuoter.Address(), actualConfig.FeeQuoter)
})
}
}

func TestUpdateNonceManagersCS(t *testing.T) {
for _, tc := range []struct {
name string
Expand Down
8 changes: 5 additions & 3 deletions deployment/ccip/changeset/cs_deploy_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (c ChainContractParams) Validate() error {
if err := c.FeeQuoterParams.Validate(); err != nil {
return fmt.Errorf("invalid FeeQuoterParams: %w", err)
}
if err := c.OffRampParams.Validate(); err != nil {
if err := c.OffRampParams.Validate(false); err != nil {
return fmt.Errorf("invalid OffRampParams: %w", err)
}
return nil
Expand Down Expand Up @@ -145,10 +145,11 @@ type OffRampParams struct {
GasForCallExactCheck uint16
PermissionLessExecutionThresholdSeconds uint32
IsRMNVerificationDisabled bool
MessageInterceptor common.Address
}

func (c OffRampParams) Validate() error {
if c.GasForCallExactCheck == 0 {
func (c OffRampParams) Validate(ignoreGasForCallExactCheck bool) error {
if !ignoreGasForCallExactCheck && c.GasForCallExactCheck == 0 {
return errors.New("GasForCallExactCheck is 0")
}
if c.PermissionLessExecutionThresholdSeconds == 0 {
Expand Down Expand Up @@ -496,6 +497,7 @@ func deployChainContractsEVM(e deployment.Environment, chain deployment.Chain, a
FeeQuoter: feeQuoterContract.Address(),
PermissionLessExecutionThresholdSeconds: contractParams.OffRampParams.PermissionLessExecutionThresholdSeconds,
IsRMNVerificationDisabled: contractParams.OffRampParams.IsRMNVerificationDisabled,
MessageInterceptor: contractParams.OffRampParams.MessageInterceptor,
},
[]offramp.OffRampSourceChainConfigArgs{},
)
Expand Down

0 comments on commit 935d854

Please sign in to comment.