Skip to content

Commit

Permalink
Set access controller changeset and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
akuzni2 committed Mar 12, 2025
1 parent 9a3f44a commit 921ef66
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package verifier_proxy

import (
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/smartcontractkit/chainlink/deployment"
commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
"github.com/smartcontractkit/chainlink/deployment/data-streams/changeset"
"github.com/smartcontractkit/chainlink/deployment/data-streams/changeset/types"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy_v0_5_0"
mcmslib "github.com/smartcontractkit/mcms"
mcmstypes "github.com/smartcontractkit/mcms/types"
)

// SetAccessControllerChangeset sets the active verifier contract on the proxy contract
var SetAccessControllerChangeset deployment.ChangeSetV2[VerifierProxySetAccessControllerConfig] = &verifierProxySetAccessController{}

type verifierProxySetAccessController struct{}

type VerifierProxySetAccessControllerConfig struct {
ConfigPerChain map[uint64]setAccessControllerConfig
MCMSConfig *changeset.MCMSConfig
}

type setAccessControllerConfig struct {
Address common.Address
}

func (v verifierProxySetAccessController) Apply(e deployment.Environment, cfg VerifierProxySetAccessControllerConfig) (deployment.ChangesetOutput, error) {
chainSelectors := make([]uint64, 0, len(cfg.ConfigPerChain))
for chainSelector := range cfg.ConfigPerChain {
chainSelectors = append(chainSelectors, chainSelector)
}

useMCMS := cfg.MCMSConfig != nil
if !useMCMS {
return executeDirectTransactions(e, cfg)
}
return createMCMSProposal(e, cfg, chainSelectors)
}

func executeDirectTransactions(e deployment.Environment, cfg VerifierProxySetAccessControllerConfig) (deployment.ChangesetOutput, error) {
for chainSelector, config := range cfg.ConfigPerChain {
chain := e.Chains[chainSelector]

verifierProxy, err := maybeLoadVerifierProxyState(e, chainSelector, config.Address.String())
if err != nil {
return deployment.ChangesetOutput{}, err
}

tx, err := GetTransaction(e, chainSelector, true, verifierProxy, config)
if err != nil {
return deployment.ChangesetOutput{}, err
}

if _, err := chain.Confirm(tx); err != nil {
return deployment.ChangesetOutput{}, err
}
}
return deployment.ChangesetOutput{}, nil
}

func createMCMSProposal(e deployment.Environment, cfg VerifierProxySetAccessControllerConfig, chainSelectors []uint64) (deployment.ChangesetOutput, error) {
mcmsStatePerChain, err := commonchangeset.MaybeLoadMCMSWithTimelockState(e, chainSelectors)
if err != nil {
return deployment.ChangesetOutput{}, err
}

inspectors, err := proposalutils.McmsInspectors(e)
if err != nil {
return deployment.ChangesetOutput{}, err
}

var batches []mcmstypes.BatchOperation
timelockAddressesPerChain := map[uint64]string{}
proposerMcmsPerChain := map[uint64]string{}

// Generate transactions and create batch operations
for chainSelector, config := range cfg.ConfigPerChain {
verifierProxyState, tx, err := generateMCMSTransaction(e, chainSelector, config)
if err != nil {
return deployment.ChangesetOutput{}, err
}

batchOp, err := proposalutils.BatchOperationForChain(
chainSelector,
verifierProxyState.VerifierProxy.Address().Hex(),
tx.Data(),
big.NewInt(0),
string(types.VerifierProxy),
[]string{},
)
if err != nil {
return deployment.ChangesetOutput{}, err
}

batches = append(batches, batchOp)

state := mcmsStatePerChain[chainSelector]
timelockAddressesPerChain[chainSelector] = state.Timelock.Address().Hex()
proposerMcmsPerChain[chainSelector] = state.ProposerMcm.Address().Hex()
}

proposal, err := proposalutils.BuildProposalFromBatchesV2(
e,
timelockAddressesPerChain,
proposerMcmsPerChain,
inspectors,
batches,
"Set Access Controller proposal",
cfg.MCMSConfig.MinDelay,
)
if err != nil {
return deployment.ChangesetOutput{}, err
}

return deployment.ChangesetOutput{
MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal},
}, nil
}

func generateMCMSTransaction(e deployment.Environment, chainSelector uint64, config setAccessControllerConfig) (*VerifierProxyState, *gethtypes.Transaction, error) {
verifierProxy, err := maybeLoadVerifierProxyState(e, chainSelector, config.Address.String())
if err != nil {
return nil, nil, err
}

tx, err := GetTransaction(e, chainSelector, true, verifierProxy, config)
return verifierProxy, tx, nil
}

func (v verifierProxySetAccessController) VerifyPreconditions(e deployment.Environment, cfg VerifierProxySetAccessControllerConfig) error {
if len(cfg.ConfigPerChain) == 0 {
return errors.New("ConfigPerChain is empty")
}
for cs, _ := range cfg.ConfigPerChain {
if err := deployment.IsValidChainSelector(cs); err != nil {
return fmt.Errorf("invalid chain selector: %d - %w", cs, err)
}
}
return nil
}

func getTransactOpts(e deployment.Environment, chainSel uint64, mcms bool) *bind.TransactOpts {
if mcms {
return deployment.SimTransactOpts()
}
return e.Chains[chainSel].DeployerKey
}

func GetTransaction(e deployment.Environment, chainSel uint64, mcms bool, vps *VerifierProxyState, cfg setAccessControllerConfig) (*gethtypes.Transaction, error) {
var opts = getTransactOpts(e, chainSel, mcms)
return vps.VerifierProxy.SetAccessController(opts, cfg.Address)
}

type VerifierProxyState struct {
VerifierProxy *verifier_proxy_v0_5_0.VerifierProxy
}

func maybeLoadVerifierProxyState(e deployment.Environment, chainSel uint64, contractAddr string) (*VerifierProxyState, error) {
chain, ok := e.Chains[chainSel]
if !ok {
return nil, fmt.Errorf("chain %d not found", chainSel)
}
addresses, err := e.ExistingAddresses.AddressesForChain(chainSel)
if err != nil {
return nil, err
}
tv, ok := addresses[contractAddr]
if !ok {
return nil, fmt.Errorf("unable to find VerifierProxy contract on chain %s (chain selector %d)", chain.Name(), chain.Selector)
}

if tv.Type != types.VerifierProxy || tv.Version != deployment.Version0_5_0 {
return nil, fmt.Errorf("unexpected contract type %s for VerifierProxy on chain %s (chain selector %d)", tv, chain.Name(), chain.Selector)
}

vp, err := verifier_proxy_v0_5_0.NewVerifierProxy(common.HexToAddress(contractAddr), chain.Client)
if err != nil {
return nil, err
}

return &VerifierProxyState{
VerifierProxy: vp,
}, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package verifier_proxy

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/chainlink/deployment"
commonChangesets "github.com/smartcontractkit/chainlink/deployment/common/changeset"
"github.com/smartcontractkit/chainlink/deployment/data-streams/changeset/testutil"
"github.com/smartcontractkit/chainlink/deployment/data-streams/changeset/types"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy_v0_5_0"
"github.com/stretchr/testify/require"
)

func TestCallVerifierProxySetAccessController(t *testing.T) {
e := testutil.NewMemoryEnv(t, true)
acAddress := common.HexToAddress("0x0000000000000000000000000000000000000123")
cc := VerifierProxySetAccessControllerConfig{
ConfigPerChain: map[uint64]setAccessControllerConfig{
testutil.TestChain.Selector: {
Address: acAddress,
},
},
}

resp, err := commonChangesets.Apply(t, e, nil,
commonChangesets.Configure(
SetAccessControllerChangeset,
cc,
),
commonChangesets.Configure(
DeployVerifierProxyChangeset,
DeployVerifierProxyConfig{
ChainsToDeploy: []uint64{testutil.TestChain.Selector},
},
),
)
require.NoError(t, err)

// Ensure the VerifierProxy was deployed
ab, err := resp.ExistingAddresses.Addresses()
require.NoError(t, err)
require.Len(t, ab, 1)

verifierProxyAddrHex, err := deployment.SearchAddressBook(e.ExistingAddresses, testutil.TestChain.Selector, types.VerifierProxy)
verifierProxyAddr := common.HexToAddress(verifierProxyAddrHex)

client := e.Chains[testutil.TestChain.Selector].Client
verifierProxy, err := verifier_proxy_v0_5_0.NewVerifierProxy(verifierProxyAddr, client)
require.NoError(t, err)

accessController, err := verifierProxy.SAccessController(nil)
require.NoError(t, err)
require.Equal(t, acAddress, accessController)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy_v0_5_0"
)

// DeployVerifierProxy deploys VerifierProxy to the chains specified in the config.
var DeployVerifierProxy = deployment.CreateChangeSet(apply, verifyPreconditions)
// DeployVerifierProxyChangeset deploys VerifierProxy to the chains specified in the config.
var DeployVerifierProxyChangeset deployment.ChangeSetV2[DeployVerifierProxyConfig] = &verifierProxyDeploy{}

type verifierProxyDeploy struct{}
type DeployVerifierProxyConfig struct {
AccessControllerAddress common.Address
// ChainsToDeploy is a list of chain selectors to deploy the contract to.
Expand All @@ -42,7 +43,7 @@ func (cfg DeployVerifierProxyConfig) Validate() error {
return nil
}

func apply(e deployment.Environment, cc DeployVerifierProxyConfig) (deployment.ChangesetOutput, error) {
func (v *verifierProxyDeploy) Apply(e deployment.Environment, cc DeployVerifierProxyConfig) (deployment.ChangesetOutput, error) {
ab := deployment.NewMemoryAddressBook()
err := performProxyDeployment(e, ab, cc)
if err != nil {
Expand All @@ -54,11 +55,10 @@ func apply(e deployment.Environment, cc DeployVerifierProxyConfig) (deployment.C
}, nil
}

func verifyPreconditions(_ deployment.Environment, cc DeployVerifierProxyConfig) error {
func (v *verifierProxyDeploy) VerifyPreconditions(_ deployment.Environment, cc DeployVerifierProxyConfig) error {
if err := cc.Validate(); err != nil {
return fmt.Errorf("invalid DeployVerifierProxyConfig: %w", err)
}

return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import (
"github.com/smartcontractkit/chainlink/deployment/data-streams/changeset/types"
)

func DeployVerifierProxyTest(t *testing.T) {
func TestDeployVerifierProxy(t *testing.T) {
e := testutil.NewMemoryEnv(t, true)
cc := DeployVerifierProxyConfig{
ChainsToDeploy: []uint64{testutil.TestChain.Selector},
}

resp, err := commonChangesets.Apply(t, e, nil,
commonChangesets.Configure(
DeployVerifierProxy,
DeployVerifierProxyChangeset,
cc,
),
)
Expand Down

0 comments on commit 921ef66

Please sign in to comment.