-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
CCIP-4158 chain contract changeset #15294
Changes from all commits
ba9a204
c497d80
7c1855c
78993c0
191e5c4
80e0ee1
c6f6fd0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package changeset | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" | ||
|
||
"github.com/smartcontractkit/chainlink/deployment" | ||
ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" | ||
) | ||
|
||
var _ deployment.ChangeSet[DeployChainContractsConfig] = DeployChainContracts | ||
|
||
func DeployChainContracts(env deployment.Environment, c DeployChainContractsConfig) (deployment.ChangesetOutput, error) { | ||
newAddresses := deployment.NewMemoryAddressBook() | ||
err := ccipdeployment.DeployChainContractsForChains(env, newAddresses, c.HomeChainSelector, c.ChainSelectors, c.MCMSCfg) | ||
if err != nil { | ||
env.Logger.Errorw("Failed to deploy CCIP contracts", "err", err, "newAddresses", newAddresses) | ||
return deployment.ChangesetOutput{AddressBook: newAddresses}, deployment.MaybeDataErr(err) | ||
} | ||
return deployment.ChangesetOutput{ | ||
Proposals: []timelock.MCMSWithTimelockProposal{}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are all of these changesets going to be converted to use MCMS? Or is MCMS for post-deployment processes only (transferring ownership, setting config, etc.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MCMS for post deployment |
||
AddressBook: newAddresses, | ||
JobSpecs: nil, | ||
}, nil | ||
} | ||
|
||
type DeployChainContractsConfig struct { | ||
ChainSelectors []uint64 | ||
HomeChainSelector uint64 | ||
MCMSCfg ccipdeployment.MCMSConfig | ||
} | ||
|
||
func (c DeployChainContractsConfig) Validate() error { | ||
for _, cs := range c.ChainSelectors { | ||
if err := deployment.IsValidChainSelector(cs); err != nil { | ||
return fmt.Errorf("invalid chain selector: %d - %w", cs, err) | ||
} | ||
} | ||
if err := deployment.IsValidChainSelector(c.HomeChainSelector); err != nil { | ||
return fmt.Errorf("invalid home chain selector: %d - %w", c.HomeChainSelector, err) | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package changeset | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.uber.org/zap/zapcore" | ||
|
||
"github.com/smartcontractkit/chainlink/deployment" | ||
ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" | ||
"github.com/smartcontractkit/chainlink/deployment/environment/memory" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
) | ||
|
||
func TestDeployChainContractsChangeset(t *testing.T) { | ||
lggr := logger.TestLogger(t) | ||
e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ | ||
Bootstraps: 1, | ||
Chains: 2, | ||
Nodes: 4, | ||
}) | ||
selectors := e.AllChainSelectors() | ||
homeChainSel := selectors[0] | ||
nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) | ||
require.NoError(t, err) | ||
p2pIds := nodes.NonBootstraps().PeerIDs() | ||
// deploy home chain | ||
homeChainCfg := DeployHomeChainConfig{ | ||
HomeChainSel: homeChainSel, | ||
RMNStaticConfig: ccdeploy.NewTestRMNStaticConfig(), | ||
RMNDynamicConfig: ccdeploy.NewTestRMNDynamicConfig(), | ||
NodeOperators: ccdeploy.NewTestNodeOperator(e.Chains[homeChainSel].DeployerKey.From), | ||
NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ | ||
"NodeOperator": p2pIds, | ||
}, | ||
} | ||
output, err := DeployHomeChain(e, homeChainCfg) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Figuring out the correct order of incantations to get a functioning environment seems to be getting harder with all these new changesets, are we planning a more "hard to mess up" API in order to do things like this or nah? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or maybe for tests, a simple function that composes everything needed in order to get a functioning env There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I added this in #15288 FYI |
||
require.NoError(t, err) | ||
require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) | ||
|
||
// deploy pre-requisites | ||
prerequisites, err := DeployPrerequisites(e, DeployPrerequisiteConfig{ | ||
ChainSelectors: selectors, | ||
}) | ||
require.NoError(t, err) | ||
require.NoError(t, e.ExistingAddresses.Merge(prerequisites.AddressBook)) | ||
|
||
// deploy ccip chain contracts | ||
output, err = DeployChainContracts(e, DeployChainContractsConfig{ | ||
ChainSelectors: selectors, | ||
HomeChainSelector: homeChainSel, | ||
MCMSCfg: ccdeploy.NewTestMCMSConfig(t, e), | ||
}) | ||
require.NoError(t, err) | ||
require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) | ||
|
||
// load onchain state | ||
state, err := ccdeploy.LoadOnchainState(e) | ||
require.NoError(t, err) | ||
|
||
// verify all contracts populated | ||
require.NotNil(t, state.Chains[homeChainSel].CapabilityRegistry) | ||
require.NotNil(t, state.Chains[homeChainSel].CCIPHome) | ||
require.NotNil(t, state.Chains[homeChainSel].RMNHome) | ||
for _, sel := range selectors { | ||
require.NotNil(t, state.Chains[sel].LinkToken) | ||
require.NotNil(t, state.Chains[sel].Weth9) | ||
require.NotNil(t, state.Chains[sel].TokenAdminRegistry) | ||
require.NotNil(t, state.Chains[sel].RegistryModule) | ||
require.NotNil(t, state.Chains[sel].Router) | ||
require.NotNil(t, state.Chains[sel].RMNRemote) | ||
require.NotNil(t, state.Chains[sel].TestRouter) | ||
require.NotNil(t, state.Chains[sel].NonceManager) | ||
require.NotNil(t, state.Chains[sel].FeeQuoter) | ||
require.NotNil(t, state.Chains[sel].OffRamp) | ||
require.NotNil(t, state.Chains[sel].OnRamp) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package changeset | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" | ||
|
||
"github.com/smartcontractkit/chainlink/deployment" | ||
ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" | ||
) | ||
|
||
func Jobspec(env deployment.Environment, _ any) (deployment.ChangesetOutput, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment + how this is expected to be used in conjunction with all the other stuff would be useful There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also naming is kinda not great on this one |
||
js, err := ccipdeployment.NewCCIPJobSpecs(env.NodeIDs, env.Offchain) | ||
if err != nil { | ||
return deployment.ChangesetOutput{}, errors.Wrapf(err, "failed to create job specs") | ||
} | ||
return deployment.ChangesetOutput{ | ||
Proposals: []timelock.MCMSWithTimelockProposal{}, | ||
AddressBook: deployment.NewMemoryAddressBook(), | ||
JobSpecs: js, | ||
}, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package changeset | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.uber.org/zap/zapcore" | ||
|
||
"github.com/smartcontractkit/chainlink/deployment" | ||
"github.com/smartcontractkit/chainlink/deployment/environment/memory" | ||
ccip "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" | ||
"github.com/smartcontractkit/chainlink/v2/core/logger" | ||
) | ||
|
||
func TestJobSpecChangeset(t *testing.T) { | ||
lggr := logger.TestLogger(t) | ||
e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ | ||
Chains: 1, | ||
Nodes: 4, | ||
}) | ||
output, err := Jobspec(e, nil) | ||
require.NoError(t, err) | ||
require.NotNil(t, output.JobSpecs) | ||
nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) | ||
require.NoError(t, err) | ||
for _, node := range nodes { | ||
jobs, exists := output.JobSpecs[node.NodeID] | ||
require.True(t, exists) | ||
require.NotNil(t, jobs) | ||
for _, job := range jobs { | ||
_, err = ccip.ValidatedCCIPSpec(job) | ||
require.NoError(t, err) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -321,29 +321,11 @@ func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c | |||||
e.Logger.Errorw("Failed to get capability registry") | ||||||
return fmt.Errorf("capability registry not found") | ||||||
} | ||||||
cr, err := capReg.GetHashedCapabilityId( | ||||||
&bind.CallOpts{}, CapabilityLabelledName, CapabilityVersion) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get hashed capability id", "err", err) | ||||||
return err | ||||||
ccipHome := existingState.Chains[c.HomeChainSel].CCIPHome | ||||||
if ccipHome == nil { | ||||||
e.Logger.Errorw("Failed to get ccip home", "err", err) | ||||||
return fmt.Errorf("ccip home not found") | ||||||
} | ||||||
if cr != CCIPCapabilityID { | ||||||
return fmt.Errorf("capability registry does not support CCIP %s %s", hexutil.Encode(cr[:]), hexutil.Encode(CCIPCapabilityID[:])) | ||||||
} | ||||||
capability, err := capReg.GetCapability(nil, CCIPCapabilityID) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get capability", "err", err) | ||||||
return err | ||||||
} | ||||||
ccipHome, err := ccip_home.NewCCIPHome(capability.ConfigurationContract, e.Chains[c.HomeChainSel].Client) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get ccip config", "err", err) | ||||||
return err | ||||||
} | ||||||
if ccipHome.Address() != existingState.Chains[c.HomeChainSel].CCIPHome.Address() { | ||||||
return fmt.Errorf("ccip home address mismatch") | ||||||
} | ||||||
|
||||||
rmnHome := existingState.Chains[c.HomeChainSel].RMNHome | ||||||
if rmnHome == nil { | ||||||
e.Logger.Errorw("Failed to get rmn home", "err", err) | ||||||
|
@@ -352,18 +334,10 @@ func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c | |||||
|
||||||
usdcConfiguration := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) | ||||||
for _, chainSel := range c.ChainsToDeploy { | ||||||
chain, ok := e.Chains[chainSel] | ||||||
if !ok { | ||||||
chain, exists := e.Chains[chainSel] | ||||||
if !exists { | ||||||
return fmt.Errorf("chain %d not found", chainSel) | ||||||
} | ||||||
if existingState.Chains[chainSel].LinkToken == nil || existingState.Chains[chainSel].Weth9 == nil { | ||||||
return fmt.Errorf("fee tokens not found for chain %d", chainSel) | ||||||
} | ||||||
err = DeployChainContracts(e, chain, ab, c.MCMSConfig, rmnHome) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
if c.USDCConfig.Enabled { | ||||||
token, pool, messenger, transmitter, err1 := DeployUSDC(e.Logger, chain, ab, existingState.Chains[chainSel]) | ||||||
if err1 != nil { | ||||||
|
@@ -383,10 +357,13 @@ func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c | |||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
err = DeployChainContractsForChains(e, ab, c.HomeChainSel, c.ChainsToDeploy, c.MCMSConfig) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to deploy chain contracts", "err", err) | ||||||
return err | ||||||
} | ||||||
for _, chainSel := range c.ChainsToDeploy { | ||||||
chain, _ := e.Chains[chainSel] | ||||||
|
||||||
chainAddresses, err := ab.AddressesForChain(chain.Selector) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get chain addresses", "err", err) | ||||||
|
@@ -553,6 +530,62 @@ func DeployMCMSContracts( | |||||
}, nil | ||||||
} | ||||||
|
||||||
func DeployChainContractsForChains(e deployment.Environment, ab deployment.AddressBook, homeChainSel uint64, chainsToDeploy []uint64, mcmsConfig MCMSConfig) error { | ||||||
existingState, err := LoadOnchainState(e) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to load existing onchain state", "err") | ||||||
return err | ||||||
} | ||||||
|
||||||
capReg := existingState.Chains[homeChainSel].CapabilityRegistry | ||||||
if capReg == nil { | ||||||
e.Logger.Errorw("Failed to get capability registry") | ||||||
return fmt.Errorf("capability registry not found") | ||||||
} | ||||||
cr, err := capReg.GetHashedCapabilityId( | ||||||
&bind.CallOpts{}, CapabilityLabelledName, CapabilityVersion) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get hashed capability id", "err", err) | ||||||
return err | ||||||
} | ||||||
if cr != CCIPCapabilityID { | ||||||
return fmt.Errorf("capability registry does not support CCIP %s %s", hexutil.Encode(cr[:]), hexutil.Encode(CCIPCapabilityID[:])) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would ultimately be a bug in the constant |
||||||
} | ||||||
capability, err := capReg.GetCapability(nil, CCIPCapabilityID) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get capability", "err", err) | ||||||
return err | ||||||
} | ||||||
ccipHome, err := ccip_home.NewCCIPHome(capability.ConfigurationContract, e.Chains[homeChainSel].Client) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to get ccip config", "err", err) | ||||||
return err | ||||||
} | ||||||
if ccipHome.Address() != existingState.Chains[homeChainSel].CCIPHome.Address() { | ||||||
return fmt.Errorf("ccip home address mismatch") | ||||||
} | ||||||
rmnHome := existingState.Chains[homeChainSel].RMNHome | ||||||
if rmnHome == nil { | ||||||
e.Logger.Errorw("Failed to get rmn home", "err", err) | ||||||
return fmt.Errorf("rmn home not found") | ||||||
} | ||||||
for _, chainSel := range chainsToDeploy { | ||||||
chain, ok := e.Chains[chainSel] | ||||||
if !ok { | ||||||
return fmt.Errorf("chain %d not found", chainSel) | ||||||
} | ||||||
if existingState.Chains[chainSel].LinkToken == nil || existingState.Chains[chainSel].Weth9 == nil { | ||||||
return fmt.Errorf("fee tokens not found for chain %d", chainSel) | ||||||
} | ||||||
err := DeployChainContracts(e, chain, ab, mcmsConfig, rmnHome) | ||||||
if err != nil { | ||||||
e.Logger.Errorw("Failed to deploy chain contracts", "chain", chainSel, "err", err) | ||||||
return fmt.Errorf("failed to deploy chain contracts for chain %d: %w", chainSel, err) | ||||||
} | ||||||
} | ||||||
return nil | ||||||
} | ||||||
|
||||||
func DeployChainContracts( | ||||||
e deployment.Environment, | ||||||
chain deployment.Chain, | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments on these would be nice