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

Extract MCMS to deployment/common #15288

Merged
merged 18 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
25 changes: 1 addition & 24 deletions deployment/ccip/add_lane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,15 @@ import (
func TestAddLane(t *testing.T) {
t.Parallel()
// We add more chains to the chainlink nodes than the number of chains where CCIP is deployed.
e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 4, 4)
e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4)
// Here we have CR + nodes set up, but no CCIP contracts deployed.
state, err := LoadOnchainState(e.Env)
require.NoError(t, err)

selectors := e.Env.AllChainSelectors()
// deploy CCIP contracts on two chains
chain1, chain2 := selectors[0], selectors[1]

feeds := state.Chains[e.FeedChainSel].USDFeeds
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As there is now 3 changesets (prereqs, mcms + ccip contracts) you need to get a full system I just created a helper

tokenConfig := NewTestTokenConfig(feeds)
newAddresses := deployment.NewMemoryAddressBook()
err = DeployPrerequisiteChainContracts(e.Env, newAddresses, e.Env.AllChainSelectors())
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))

// Set up CCIP contracts and a DON per chain.
newAddresses = deployment.NewMemoryAddressBook()
err = DeployCCIPContracts(e.Env, newAddresses, DeployCCIPContractConfig{
HomeChainSel: e.HomeChainSel,
FeedChainSel: e.FeedChainSel,
TokenConfig: tokenConfig,
MCMSConfig: NewTestMCMSConfig(t, e.Env),
ChainsToDeploy: []uint64{chain1, chain2},
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
})
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))

// We expect no lanes available on any chain.
state, err = LoadOnchainState(e.Env)
require.NoError(t, err)
for _, sel := range []uint64{chain1, chain2} {
chain := state.Chains[sel]
offRamps, err := chain.Router.GetOffRamps(nil)
Expand Down
115 changes: 39 additions & 76 deletions deployment/ccip/changeset/active_candidate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ import (

"github.com/stretchr/testify/require"

jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job"

ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"

"github.com/smartcontractkit/chainlink/v2/core/logger"
)
Expand All @@ -27,47 +26,10 @@ func TestActiveCandidate(t *testing.T) {
t.Skipf("to be enabled after latest cl-ccip is compatible")

lggr := logger.TestLogger(t)
ctx := ccdeploy.Context(t)
tenv := ccdeploy.NewMemoryEnvironment(t, lggr, 3, 5, ccdeploy.MockLinkPrice, ccdeploy.MockWethPrice)
tenv := ccdeploy.NewMemoryEnvironmentWithJobsAndContracts(t, lggr, 3, 5)
e := tenv.Env

state, err := ccdeploy.LoadOnchainState(tenv.Env)
require.NoError(t, err)
require.NotNil(t, state.Chains[tenv.HomeChainSel].LinkToken)

feeds := state.Chains[tenv.FeedChainSel].USDFeeds
tokenConfig := ccdeploy.NewTestTokenConfig(feeds)

output, err := InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{
HomeChainSel: tenv.HomeChainSel,
FeedChainSel: tenv.FeedChainSel,
ChainsToDeploy: tenv.Env.AllChainSelectors(),
TokenConfig: tokenConfig,
MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e),
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
})
require.NoError(t, err)
// Get new state after migration.
require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook))
state, err = ccdeploy.LoadOnchainState(tenv.Env)
require.NoError(t, err)
homeCS, destCS := tenv.HomeChainSel, tenv.FeedChainSel

// Ensure capreg logs are up to date.
ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks)

// Apply the jobs.
for nodeID, jobs := range output.JobSpecs {
for _, job := range jobs {
// Note these auto-accept
_, err := e.Offchain.ProposeJob(ctx,
&jobv1.ProposeJobRequest{
NodeId: nodeID,
Spec: job,
})
require.NoError(t, err)
}
}

// Add all lanes
require.NoError(t, ccdeploy.AddLanesForAll(e, state))
Expand Down Expand Up @@ -111,23 +73,23 @@ func TestActiveCandidate(t *testing.T) {
ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks)

// transfer ownership
ccdeploy.TransferAllOwnership(t, state, homeCS, e)
acceptOwnershipProposal, err := ccdeploy.GenerateAcceptOwnershipProposal(state, homeCS, e.AllChainSelectors())
ccdeploy.TransferAllOwnership(t, state, tenv.HomeChainSel, e)
acceptOwnershipProposal, err := ccdeploy.GenerateAcceptOwnershipProposal(state, tenv.HomeChainSel, e.AllChainSelectors())
require.NoError(t, err)
acceptOwnershipExec := ccdeploy.SignProposal(t, e, acceptOwnershipProposal)
acceptOwnershipExec := commonchangeset.SignProposal(t, e, acceptOwnershipProposal)
for _, sel := range e.AllChainSelectors() {
ccdeploy.ExecuteProposal(t, e, acceptOwnershipExec, state, sel)
commonchangeset.ExecuteProposal(t, e, acceptOwnershipExec, state.Chains[sel].Timelock, sel)
}
// Apply the accept ownership proposal to all the chains.

err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, homeCS, destCS, 2)
err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, tenv.HomeChainSel, tenv.FeedChainSel, 2)
require.NoError(t, err)

// [ACTIVE, CANDIDATE] setup by setting candidate through cap reg
capReg, ccipHome := state.Chains[homeCS].CapabilityRegistry, state.Chains[homeCS].CCIPHome
donID, err := ccdeploy.DonIDForChain(capReg, ccipHome, destCS)
capReg, ccipHome := state.Chains[tenv.HomeChainSel].CapabilityRegistry, state.Chains[tenv.HomeChainSel].CCIPHome
donID, err := ccdeploy.DonIDForChain(capReg, ccipHome, tenv.FeedChainSel)
require.NoError(t, err)
donInfo, err := state.Chains[homeCS].CapabilityRegistry.GetDON(nil, donID)
donInfo, err := state.Chains[tenv.HomeChainSel].CapabilityRegistry.GetDON(nil, donID)
require.NoError(t, err)
require.Equal(t, 5, len(donInfo.NodeP2PIds))
require.Equal(t, uint32(4), donInfo.ConfigCount)
Expand All @@ -151,13 +113,14 @@ func TestActiveCandidate(t *testing.T) {

// this will construct ocr3 configurations for the
// commit and exec plugin we will be using
rmnHomeAddress := state.Chains[homeCS].RMNHome.Address()
rmnHomeAddress := state.Chains[tenv.HomeChainSel].RMNHome.Address()
tokenConfig := ccdeploy.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds)
ocr3ConfigMap, err := ccdeploy.BuildOCR3ConfigForCCIPHome(
deployment.XXXGenerateTestOCRSecrets(),
state.Chains[destCS].OffRamp,
e.Chains[destCS],
destCS,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[destCS].LinkToken, state.Chains[destCS].Weth9),
state.Chains[tenv.FeedChainSel].OffRamp,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why feedChainSel instead of destCS?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

destCS was feedChainSel

e.Chains[tenv.FeedChainSel],
tenv.FeedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[tenv.FeedChainSel].LinkToken, state.Chains[tenv.FeedChainSel].Weth9),
nodes.NonBootstraps(),
rmnHomeAddress,
nil,
Expand All @@ -166,82 +129,82 @@ func TestActiveCandidate(t *testing.T) {

setCommitCandidateOp, err := ccdeploy.SetCandidateOnExistingDon(
ocr3ConfigMap[cctypes.PluginTypeCCIPCommit],
state.Chains[homeCS].CapabilityRegistry,
state.Chains[homeCS].CCIPHome,
destCS,
state.Chains[tenv.HomeChainSel].CapabilityRegistry,
state.Chains[tenv.HomeChainSel].CCIPHome,
tenv.FeedChainSel,
nodes.NonBootstraps(),
)
require.NoError(t, err)
setCommitCandidateProposal, err := ccdeploy.BuildProposalFromBatches(state, []timelock.BatchChainOperation{{
ChainIdentifier: mcms.ChainIdentifier(homeCS),
ChainIdentifier: mcms.ChainIdentifier(tenv.HomeChainSel),
Batch: setCommitCandidateOp,
}}, "set new candidates on commit plugin", 0)
require.NoError(t, err)
setCommitCandidateSigned := ccdeploy.SignProposal(t, e, setCommitCandidateProposal)
ccdeploy.ExecuteProposal(t, e, setCommitCandidateSigned, state, homeCS)
setCommitCandidateSigned := commonchangeset.SignProposal(t, e, setCommitCandidateProposal)
commonchangeset.ExecuteProposal(t, e, setCommitCandidateSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)

// create the op for the commit plugin as well
setExecCandidateOp, err := ccdeploy.SetCandidateOnExistingDon(
ocr3ConfigMap[cctypes.PluginTypeCCIPExec],
state.Chains[homeCS].CapabilityRegistry,
state.Chains[homeCS].CCIPHome,
destCS,
state.Chains[tenv.HomeChainSel].CapabilityRegistry,
state.Chains[tenv.HomeChainSel].CCIPHome,
tenv.FeedChainSel,
nodes.NonBootstraps(),
)
require.NoError(t, err)

setExecCandidateProposal, err := ccdeploy.BuildProposalFromBatches(state, []timelock.BatchChainOperation{{
ChainIdentifier: mcms.ChainIdentifier(homeCS),
ChainIdentifier: mcms.ChainIdentifier(tenv.HomeChainSel),
Batch: setExecCandidateOp,
}}, "set new candidates on commit and exec plugins", 0)
require.NoError(t, err)
setExecCandidateSigned := ccdeploy.SignProposal(t, e, setExecCandidateProposal)
ccdeploy.ExecuteProposal(t, e, setExecCandidateSigned, state, homeCS)
setExecCandidateSigned := commonchangeset.SignProposal(t, e, setExecCandidateProposal)
commonchangeset.ExecuteProposal(t, e, setExecCandidateSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)

// check setup was successful by confirming number of nodes from cap reg
donInfo, err = state.Chains[homeCS].CapabilityRegistry.GetDON(nil, donID)
donInfo, err = state.Chains[tenv.HomeChainSel].CapabilityRegistry.GetDON(nil, donID)
require.NoError(t, err)
require.Equal(t, 4, len(donInfo.NodeP2PIds))
require.Equal(t, uint32(6), donInfo.ConfigCount)
// [ACTIVE, CANDIDATE] done setup

// [ACTIVE, CANDIDATE] make sure we can still send successful transaction without updating job specs
err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, homeCS, destCS, 3)
err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, tenv.HomeChainSel, tenv.FeedChainSel, 3)
require.NoError(t, err)
// [ACTIVE, CANDIDATE] done send successful transaction on active

// [NEW ACTIVE, NO CANDIDATE] promote to active
// confirm by getting old candidate digest and making sure new active matches
oldCandidateDigest, err := state.Chains[homeCS].CCIPHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPExec))
oldCandidateDigest, err := state.Chains[tenv.HomeChainSel].CCIPHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPExec))
require.NoError(t, err)

promoteOps, err := ccdeploy.PromoteAllCandidatesForChainOps(state.Chains[homeCS].CapabilityRegistry, state.Chains[homeCS].CCIPHome, destCS, nodes.NonBootstraps())
promoteOps, err := ccdeploy.PromoteAllCandidatesForChainOps(state.Chains[tenv.HomeChainSel].CapabilityRegistry, state.Chains[tenv.HomeChainSel].CCIPHome, tenv.FeedChainSel, nodes.NonBootstraps())
require.NoError(t, err)
promoteProposal, err := ccdeploy.BuildProposalFromBatches(state, []timelock.BatchChainOperation{{
ChainIdentifier: mcms.ChainIdentifier(homeCS),
ChainIdentifier: mcms.ChainIdentifier(tenv.HomeChainSel),
Batch: promoteOps,
}}, "promote candidates and revoke actives", 0)
require.NoError(t, err)
promoteSigned := ccdeploy.SignProposal(t, e, promoteProposal)
ccdeploy.ExecuteProposal(t, e, promoteSigned, state, homeCS)
promoteSigned := commonchangeset.SignProposal(t, e, promoteProposal)
commonchangeset.ExecuteProposal(t, e, promoteSigned, state.Chains[tenv.HomeChainSel].Timelock, tenv.HomeChainSel)
// [NEW ACTIVE, NO CANDIDATE] done promoting

// [NEW ACTIVE, NO CANDIDATE] check onchain state
newActiveDigest, err := state.Chains[homeCS].CCIPHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPExec))
newActiveDigest, err := state.Chains[tenv.HomeChainSel].CCIPHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPExec))
require.NoError(t, err)
require.Equal(t, oldCandidateDigest, newActiveDigest)

newCandidateDigest, err := state.Chains[homeCS].CCIPHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit))
newCandidateDigest, err := state.Chains[tenv.HomeChainSel].CCIPHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit))
require.NoError(t, err)
require.Equal(t, newCandidateDigest, [32]byte{})
// [NEW ACTIVE, NO CANDIDATE] done checking on chain state

// [NEW ACTIVE, NO CANDIDATE] send successful request on new active
donInfo, err = state.Chains[homeCS].CapabilityRegistry.GetDON(nil, donID)
donInfo, err = state.Chains[tenv.HomeChainSel].CapabilityRegistry.GetDON(nil, donID)
require.NoError(t, err)
require.Equal(t, uint32(8), donInfo.ConfigCount)

err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, homeCS, destCS, 4)
err = ccdeploy.ConfirmRequestOnSourceAndDest(t, e, state, tenv.HomeChainSel, tenv.FeedChainSel, 4)
require.NoError(t, err)
// [NEW ACTIVE, NO CANDIDATE] done sending successful request
}
34 changes: 27 additions & 7 deletions deployment/ccip/changeset/add_chain_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package changeset

import (
"math/big"
"testing"
"time"

ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
commontypes "github.com/smartcontractkit/chainlink/deployment/common/types"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -41,14 +43,27 @@ func TestAddChainInbound(t *testing.T) {
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))

tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds)
cfg := commontypes.MCMSWithTimelockConfig{
Canceller: commonchangeset.SingleGroupMCMS(t),
Bypasser: commonchangeset.SingleGroupMCMS(t),
Proposer: commonchangeset.SingleGroupMCMS(t),
TimelockExecutors: e.Env.AllDeployerKeys(),
TimelockMinDelay: big.NewInt(0),
}
out, err := commonchangeset.DeployMCMSWithTimelock(e.Env, map[uint64]commontypes.MCMSWithTimelockConfig{
Copy link
Contributor

Choose a reason for hiding this comment

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

Use DeployMCMSWithTimelockContractsBatch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thats the internal impl

initialDeploy[0]: cfg,
initialDeploy[1]: cfg,
initialDeploy[2]: cfg,
})
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(out.AddressBook))
newAddresses = deployment.NewMemoryAddressBook()
tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds)
err = ccipdeployment.DeployCCIPContracts(e.Env, newAddresses, ccipdeployment.DeployCCIPContractConfig{
HomeChainSel: e.HomeChainSel,
FeedChainSel: e.FeedChainSel,
ChainsToDeploy: initialDeploy,
TokenConfig: tokenConfig,
MCMSConfig: ccipdeployment.NewTestMCMSConfig(t, e.Env),
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
})
require.NoError(t, err)
Expand All @@ -72,14 +87,19 @@ func TestAddChainInbound(t *testing.T) {
require.NoError(t, err)

// Deploy contracts to new chain
out, err = commonchangeset.DeployMCMSWithTimelock(e.Env, map[uint64]commontypes.MCMSWithTimelockConfig{
newChain: cfg,
})
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(out.AddressBook))

newAddresses = deployment.NewMemoryAddressBook()
err = ccipdeployment.DeployPrerequisiteChainContracts(e.Env, newAddresses, []uint64{newChain})
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))
newAddresses = deployment.NewMemoryAddressBook()
err = ccipdeployment.DeployChainContracts(e.Env,
e.Env.Chains[newChain], newAddresses,
ccipdeployment.NewTestMCMSConfig(t, e.Env), rmnHome)
e.Env.Chains[newChain], newAddresses, rmnHome)
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))
state, err = ccipdeployment.LoadOnchainState(e.Env)
Expand Down Expand Up @@ -117,10 +137,10 @@ func TestAddChainInbound(t *testing.T) {

acceptOwnershipProposal, err := ccipdeployment.GenerateAcceptOwnershipProposal(state, e.HomeChainSel, initialDeploy)
require.NoError(t, err)
acceptOwnershipExec := ccipdeployment.SignProposal(t, e.Env, acceptOwnershipProposal)
acceptOwnershipExec := commonchangeset.SignProposal(t, e.Env, acceptOwnershipProposal)
// Apply the accept ownership proposal to all the chains.
for _, sel := range initialDeploy {
ccipdeployment.ExecuteProposal(t, e.Env, acceptOwnershipExec, state, sel)
commonchangeset.ExecuteProposal(t, e.Env, acceptOwnershipExec, state.Chains[sel].Timelock, sel)
}
for _, chain := range initialDeploy {
owner, err2 := state.Chains[chain].OnRamp.Owner(nil)
Expand Down
19 changes: 18 additions & 1 deletion deployment/ccip/changeset/initial_deploy_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package changeset

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"

jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
commontypes "github.com/smartcontractkit/chainlink/deployment/common/types"

"github.com/smartcontractkit/chainlink/deployment"
ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip"

Expand All @@ -32,12 +36,25 @@ func TestInitialDeploy(t *testing.T) {
require.NoError(t, err)
require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook))

cfg := make(map[uint64]commontypes.MCMSWithTimelockConfig)
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the reason for not using the NewMemoryEnvironmentWithJobsAndContracts, I see it already does this as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

in this case we want to actually test the last step in NewMemoryEnvironmentWithJobsAndContracts

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),
}
}
output, err = commonchangeset.DeployMCMSWithTimelock(e, cfg)
require.NoError(t, err)
require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook))

output, err = InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{
HomeChainSel: tenv.HomeChainSel,
FeedChainSel: tenv.FeedChainSel,
ChainsToDeploy: tenv.Env.AllChainSelectors(),
TokenConfig: ccdeploy.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds),
MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e),
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
})
require.NoError(t, err)
Expand Down
Loading
Loading