Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy call proxy instead of using deployer executor keys #15559

Merged
merged 17 commits into from
Dec 10, 2024
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
15 changes: 10 additions & 5 deletions deployment/ccip/changeset/accept_ownership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"
Expand All @@ -29,9 +28,15 @@ func Test_NewAcceptOwnershipChangeset(t *testing.T) {
source := allChains[0]
dest := allChains[1]

timelocks := map[uint64]*gethwrappers.RBACTimelock{
source: state.Chains[source].Timelock,
dest: state.Chains[dest].Timelock,
timelockContracts := map[uint64]*commonchangeset.TimelockExecutionContracts{
source: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[source].Timelock,
CallProxy: state.Chains[source].CallProxy,
},
dest: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[dest].Timelock,
CallProxy: state.Chains[dest].CallProxy,
},
}

// at this point we have the initial deploys done, now we need to transfer ownership
Expand All @@ -40,7 +45,7 @@ func Test_NewAcceptOwnershipChangeset(t *testing.T) {
require.NoError(t, err)

// compose the transfer ownership and accept ownership changesets
_, err = commonchangeset.ApplyChangesets(t, e.Env, timelocks, []commonchangeset.ChangesetApplication{
_, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContracts, []commonchangeset.ChangesetApplication{
// note this doesn't have proposals.
{
Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock),
Expand Down
25 changes: 19 additions & 6 deletions deployment/ccip/changeset/cs_active_candidate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,15 @@ func TestActiveCandidate(t *testing.T) {
ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks)

// compose the transfer ownership and accept ownership changesets
timelocks := make(map[uint64]*gethwrappers.RBACTimelock)
timelockContracts := make(map[uint64]*commonchangeset.TimelockExecutionContracts)
for _, chain := range allChains {
timelocks[chain] = state.Chains[chain].Timelock
timelockContracts[chain] = &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[chain].Timelock,
CallProxy: state.Chains[chain].CallProxy,
}
}
_, err = commonchangeset.ApplyChangesets(t, e, timelocks, []commonchangeset.ChangesetApplication{

_, err = commonchangeset.ApplyChangesets(t, e, timelockContracts, []commonchangeset.ChangesetApplication{
// note this doesn't have proposals.
{
Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock),
Expand Down Expand Up @@ -177,7 +181,10 @@ func TestActiveCandidate(t *testing.T) {
}}, "set new candidates on commit plugin", 0)
require.NoError(t, err)
setCommitCandidateSigned := commonchangeset.SignProposal(t, e, setCommitCandidateProposal)
commonchangeset.ExecuteProposal(t, e, setCommitCandidateSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)
commonchangeset.ExecuteProposal(t, e, setCommitCandidateSigned, &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[tenv.HomeChainSel].Timelock,
CallProxy: state.Chains[tenv.HomeChainSel].CallProxy,
}, tenv.HomeChainSel)

// create the op for the commit plugin as well
setExecCandidateOp, err := setCandidateOnExistingDon(
Expand All @@ -195,7 +202,10 @@ func TestActiveCandidate(t *testing.T) {
}}, "set new candidates on commit and exec plugins", 0)
require.NoError(t, err)
setExecCandidateSigned := commonchangeset.SignProposal(t, e, setExecCandidateProposal)
commonchangeset.ExecuteProposal(t, e, setExecCandidateSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)
commonchangeset.ExecuteProposal(t, e, setExecCandidateSigned, &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[tenv.HomeChainSel].Timelock,
CallProxy: state.Chains[tenv.HomeChainSel].CallProxy,
}, tenv.HomeChainSel)

// check setup was successful by confirming number of nodes from cap reg
donInfo, err = state.Chains[tenv.HomeChainSel].CapabilityRegistry.GetDON(nil, donID)
Expand All @@ -222,7 +232,10 @@ func TestActiveCandidate(t *testing.T) {
}}, "promote candidates and revoke actives", 0)
require.NoError(t, err)
promoteSigned := commonchangeset.SignProposal(t, e, promoteProposal)
commonchangeset.ExecuteProposal(t, e, promoteSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)
commonchangeset.ExecuteProposal(t, e, promoteSigned, &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[tenv.HomeChainSel].Timelock,
CallProxy: state.Chains[tenv.HomeChainSel].CallProxy,
}, tenv.HomeChainSel)
// [NEW ACTIVE, NO CANDIDATE] done promoting

// [NEW ACTIVE, NO CANDIDATE] check onchain state
Expand Down
40 changes: 26 additions & 14 deletions deployment/ccip/changeset/cs_add_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"testing"
"time"

"github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"

"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
commontypes "github.com/smartcontractkit/chainlink/deployment/common/types"
Expand Down Expand Up @@ -52,11 +50,10 @@ func TestAddChainInbound(t *testing.T) {
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))

cfg := commontypes.MCMSWithTimelockConfig{
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockExecutors: e.Env.AllDeployerKeys(),
TimelockMinDelay: big.NewInt(0),
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockMinDelay: big.NewInt(0),
}
e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{
{
Expand Down Expand Up @@ -145,10 +142,19 @@ func TestAddChainInbound(t *testing.T) {
}

// transfer ownership to timelock
_, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*gethwrappers.RBACTimelock{
initialDeploy[0]: state.Chains[initialDeploy[0]].Timelock,
initialDeploy[1]: state.Chains[initialDeploy[1]].Timelock,
initialDeploy[2]: state.Chains[initialDeploy[2]].Timelock,
_, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*commonchangeset.TimelockExecutionContracts{
initialDeploy[0]: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[initialDeploy[0]].Timelock,
CallProxy: state.Chains[initialDeploy[0]].CallProxy,
},
initialDeploy[1]: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[initialDeploy[1]].Timelock,
CallProxy: state.Chains[initialDeploy[1]].CallProxy,
},
initialDeploy[2]: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[initialDeploy[2]].Timelock,
CallProxy: state.Chains[initialDeploy[2]].CallProxy,
},
}, []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock),
Expand Down Expand Up @@ -178,9 +184,15 @@ func TestAddChainInbound(t *testing.T) {
nodeIDs = append(nodeIDs, node.NodeID)
}

_, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*gethwrappers.RBACTimelock{
e.HomeChainSel: state.Chains[e.HomeChainSel].Timelock,
newChain: state.Chains[newChain].Timelock,
_, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*commonchangeset.TimelockExecutionContracts{
e.HomeChainSel: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[e.HomeChainSel].Timelock,
CallProxy: state.Chains[e.HomeChainSel].CallProxy,
},
newChain: &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[newChain].Timelock,
CallProxy: state.Chains[newChain].CallProxy,
},
}, []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(AddDonAndSetCandidateChangeset),
Expand Down
9 changes: 4 additions & 5 deletions deployment/ccip/changeset/cs_deploy_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ func TestDeployChainContractsChangeset(t *testing.T) {
cfg := make(map[uint64]commontypes.MCMSWithTimelockConfig)
for _, chain := range e.AllChainSelectors() {
cfg[chain] = commontypes.MCMSWithTimelockConfig{
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockExecutors: e.AllDeployerKeys(),
TimelockMinDelay: big.NewInt(0),
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockMinDelay: big.NewInt(0),
}
}
e, err = commonchangeset.ApplyChangesets(t, e, nil, []commonchangeset.ChangesetApplication{
Expand Down
13 changes: 8 additions & 5 deletions deployment/ccip/changeset/cs_update_rmn_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"
mcmsWrappers "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"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"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"
Expand Down Expand Up @@ -274,10 +274,13 @@ func NewPromoteCandidateConfigChangeset(e deployment.Environment, config Promote
}, nil
}

func buildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*mcmsWrappers.RBACTimelock {
timelocksPerChain := make(map[uint64]*mcmsWrappers.RBACTimelock)
func buildTimelockPerChain(e deployment.Environment, state CCIPOnChainState) map[uint64]*commonchangeset.TimelockExecutionContracts {
timelocksPerChain := make(map[uint64]*commonchangeset.TimelockExecutionContracts)
for _, chain := range e.Chains {
timelocksPerChain[chain.Selector] = state.Chains[chain.Selector].Timelock
timelocksPerChain[chain.Selector] = &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[chain.Selector].Timelock,
CallProxy: state.Chains[chain.Selector].CallProxy,
}
}
return timelocksPerChain
}
Expand All @@ -286,7 +289,7 @@ func buildTimelockAddressPerChain(e deployment.Environment, state CCIPOnChainSta
timelocksPerChain := buildTimelockPerChain(e, state)
timelockAddressPerChain := make(map[uint64]common.Address)
for chain, timelock := range timelocksPerChain {
timelockAddressPerChain[chain] = timelock.Address()
timelockAddressPerChain[chain] = timelock.Timelock.Address()
}
return timelockAddressPerChain
}
Expand Down
1 change: 1 addition & 0 deletions deployment/ccip/changeset/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type
for address, tvStr := range addresses {
switch tvStr.String() {
case deployment.NewTypeAndVersion(commontypes.RBACTimelock, deployment.Version1_0_0).String(),
deployment.NewTypeAndVersion(commontypes.CallProxy, deployment.Version1_0_0).String(),
deployment.NewTypeAndVersion(commontypes.ProposerManyChainMultisig, deployment.Version1_0_0).String(),
deployment.NewTypeAndVersion(commontypes.CancellerManyChainMultisig, deployment.Version1_0_0).String(),
deployment.NewTypeAndVersion(commontypes.BypasserManyChainMultisig, deployment.Version1_0_0).String(),
Expand Down
24 changes: 14 additions & 10 deletions deployment/ccip/changeset/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/pkg/errors"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers"

"github.com/smartcontractkit/chainlink-ccip/pluginconfig"
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
Expand Down Expand Up @@ -279,11 +278,10 @@ func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger,
mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig)
for _, c := range e.Env.AllChainSelectors() {
mcmsCfg[c] = commontypes.MCMSWithTimelockConfig{
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockExecutors: e.Env.AllDeployerKeys(),
TimelockMinDelay: big.NewInt(0),
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockMinDelay: big.NewInt(0),
}
}
var (
Expand Down Expand Up @@ -366,14 +364,17 @@ func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger,
}
// Build the per chain config.
chainConfigs := make(map[uint64]CCIPOCRParams)
timelocksPerChain := make(map[uint64]*gethwrappers.RBACTimelock)
timelockContractsPerChain := make(map[uint64]*commonchangeset.TimelockExecutionContracts)
for _, chain := range allChains {
timelocksPerChain[chain] = state.Chains[chain].Timelock
timelockContractsPerChain[chain] = &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[chain].Timelock,
CallProxy: state.Chains[chain].CallProxy,
}
tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9)
chainConfigs[chain] = DefaultOCRParams(e.FeedChainSel, tokenInfo, tokenDataProviders)
}
// Deploy second set of changesets to deploy and configure the CCIP contracts.
e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelocksPerChain, []commonchangeset.ChangesetApplication{
e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{
{
Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains),
Config: NewChainsConfig{
Expand Down Expand Up @@ -822,7 +823,10 @@ func ProcessChangeset(t *testing.T, e deployment.Environment, c deployment.Chang

signed := commonchangeset.SignProposal(t, e, &prop)
for _, sel := range chains.ToSlice() {
commonchangeset.ExecuteProposal(t, e, signed, state.Chains[sel].Timelock, sel)
commonchangeset.ExecuteProposal(t, e, signed, &commonchangeset.TimelockExecutionContracts{
Timelock: state.Chains[sel].Timelock,
CallProxy: state.Chains[sel].CallProxy,
}, sel)
}
}
}
Expand Down
43 changes: 39 additions & 4 deletions deployment/common/changeset/internal/mcms.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type MCMSWithTimelockDeploy struct {
Bypasser *deployment.ContractDeploy[*owner_helpers.ManyChainMultiSig]
Proposer *deployment.ContractDeploy[*owner_helpers.ManyChainMultiSig]
Timelock *deployment.ContractDeploy[*owner_helpers.RBACTimelock]
CallProxy *deployment.ContractDeploy[*owner_helpers.CallProxy]
}

func DeployMCMSWithTimelockContractsBatch(
Expand Down Expand Up @@ -106,10 +107,12 @@ func DeployMCMSWithTimelockContracts(
// TODO: Could expose this as config?
// Or keep this enforced to follow the same pattern?
chain.DeployerKey.From,
[]common.Address{proposer.Address}, // proposers
config.TimelockExecutors, //executors
[]common.Address{canceller.Address}, // cancellers
[]common.Address{bypasser.Address}, // bypassers
[]common.Address{proposer.Address}, // proposers
// Executors field is empty here because we grant the executor role to the call proxy later
// and the call proxy cannot be deployed before the timelock.
[]common.Address{},
[]common.Address{canceller.Address, proposer.Address, bypasser.Address}, // cancellers
[]common.Address{bypasser.Address}, // bypassers
)
return deployment.ContractDeploy[*owner_helpers.RBACTimelock]{
timelock, cc, tx2, deployment.NewTypeAndVersion(types.RBACTimelock, deployment.Version1_0_0), err2,
Expand All @@ -119,6 +122,37 @@ func DeployMCMSWithTimelockContracts(
lggr.Errorw("Failed to deploy timelock", "chain", chain.String(), "err", err)
return nil, err
}

callProxy, err := deployment.DeployContract(lggr, chain, ab,
func(chain deployment.Chain) deployment.ContractDeploy[*owner_helpers.CallProxy] {
callProxy, tx2, cc, err2 := owner_helpers.DeployCallProxy(
chain.DeployerKey,
chain.Client,
timelock.Address,
)
return deployment.ContractDeploy[*owner_helpers.CallProxy]{
callProxy, cc, tx2, deployment.NewTypeAndVersion(types.CallProxy, deployment.Version1_0_0), err2,
}
})
if err != nil {
lggr.Errorw("Failed to deploy call proxy", "chain", chain.String(), "err", err)
return nil, err
}

grantRoleTx, err := timelock.Contract.GrantRole(
chain.DeployerKey,
v1_0.EXECUTOR_ROLE.ID,
callProxy.Address,
)
if err != nil {
lggr.Errorw("Failed to grant timelock executor role", "chain", chain.String(), "err", err)
return nil, err
}

if _, err := deployment.ConfirmIfNoError(chain, grantRoleTx, err); err != nil {
lggr.Errorw("Failed to grant timelock executor role", "chain", chain.String(), "err", err)
return nil, err
}
// We grant the timelock the admin role on the MCMS contracts.
tx, err := timelock.Contract.GrantRole(chain.DeployerKey,
v1_0.ADMIN_ROLE.ID, timelock.Address)
Expand All @@ -133,5 +167,6 @@ func DeployMCMSWithTimelockContracts(
Bypasser: bypasser,
Proposer: proposer,
Timelock: timelock,
CallProxy: callProxy,
}, nil
}
12 changes: 4 additions & 8 deletions deployment/common/changeset/internal/mcms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
chainsel "github.com/smartcontractkit/chain-selectors"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -37,18 +36,15 @@ func TestDeployMCMSWithTimelockContracts(t *testing.T) {
_, err := internal.DeployMCMSWithTimelockContracts(lggr,
chains[chainsel.TEST_90000001.Selector],
ab, types.MCMSWithTimelockConfig{
Canceller: changeset.SingleGroupMCMS(t),
Bypasser: changeset.SingleGroupMCMS(t),
Proposer: changeset.SingleGroupMCMS(t),
TimelockExecutors: []common.Address{
chains[chainsel.TEST_90000001.Selector].DeployerKey.From,
},
Canceller: changeset.SingleGroupMCMS(t),
Bypasser: changeset.SingleGroupMCMS(t),
Proposer: changeset.SingleGroupMCMS(t),
TimelockMinDelay: big.NewInt(0),
})
require.NoError(t, err)
addresses, err := ab.AddressesForChain(chainsel.TEST_90000001.Selector)
require.NoError(t, err)
require.Len(t, addresses, 4)
require.Len(t, addresses, 5)
mcmsState, err := changeset.MaybeLoadMCMSWithTimelockState(chains[chainsel.TEST_90000001.Selector], addresses)
require.NoError(t, err)
v, err := mcmsState.GenerateMCMSWithTimelockView()
Expand Down
Loading
Loading