-
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 - Initial Add Chain changeset #15349
Conversation
…ccip-4308-optimize-docker-tests
…t/chainlink into ccip-4158-add-chain
…ccip-4158-add-chain
deployment/ccip/changeset/deploy.go
Outdated
} | ||
|
||
// DeployPrerequisiteContracts deploys the contracts that can be ported from previous CCIP version to the new one. | ||
// This is only required for staging and test environments where the contracts are not already deployed. | ||
func DeployPrerequisiteContracts(e deployment.Environment, ab deployment.AddressBook, state CCIPOnChainState, chain deployment.Chain) error { | ||
func DeployPrerequisiteContracts(e deployment.Environment, ab deployment.AddressBook, state CCIPOnChainState, chain deployment.Chain, usdcEnabled bool) error { |
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.
Can we make this function take a variadic or something at the end? I assume I can do something similar to this in the multicall3 PR
type Options struct {
USDCEnabled bool
Multicall3Enabled bool
}
type DeployOpt func(o *Options)
func WithUSDC(enabled bool) DeployOpt {
return func(o *Options) {
o.USDCEnabled = enabled
}
}
func WithMulticall3(enabled bool) DeployOpt {
return func(o *Options) {
o.Multicall3Enabled = enabled
}
}
func DeployPrerequisiteContracts(e deployment.Environment, ab deployment.AddressBook, state CCIPOnChainState, chain deployment.Chain, deployOpts ...DeployOpt) {
options := &Options{}
for _, deployOpt := range deployOpts {
deployOpt(options)
}
// use options.USDCEnabled
}
@@ -242,15 +244,10 @@ func mockAttestationResponse() *httptest.Server { | |||
return server | |||
} | |||
|
|||
func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, numChains int, numNodes int) DeployedEnv { | |||
func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, numChains int, numNodes int, isUSDC bool) DeployedEnv { |
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.
I think this would benefit greatly from using the options pattern I mentioned above, everything after lggr logger.Logger
can be an option
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.
in this case maybe just a TestConfig struct would be easier? Its more like regular configuration so option funcs might be overkill
deployment/common/changeset/apply.go
Outdated
signed, err := SignProposal(e, &prop) | ||
if err != nil { | ||
return deployment.Environment{}, fmt.Errorf("failed to sign proposal: %w", err) | ||
} | ||
for _, sel := range chains.ToSlice() { | ||
timelock, ok := timelocksPerChain[sel] | ||
if !ok || timelock == nil { | ||
return deployment.Environment{}, fmt.Errorf("timelock not found for chain %d", sel) | ||
} | ||
err := ExecuteProposal(e, signed, timelock, sel) |
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.
Is this func expected to be used only in tests? Signs + executes the proposal seems to suggest that, but not 100% sure
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.
yeah it is. Lets name the file test_helpers.go to be clear
t *testing.T, | ||
lggr logger.Logger) (changeset.DeployedEnv, *test_env.CLClusterTestEnv, testconfig.TestConfig) { | ||
return NewLocalDevEnvironment(t, lggr, changeset.MockLinkPrice, changeset.MockWethPrice) | ||
func NewLocalDevEnvironmentWithDefaultPrice(t *testing.T, lggr logger.Logger, isUSDC bool) (changeset.DeployedEnv, *test_env.CLClusterTestEnv, tc.TestConfig) { |
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.
Ditto here and below re: options
}, | ||
}, | ||
} | ||
ctx = testcontext.Get(t) |
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.
This seems unnecessary
|
||
state, err := changeset.LoadOnchainState(*e) | ||
// Need to deploy prerequisites first so that we can for the CCIP contracts. | ||
cs01 := []commonchangeset.ChangesetApplication{ |
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.
cs01 := []commonchangeset.ChangesetApplication{ | |
prereqChangesets := []commonchangeset.ChangesetApplication{ |
API: endpoint, | ||
APITimeout: commonconfig.MustNewDuration(time.Second), | ||
APIInterval: commonconfig.MustNewDuration(500 * time.Millisecond), | ||
USDCCCTPConfig := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) |
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.
USDCCCTPConfig := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) | |
usdcCCTPConfig := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) |
} | ||
|
||
// Deploy second set of changesets to deploy and configure the CCIP contracts. | ||
cs02 := []commonchangeset.ChangesetApplication{ |
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.
cs02 := []commonchangeset.ChangesetApplication{ | |
deployCCIPChangesets := []commonchangeset.ChangesetApplication{ |
deployment/common/changeset/apply.go
Outdated
signed, err := SignProposal(e, &prop) | ||
if err != nil { | ||
return deployment.Environment{}, fmt.Errorf("failed to sign proposal: %w", err) | ||
} | ||
for _, sel := range chains.ToSlice() { | ||
timelock, ok := timelocksPerChain[sel] | ||
if !ok || timelock == nil { | ||
return deployment.Environment{}, fmt.Errorf("timelock not found for chain %d", sel) | ||
} | ||
err := ExecuteProposal(e, signed, timelock, sel) |
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.
yeah it is. Lets name the file test_helpers.go to be clear
@@ -42,62 +43,81 @@ func SingleGroupMCMS(t *testing.T) config.Config { | |||
return *c | |||
} | |||
|
|||
func SignProposal(t *testing.T, env deployment.Environment, proposal *timelock.MCMSWithTimelockProposal) *mcms.Executor { |
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.
why the change here? its kind of nice that the testing arg makes it clear its for test only
@@ -42,6 +42,8 @@ func (cfg ExistingContractsConfig) Validate() error { | |||
return nil | |||
} | |||
|
|||
// SaveExistingContracts saves the existing contracts to the address book. | |||
// Caller should update the environment's address book with the returned addresses. | |||
func SaveExistingContracts(env deployment.Environment, cfg ExistingContractsConfig) (deployment.ChangesetOutput, error) { |
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.
can we move the test here too and modify it to be abstract? thats more like a unit test which should be as close as possible to the code its testing
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.
I added a test here but kept the ccip specific test too
@@ -242,15 +244,10 @@ func mockAttestationResponse() *httptest.Server { | |||
return server | |||
} | |||
|
|||
func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, numChains int, numNodes int) DeployedEnv { | |||
func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, numChains int, numNodes int, isUSDC bool) DeployedEnv { |
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.
in this case maybe just a TestConfig struct would be easier? Its more like regular configuration so option funcs might be overkill
deployment/common/changeset/apply.go
Outdated
) | ||
|
||
type ChangesetApplication struct { | ||
Changeset func(e deployment.Environment, config any) (deployment.ChangesetOutput, error) |
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.
you can do deployment.ChangeSet[any]
here no need to redefine
deployment/ccip/changeset/deploy.go
Outdated
APIInterval *commonconfig.Duration | ||
} | ||
|
||
type DeployCCIPContractConfig struct { |
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.
since this is top level changeset input config, lets put it in the changeset file itself
// - AddChainConfig + AddDON (candidate->primary promotion i.e. init) on the home chain | ||
// - SetOCR3Config on the remote chain | ||
// ConfigureChain assumes that the home chain is already enabled and all CCIP contracts are already deployed. | ||
func InitialAddChain(env deployment.Environment, c DeployCCIPContractConfig) (deployment.ChangesetOutput, error) { |
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.
should be plural as its adding multiple? Maybe just ConfigureNewChains
"github.com/smartcontractkit/chainlink/deployment" | ||
) | ||
|
||
var _ deployment.ChangeSet[DeployCCIPContractConfig] = InitialAddChain |
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.
definitely should rename this config struct - NewChainsConfig? Also lets keep the definition of the config here
deployment/ccip/changeset/deploy.go
Outdated
HomeChainSel uint64 | ||
FeedChainSel uint64 | ||
ChainsToDeploy []uint64 | ||
TokenConfig TokenConfig |
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.
hmm doesn't the token config vary by chain @makramkd ?
deployment/ccip/changeset/deploy.go
Outdated
USDCConfig USDCConfig | ||
// For setting OCR configuration | ||
OCRSecrets deployment.OCRSecrets | ||
} |
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.
we need to parameterize the chain configuration values as well those are just hard coded right now
GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), |
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.
also I think the OCR timing parameters need to be parameterized and could vary by 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.
added ticket ccip-4320
|
||
type PrerequisiteOpt func(o *DeployPrerequisiteContractsOpts) | ||
|
||
func WithUSDCChains(chains []uint64) PrerequisiteOpt { |
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.
these still don't look very useful to me, whats wrong with just using the struct directly?
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.
It makes the DeployPrerequisite signature constant and helps adding more options. Otherwise for multicall there needs to be another bool addition to deployChainContracts
deployment/ccip/changeset/deploy.go
Outdated
// It then deploys the rest of the CCIP chain contracts to the selected chains | ||
// registers the nodes with the capability registry and creates a DON for | ||
// each new chain. | ||
func DeployCCIPContracts( |
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.
can be private
deployment/ccip/changeset/deploy.go
Outdated
|
||
return nil | ||
} | ||
|
||
func DeployChainContractsForChains( |
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.
can be private
} | ||
deployGrp.Go( | ||
func() error { | ||
err := deployChainContracts(e, chain, ab, rmnHome) |
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.
I'm not certain that rmnHome etc are threadsafe - maybe we come back to this idea in a follow up?
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.
This does not deal with any home contract write operation. Just deploys chain contracts in different chains
// DeployChainContracts deploys all new CCIP v1.6 or later contracts for the given chains. | ||
// It returns the new addresses for the contracts. | ||
// 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. |
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.
ah so it is already idempotent now? Lets explicitly mention that
@@ -21,61 +15,11 @@ import ( | |||
|
|||
func TestInitialDeploy(t *testing.T) { |
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.
I see ok, we can come back to it then
deployment/environment.go
Outdated
@@ -76,6 +76,17 @@ type Environment struct { | |||
Offchain OffchainClient | |||
} | |||
|
|||
func (e Environment) Copy() (Environment, error) { |
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.
I think this is confusing because its only does a deep copy of one field. Its more clear to just use the NewEnvironment constructor in ApplyChangesets and remove this
return e, fmt.Errorf("failed to apply changeset at index %d: %w", i, err) | ||
} | ||
if out.AddressBook != nil { | ||
err := currentEnv.ExistingAddresses.Merge(out.AddressBook) |
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.
we're planning on making ExistingAddresses read-only as per CCIP-4247. So I'd invert this:
newAddresses = out.AddressBook.Merge(currentEnv.ExistingAddresses)
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.
There is an issue with this. The consecutive changesets will load the state and try to look for previously deployed dependent contracts. that will fail if we do not update the existing addresses.
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.
Discussed offline and addressed
It addresses the InitialAddChain part in ticket CCIP-4158
Moves USDC contract deployment to DeployPrerequisites as these contracts are separate from ccip.
Creates
ChangesetApplication.Apply
so that multiple changesets can be applied from test as it would be followed in real deployment.Moves SaveExistingChangeset to common/changeset so that it can be used by all
Makes all contract deployment across different chains parallel.
Creates separate go routine for funding of nodes in different chains
Updates few function to return error instead of relying on require.NoError