Skip to content

Commit

Permalink
RMNProxy changes
Browse files Browse the repository at this point in the history
  • Loading branch information
AnieeG committed Dec 13, 2024
1 parent 5f6d2d5 commit 93232f8
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 37 deletions.
24 changes: 18 additions & 6 deletions deployment/ccip/changeset/cs_deploy_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ var _ deployment.ChangeSet[DeployChainContractsConfig] = DeployChainContracts
// DeployChainContracts is idempotent. If there is an error, it will return the successfully deployed addresses and the error so that the caller can call the
// changeset again with the same input to retry the failed deployment.
// Caller should update the environment's address book with the returned addresses.
// Points to note :
// In case of migrating from legacy ccip to 1.6, the previous RMN address should be set while deploying RMNRemote.
// if there is no existing RMN address found, RMNRemote will be deployed with 0x0 address for previous RMN address
// which will set RMN to 0x0 address immutably in RMNRemote.
func DeployChainContracts(env deployment.Environment, c DeployChainContractsConfig) (deployment.ChangesetOutput, error) {
if err := c.Validate(); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("invalid DeployChainContractsConfig: %w", err)
Expand Down Expand Up @@ -192,6 +196,14 @@ func deployChainContracts(
} else {
e.Logger.Infow("receiver already deployed", "addr", chainState.Receiver.Address, "chain", chain.String())
}
var rmnLegacyAddr common.Address
if chainState.MockRMN != nil {
rmnLegacyAddr = chainState.MockRMN.Address()
}
// TODO add legacy RMN here when 1.5 contracts are available
if rmnLegacyAddr == (common.Address{}) {
e.Logger.Warnf("No legacy RMN contract found for chain %s, will not setRMN in RMNRemote", chain.String())
}
rmnRemoteContract := chainState.RMNRemote
if chainState.RMNRemote == nil {
// TODO: Correctly configure RMN remote.
Expand All @@ -201,8 +213,7 @@ func deployChainContracts(
chain.DeployerKey,
chain.Client,
chain.Selector,
// Indicates no legacy RMN contract
common.HexToAddress("0x0"),
rmnLegacyAddr,
)
return deployment.ContractDeploy[*rmn_remote.RMNRemote]{
rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev), err2,
Expand All @@ -216,6 +227,7 @@ func deployChainContracts(
} else {
e.Logger.Infow("rmn remote already deployed", "chain", chain.String(), "addr", chainState.RMNRemote.Address)
}

activeDigest, err := rmnHome.GetActiveDigest(&bind.CallOpts{})
if err != nil {
e.Logger.Errorw("Failed to get active digest", "chain", chain.String(), "err", err)
Expand All @@ -237,8 +249,8 @@ func deployChainContracts(

// we deploy a new RMNProxy so that RMNRemote can be tested first before pointing it to the main Existing RMNProxy
// To differentiate between the two RMNProxies, we will deploy new one with Version1_6_0_dev
rmnProxyContract := chainState.RMNProxyNew
if chainState.RMNProxyNew == nil {
rmnProxyContract := chainState.RMNProxy
if chainState.RMNProxy == nil {
// we deploy a new rmnproxy contract to test RMNRemote
rmnProxy, err := deployment.DeployContract(e.Logger, chain, ab,
func(chain deployment.Chain) deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract] {
Expand All @@ -252,12 +264,12 @@ func deployChainContracts(
}
})
if err != nil {
e.Logger.Errorw("Failed to deploy RMNProxyNew", "chain", chain.String(), "err", err)
e.Logger.Errorw("Failed to deploy RMNProxy", "chain", chain.String(), "err", err)
return err
}
rmnProxyContract = rmnProxy.Contract
} else {
e.Logger.Infow("rmn proxy already deployed", "chain", chain.String(), "addr", chainState.RMNProxyNew.Address)
e.Logger.Infow("rmn proxy already deployed", "chain", chain.String(), "addr", chainState.RMNProxy.Address)
}
if chainState.TestRouter == nil {
_, err := deployment.DeployContract(e.Logger, chain, ab,
Expand Down
6 changes: 3 additions & 3 deletions deployment/ccip/changeset/cs_prerequisites.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ func deployPrerequisiteContracts(e deployment.Environment, ab deployment.Address
weth9Contract = chainState.Weth9
tokenAdminReg = chainState.TokenAdminRegistry
registryModule = chainState.RegistryModule
rmnProxy = chainState.RMNProxyExisting
rmnProxy = chainState.RMNProxy
r = chainState.Router
mc3 = chainState.Multicall3
}
if rmnProxy == nil {
// we want to replicate the mainnet scenario where RMNProxy is already deployed with some existing RMN
// This will need us to use two different RMNProxy contracts
// 1. RMNProxyNew with RMNRemote - ( deployed later in chain contracts)
// 1. RMNProxy with RMNRemote - ( deployed later in chain contracts)
// 2. RMNProxyExisting with mockRMN - ( deployed here, replicating the behavior of existing RMNProxy with already set RMN)
rmn, err := deployment.DeployContract(lggr, chain, ab,
func(chain deployment.Chain) deployment.ContractDeploy[*mock_rmn_contract.MockRMNContract] {
Expand All @@ -149,7 +149,7 @@ func deployPrerequisiteContracts(e deployment.Environment, ab deployment.Address
chain.Client,
)
return deployment.ContractDeploy[*mock_rmn_contract.MockRMNContract]{
rmnAddr, rmn, tx2, deployment.NewTypeAndVersion(MockRMN, deployment.Version1_0_0), err2,
Address: rmnAddr, Contract: rmn, Tx: tx2, Tv: deployment.NewTypeAndVersion(MockRMN, deployment.Version1_0_0), Err: err2,
}
})
if err != nil {
Expand Down
100 changes: 100 additions & 0 deletions deployment/ccip/changeset/cs_update_rmn_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,113 @@ import (
"github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
)

type SetRMNRemoteOnRMNProxyConfig struct {
ChainSelectors []uint64
MCMSConfig *MCMSConfig
}

func (c SetRMNRemoteOnRMNProxyConfig) Validate(state CCIPOnChainState) error {
for _, chain := range c.ChainSelectors {
err := deployment.IsValidChainSelector(chain)
if err != nil {
return err
}
chainState, exists := state.Chains[chain]
if !exists {
return fmt.Errorf("chain %d not found in state", chain)
}
if chainState.RMNRemote == nil {
return fmt.Errorf("RMNRemote not found for chain %d", chain)
}
if chainState.RMNProxy == nil {
return fmt.Errorf("RMNProxy not found for chain %d", chain)
}
}
return nil
}

func SetRMNRemoteOnRMNProxy(e deployment.Environment, cfg SetRMNRemoteOnRMNProxyConfig) (deployment.ChangesetOutput, error) {
state, err := LoadOnchainState(e)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err)
}
if err := cfg.Validate(state); err != nil {
return deployment.ChangesetOutput{}, err
}
var timelockBatch []timelock.BatchChainOperation
multiSigs := make(map[uint64]*gethwrappers.ManyChainMultiSig)
timelocks := make(map[uint64]common.Address)
for _, sel := range cfg.ChainSelectors {
chain, exists := e.Chains[sel]
if !exists {
return deployment.ChangesetOutput{}, fmt.Errorf("chain %d not found", sel)
}
txOpts := chain.DeployerKey
if cfg.MCMSConfig != nil {
txOpts = deployment.SimTransactOpts()
}
mcmsOps, err := setRMNRemoteOnRMNProxyOp(txOpts, chain, state.Chains[sel], cfg.MCMSConfig != nil)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), err)
}
if cfg.MCMSConfig != nil {
timelockBatch = append(timelockBatch, timelock.BatchChainOperation{
ChainIdentifier: mcms.ChainIdentifier(sel),
Batch: []mcms.Operation{mcmsOps},
})
multiSigs[sel] = state.Chains[sel].ProposerMcm
timelocks[sel] = state.Chains[sel].Timelock.Address()
}
}
// If we're not using MCMS, we can just return now as we've already confirmed the transactions
if len(timelockBatch) == 0 {
return deployment.ChangesetOutput{}, nil
}
prop, err := proposalutils.BuildProposalFromBatches(
timelocks,
multiSigs,
timelockBatch,
fmt.Sprintf("proposal to set RMNRemote on RMNProxy for chains %v", cfg.ChainSelectors),
cfg.MCMSConfig.MinDelay,
)
if err != nil {
return deployment.ChangesetOutput{}, err
}
return deployment.ChangesetOutput{
Proposals: []timelock.MCMSWithTimelockProposal{
*prop,
},
}, nil
}

func setRMNRemoteOnRMNProxyOp(txOpts *bind.TransactOpts, chain deployment.Chain, chainState CCIPChainState, mcmsEnabled bool) (mcms.Operation, error) {
rmnProxy := chainState.RMNProxy
rmnRemoteAddr := chainState.RMNRemote.Address()
setRMNTx, err := rmnProxy.SetARM(txOpts, rmnRemoteAddr)
if err != nil {
return mcms.Operation{}, fmt.Errorf("failed to build call data/transaction to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), err)
}
if !mcmsEnabled {
_, err = deployment.ConfirmIfNoError(chain, setRMNTx, err)
if err != nil {
return mcms.Operation{}, fmt.Errorf("failed to confirm tx to set RMNRemote on RMNProxy for chain %s: %w", chain.String(), deployment.MaybeDataErr(err))
}
}
return mcms.Operation{
To: rmnProxy.Address(),
Data: setRMNTx.Data(),
Value: big.NewInt(0),
}, nil
}

type RMNNopConfig struct {
NodeIndex uint64
OffchainPublicKey [32]byte
Expand Down
37 changes: 9 additions & 28 deletions deployment/ccip/changeset/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,10 @@ type CCIPChainState struct {
commoncs.MCMSWithTimelockState
commoncs.LinkTokenState
commoncs.StaticLinkTokenState
OnRamp *onramp.OnRamp
OffRamp *offramp.OffRamp
FeeQuoter *fee_quoter.FeeQuoter
// We need 2 RMNProxy contracts because we are in the process of migrating to a new version.
// We will switch to the existing one once the migration is complete.
// This is the new RMNProxy contract that will be used for testing RMNRemote before migration.
// Initially RMNProxyNew will point to RMNRemote
RMNProxyNew *rmn_proxy_contract.RMNProxyContract
// Existing RMNProxy contract that is used in production, This already has existing 1.5 RMN set.
// once RMNRemote is tested with RMNProxyNew, as part of migration
// RMNProxyExisting will point to RMNRemote. This will switch over CCIP 1.5 to 1.6
OnRamp *onramp.OnRamp
OffRamp *offramp.OffRamp
FeeQuoter *fee_quoter.FeeQuoter
RMNProxy *rmn_proxy_contract.RMNProxyContract
RMNProxyExisting *rmn_proxy_contract.RMNProxyContract
NonceManager *nonce_manager.NonceManager
TokenAdminRegistry *token_admin_registry.TokenAdminRegistry
Expand Down Expand Up @@ -209,12 +202,12 @@ func (c CCIPChainState) GenerateView() (view.ChainView, error) {
chainView.CommitStore[c.CommitStore.Address().Hex()] = commitStoreView
}

if c.RMNProxyNew != nil {
rmnProxyView, err := v1_0.GenerateRMNProxyView(c.RMNProxyNew)
if c.RMNProxy != nil {
rmnProxyView, err := v1_0.GenerateRMNProxyView(c.RMNProxy)
if err != nil {
return chainView, errors.Wrapf(err, "failed to generate rmn proxy view for rmn proxy %s", c.RMNProxyNew.Address().String())
return chainView, errors.Wrapf(err, "failed to generate rmn proxy view for rmn proxy %s", c.RMNProxy.Address().String())
}
chainView.RMNProxy[c.RMNProxyNew.Address().Hex()] = rmnProxyView
chainView.RMNProxy[c.RMNProxy.Address().Hex()] = rmnProxyView
}
if c.CCIPHome != nil && c.CapabilityRegistry != nil {
chView, err := v1_6.GenerateCCIPHomeView(c.CapabilityRegistry, c.CCIPHome)
Expand Down Expand Up @@ -361,19 +354,7 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type
if err != nil {
return state, err
}
state.RMNProxyExisting = armProxy
case deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_6_0_dev).String():
armProxy, err := rmn_proxy_contract.NewRMNProxyContract(common.HexToAddress(address), chain.Client)
if err != nil {
return state, err
}
state.RMNProxyNew = armProxy
case deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_6_0_dev).String():
armProxy, err := rmn_proxy_contract.NewRMNProxyContract(common.HexToAddress(address), chain.Client)
if err != nil {
return state, err
}
state.RMNProxyNew = armProxy
state.RMNProxy = armProxy
case deployment.NewTypeAndVersion(MockRMN, deployment.Version1_0_0).String():
mockRMN, err := mock_rmn_contract.NewMockRMNContract(common.HexToAddress(address), chain.Client)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions deployment/ccip/changeset/test_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,12 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tc *TestConfigs, tEnv Test
HomeChainSelector: e.HomeChainSel,
},
},
{
Changeset: commonchangeset.WrapChangeSet(SetRMNRemoteOnRMNProxy),
Config: SetRMNRemoteOnRMNProxyConfig{
ChainSelectors: allChains,
},
},
})
require.NoError(t, err)

Expand Down

0 comments on commit 93232f8

Please sign in to comment.