Skip to content

Commit

Permalink
refactor(mcms): handle nil scenario
Browse files Browse the repository at this point in the history
Some scenarios will throw nil pointer exception without using the ok pattern check. We should handle those properly.
  • Loading branch information
graham-chainlink committed Dec 17, 2024
1 parent 85c8b96 commit f551876
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 6 deletions.
42 changes: 36 additions & 6 deletions deployment/common/changeset/transfer_to_mcms_with_timelock.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,25 +218,55 @@ type RenounceTimelockDeployerConfig struct {
ChainSel uint64
}

func (cfg RenounceTimelockDeployerConfig) Validate(e deployment.Environment) error {
if err := deployment.IsValidChainSelector(cfg.ChainSel); err != nil {
return fmt.Errorf("invalid chain selector: %w", err)
}

_, ok := e.Chains[cfg.ChainSel]
if !ok {
return fmt.Errorf("chain selector: %d not found in environment", cfg.ChainSel)
}

// MCMS should already exists
state, err := MaybeLoadMCMSWithTimelockState(e, []uint64{cfg.ChainSel})
if err != nil {
return err
}

contract, ok := state[cfg.ChainSel]
if !ok {
return fmt.Errorf("mcms contracts not found on chain %d", cfg.ChainSel)
}
if contract.Timelock == nil {
return fmt.Errorf("timelock not found on chain %d", cfg.ChainSel)
}

return nil
}

// RenounceTimelockDeployer revokes the deployer key from administering the contract.
func RenounceTimelockDeployer(e deployment.Environment, cfg RenounceTimelockDeployerConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(e); err != nil {
return deployment.ChangesetOutput{}, err
}

contracts, err := MaybeLoadMCMSWithTimelockState(e, []uint64{cfg.ChainSel})
if err != nil {
return deployment.ChangesetOutput{}, err
}
tl := contracts[cfg.ChainSel].Timelock
if tl == nil {
return deployment.ChangesetOutput{}, fmt.Errorf("timelock not found on chain %d", cfg.ChainSel)
}
admin, err := tl.ADMINROLE(&bind.CallOpts{})
admin, err := tl.ADMINROLE(&bind.CallOpts{Context: e.GetContext()})
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to get admin role: %w", err)
}
tx, err := tl.RenounceRole(e.Chains[cfg.ChainSel].DeployerKey, admin, e.Chains[cfg.ChainSel].DeployerKey.From)

chain := e.Chains[cfg.ChainSel]
tx, err := tl.RenounceRole(chain.DeployerKey, admin, chain.DeployerKey.From)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to revoke deployer key: %w", err)
}
if _, err := deployment.ConfirmIfNoError(e.Chains[cfg.ChainSel], tx, err); err != nil {
if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil {
return deployment.ChangesetOutput{}, err
}
e.Logger.Infof("revoked deployer key from owning contract %s", tl.Address().Hex())
Expand Down
76 changes: 76 additions & 0 deletions deployment/common/changeset/transfer_to_mcms_with_timelock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
chain_selectors "github.com/smartcontractkit/chain-selectors"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
"github.com/smartcontractkit/chainlink/deployment/common/types"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"
Expand Down Expand Up @@ -81,6 +83,80 @@ func TestTransferToMCMSWithTimelock(t *testing.T) {
require.Equal(t, e.Chains[chain1].DeployerKey.From, o)
}

func TestRenounceTimelockDeployerConfigValidate(t *testing.T) {
lggr := logger.TestLogger(t)
e := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{
Chains: 1,
Nodes: 1,
})
chain1 := e.AllChainSelectors()[0]
e, err := ApplyChangesets(t, e, nil, []ChangesetApplication{
{
Changeset: WrapChangeSet(DeployMCMSWithTimelock),
Config: map[uint64]types.MCMSWithTimelockConfig{
chain1: proposalutils.SingleGroupTimelockConfig(t),
},
},
})
require.NoError(t, err)

envWithNoMCMS := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{
Chains: 1,
Nodes: 1,
})
chain2 := envWithNoMCMS.AllChainSelectors()[0]

for _, test := range []struct {
name string
config RenounceTimelockDeployerConfig
env deployment.Environment
err string
}{
{
name: "valid config",
env: e,
config: RenounceTimelockDeployerConfig{
ChainSel: chain1,
},
},
{
name: "invalid chain selector",
env: e,
config: RenounceTimelockDeployerConfig{
ChainSel: 0,
},
err: "invalid chain selector: chain selector must be set",
},
{
name: "chain does not exists on env",
env: e,
config: RenounceTimelockDeployerConfig{
ChainSel: chain_selectors.ETHEREUM_TESTNET_SEPOLIA.Selector,
},
err: "chain selector: 16015286601757825753 not found in environment",
},
{
name: "no MCMS deployed",
env: envWithNoMCMS,
config: RenounceTimelockDeployerConfig{
ChainSel: chain2,
},
// chain does not match any existing addresses
err: "chain selector 909606746561742123: chain not found",
},
} {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
err := test.config.Validate(test.env)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

func TestRenounceTimelockDeployer(t *testing.T) {
lggr := logger.TestLogger(t)
e := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{
Expand Down

0 comments on commit f551876

Please sign in to comment.