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

Ccip-4158 - Initial Add Chain changeset #15349

Merged
merged 33 commits into from
Nov 21, 2024
Merged

Ccip-4158 - Initial Add Chain changeset #15349

merged 33 commits into from
Nov 21, 2024

Conversation

AnieeG
Copy link
Contributor

@AnieeG AnieeG commented Nov 20, 2024

  • It addresses the InitialAddChain part in ticket CCIP-4158

    • Creates a changeset to AddChainConfig + AddDON (candidate->primary promotion i.e. init) on the home chain, SetOCR3Config on the remote chain
  • 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

@AnieeG AnieeG requested review from a team as code owners November 20, 2024 22:59
}

// 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 {
Copy link
Contributor

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 {
Copy link
Contributor

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

Copy link
Contributor

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 Show resolved Hide resolved
deployment/common/changeset/apply.go Outdated Show resolved Hide resolved
Comment on lines 73 to 82
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)
Copy link
Contributor

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

Copy link
Contributor

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) {
Copy link
Contributor

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)
Copy link
Contributor

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{
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
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)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
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{
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
cs02 := []commonchangeset.ChangesetApplication{
deployCCIPChangesets := []commonchangeset.ChangesetApplication{

Comment on lines 73 to 82
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)
Copy link
Contributor

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 {
Copy link
Contributor

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) {
Copy link
Contributor

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

Copy link
Contributor Author

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 {
Copy link
Contributor

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

)

type ChangesetApplication struct {
Changeset func(e deployment.Environment, config any) (deployment.ChangesetOutput, error)
Copy link
Contributor

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

APIInterval *commonconfig.Duration
}

type DeployCCIPContractConfig struct {
Copy link
Contributor

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) {
Copy link
Contributor

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
Copy link
Contributor

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

HomeChainSel uint64
FeedChainSel uint64
ChainsToDeploy []uint64
TokenConfig TokenConfig
Copy link
Contributor

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 ?

USDCConfig USDCConfig
// For setting OCR configuration
OCRSecrets deployment.OCRSecrets
}
Copy link
Contributor

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),

Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added ticket ccip-4320

makramkd
makramkd previously approved these changes Nov 21, 2024

type PrerequisiteOpt func(o *DeployPrerequisiteContractsOpts)

func WithUSDCChains(chains []uint64) PrerequisiteOpt {
Copy link
Contributor

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?

Copy link
Contributor Author

@AnieeG AnieeG Nov 21, 2024

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

// 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(
Copy link
Contributor

Choose a reason for hiding this comment

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

can be private


return nil
}

func DeployChainContractsForChains(
Copy link
Contributor

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)
Copy link
Contributor

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?

Copy link
Contributor Author

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.
Copy link
Contributor

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) {
Copy link
Contributor

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

@@ -76,6 +76,17 @@ type Environment struct {
Offchain OffchainClient
}

func (e Environment) Copy() (Environment, error) {
Copy link
Contributor

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)
Copy link
Contributor

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)

Copy link
Contributor Author

@AnieeG AnieeG Nov 21, 2024

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline and addressed

@pramodhs2 pramodhs2 self-requested a review November 21, 2024 21:16
@AnieeG AnieeG added this pull request to the merge queue Nov 21, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 21, 2024
@AnieeG AnieeG added this pull request to the merge queue Nov 21, 2024
Merged via the queue into develop with commit d2817c5 Nov 21, 2024
167 of 168 checks passed
@AnieeG AnieeG deleted the ccip-4158-add-chain branch November 21, 2024 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants