Skip to content

Commit

Permalink
support mcms in ocr3 contract config changeset (#15510)
Browse files Browse the repository at this point in the history
* support mcms in ocr3 contract config changeset

* test working for ocr3 config with mcms

* migrate deployment test to setup test env

* fix test
  • Loading branch information
krehermann authored Dec 5, 2024
1 parent 63bca12 commit bbddf93
Show file tree
Hide file tree
Showing 16 changed files with 768 additions and 314 deletions.
1 change: 1 addition & 0 deletions core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ require (
github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.2 // indirect
github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241204153209-c3a71b0eef99 // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 // indirect
github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 // indirect
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect
github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect
Expand Down
2 changes: 2 additions & 0 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,8 @@ github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241204153209-c3a71b0eef9
github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241204153209-c3a71b0eef99/go.mod h1:p8aUDfJeley6oer7y+Ucd3edOtRlMTnWg3mN6rhaLWo=
github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8 h1:tNS7U9lrxkFvEuyxQv11HHOiV9LPDGC9wYEy+yM/Jv4=
github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241202202529-2033490e77b8/go.mod h1:EBrEgcdIbwepqguClkv8Ohy7CbyWSJaE4EC9aBJlQK0=
github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 h1:T0kbw07Vb6xUyA9MIJZfErMgWseWi1zf7cYvRpoq7ug=
github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13/go.mod h1:1CKUOzoK+Ga19WuhRH9pxZ+qUUnrlIx108VEA6qSzeQ=
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs=
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA=
github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 h1:NzZGjaqez21I3DU7objl3xExTH4fxYvzTqar8DC6360=
Expand Down
61 changes: 27 additions & 34 deletions deployment/environment/memory/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,49 +47,42 @@ func GenerateChains(t *testing.T, numChains int, numUsers int) map[uint64]EVMCha
chains := make(map[uint64]EVMChain)
for i := 0; i < numChains; i++ {
chainID := chainsel.TEST_90000001.EvmChainID + uint64(i)
key, err := crypto.GenerateKey()
require.NoError(t, err)
owner, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
require.NoError(t, err)
genesis := types.GenesisAlloc{
owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(7000), big.NewInt(params.Ether))}}
// create a set of user keys
var users []*bind.TransactOpts
for j := 0; j < numUsers; j++ {
key, err := crypto.GenerateKey()
require.NoError(t, err)
user, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
require.NoError(t, err)
users = append(users, user)
genesis[user.From] = types.Account{Balance: big.NewInt(0).Mul(big.NewInt(7000), big.NewInt(params.Ether))}
}
// there have to be enough initial funds on each chain to allocate for all the nodes that share the given chain in the test
backend := simulated.NewBackend(genesis, simulated.WithBlockGasLimit(50000000))
backend.Commit() // ts will be now.
chains[chainID] = EVMChain{
Backend: backend,
DeployerKey: owner,
Users: users,
}
chains[chainID] = evmChain(t, numUsers)
}
return chains
}

func GenerateChainsWithIds(t *testing.T, chainIDs []uint64) map[uint64]EVMChain {
chains := make(map[uint64]EVMChain)
for _, chainID := range chainIDs {
chains[chainID] = evmChain(t, 1)
}
return chains
}

func evmChain(t *testing.T, numUsers int) EVMChain {
key, err := crypto.GenerateKey()
require.NoError(t, err)
owner, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
require.NoError(t, err)
genesis := types.GenesisAlloc{
owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(700000), big.NewInt(params.Ether))}}
// create a set of user keys
var users []*bind.TransactOpts
for j := 0; j < numUsers; j++ {
key, err := crypto.GenerateKey()
require.NoError(t, err)
owner, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
user, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
require.NoError(t, err)
backend := simulated.NewBackend(types.GenesisAlloc{
owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(700000), big.NewInt(params.Ether))}},
simulated.WithBlockGasLimit(10000000))
backend.Commit() // Note initializes block timestamp to now().
chains[chainID] = EVMChain{
Backend: backend,
DeployerKey: owner,
}
users = append(users, user)
genesis[user.From] = types.Account{Balance: big.NewInt(0).Mul(big.NewInt(700000), big.NewInt(params.Ether))}
}
// there have to be enough initial funds on each chain to allocate for all the nodes that share the given chain in the test
backend := simulated.NewBackend(genesis, simulated.WithBlockGasLimit(50000000))
backend.Commit() // ts will be now.
return EVMChain{
Backend: backend,
DeployerKey: owner,
Users: users,
}
return chains
}
38 changes: 11 additions & 27 deletions deployment/keystone/changeset/accept_ownership.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (

"github.com/ethereum/go-ethereum/common"

kslib "github.com/smartcontractkit/chainlink/deployment/keystone"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/common/changeset"
)
Expand All @@ -23,39 +25,21 @@ func AcceptAllOwnershipsProposal(e deployment.Environment, req *AcceptAllOwnersh
chain := e.Chains[chainSelector]
addrBook := e.ExistingAddresses

capRegs, err := capRegistriesFromAddrBook(addrBook, chain)
if err != nil {
return deployment.ChangesetOutput{}, err
}
ocr3, err := ocr3FromAddrBook(addrBook, chain)
if err != nil {
return deployment.ChangesetOutput{}, err
}
forwarders, err := forwardersFromAddrBook(addrBook, chain)
if err != nil {
return deployment.ChangesetOutput{}, err
}
consumers, err := feedsConsumersFromAddrBook(addrBook, chain)
r, err := kslib.GetContractSets(e.Logger, &kslib.GetContractSetsRequest{
Chains: map[uint64]deployment.Chain{
req.ChainSelector: chain,
},
AddressBook: addrBook,
})
if err != nil {
return deployment.ChangesetOutput{}, err
}
var addrsToTransfer []common.Address
for _, consumer := range consumers {
addrsToTransfer = append(addrsToTransfer, consumer.Address())
}
for _, o := range ocr3 {
addrsToTransfer = append(addrsToTransfer, o.Address())
}
for _, f := range forwarders {
addrsToTransfer = append(addrsToTransfer, f.Address())
}
for _, c := range capRegs {
addrsToTransfer = append(addrsToTransfer, c.Address())
}
contracts := r.ContractSets[chainSelector]

// Construct the configuration
cfg := changeset.TransferToMCMSWithTimelockConfig{
ContractsByChain: map[uint64][]common.Address{
chainSelector: addrsToTransfer,
chainSelector: contracts.TransferableContracts(),
},
MinDelay: minDelay,
}
Expand Down
4 changes: 0 additions & 4 deletions deployment/keystone/changeset/accept_ownership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ func TestAcceptAllOwnership(t *testing.T) {
Changeset: commonchangeset.WrapChangeSet(changeset.DeployForwarder),
Config: registrySel,
},
{
Changeset: commonchangeset.WrapChangeSet(changeset.DeployFeedsConsumer),
Config: &changeset.DeployFeedsConsumerRequest{ChainSelector: registrySel},
},
{
Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock),
Config: map[uint64]types.MCMSWithTimelockConfig{
Expand Down
19 changes: 19 additions & 0 deletions deployment/keystone/changeset/configure_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ import (
kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
)

var _ deployment.ChangeSet[InitialContractsCfg] = ConfigureInitialContractsChangeset

type InitialContractsCfg struct {
RegistryChainSel uint64
Dons []kslib.DonCapabilities
OCR3Config *kslib.OracleConfigWithSecrets
}

func ConfigureInitialContractsChangeset(e deployment.Environment, cfg InitialContractsCfg) (deployment.ChangesetOutput, error) {
req := &kslib.ConfigureContractsRequest{
Env: &e,
RegistryChainSel: cfg.RegistryChainSel,
Dons: cfg.Dons,
OCR3Config: cfg.OCR3Config,
}
return ConfigureInitialContracts(e.Logger, req)
}

// Deprecated: Use ConfigureInitialContractsChangeset instead.
func ConfigureInitialContracts(lggr logger.Logger, req *kslib.ConfigureContractsRequest) (deployment.ChangesetOutput, error) {
if err := req.Validate(); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to validate request: %w", err)
Expand Down
10 changes: 2 additions & 8 deletions deployment/keystone/changeset/deploy_forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,10 @@ import (

var _ deployment.ChangeSet[uint64] = DeployForwarder

// DeployForwarder deploys the KeystoneForwarder contract to all chains in the environment
// callers must merge the output addressbook with the existing one
func DeployForwarder(env deployment.Environment, registryChainSel uint64) (deployment.ChangesetOutput, error) {
lggr := env.Logger
// expect OCR3 to be deployed & capabilities registry
regAddrs, err := env.ExistingAddresses.AddressesForChain(registryChainSel)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("no addresses found for chain %d: %w", registryChainSel, err)
}
if len(regAddrs) != 2 {
return deployment.ChangesetOutput{}, fmt.Errorf("expected 2 addresses for chain %d, got %d", registryChainSel, len(regAddrs))
}
ab := deployment.NewMemoryAddressBook()
for _, chain := range env.Chains {
lggr.Infow("deploying forwarder", "chainSelector", chain.Selector)
Expand Down
33 changes: 0 additions & 33 deletions deployment/keystone/changeset/deploy_forwarder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"
kslb "github.com/smartcontractkit/chainlink/deployment/keystone"
"github.com/smartcontractkit/chainlink/deployment/keystone/changeset"
)

Expand All @@ -24,43 +23,11 @@ func TestDeployForwarder(t *testing.T) {
}
env := memory.NewMemoryEnvironment(t, lggr, zapcore.DebugLevel, cfg)

var (
ocrTV = deployment.NewTypeAndVersion(kslb.OCR3Capability, deployment.Version1_0_0)
crTV = deployment.NewTypeAndVersion(kslb.CapabilitiesRegistry, deployment.Version1_0_0)
)

registrySel := env.AllChainSelectors()[0]
t.Run("err if no capabilities registry on registry chain", func(t *testing.T) {
m := make(map[uint64]map[string]deployment.TypeAndVersion)
m[registrySel] = map[string]deployment.TypeAndVersion{
"0x0000000000000000000000000000000000000002": ocrTV,
}
env.ExistingAddresses = deployment.NewMemoryAddressBookFromMap(m)
// capabilities registry and ocr3 must be deployed on registry chain
_, err := changeset.DeployForwarder(env, registrySel)
require.Error(t, err)
})

t.Run("err if no ocr3 on registry chain", func(t *testing.T) {
m := make(map[uint64]map[string]deployment.TypeAndVersion)
m[registrySel] = map[string]deployment.TypeAndVersion{
"0x0000000000000000000000000000000000000001": crTV,
}
env.ExistingAddresses = deployment.NewMemoryAddressBookFromMap(m)
// capabilities registry and ocr3 must be deployed on registry chain
_, err := changeset.DeployForwarder(env, registrySel)
require.Error(t, err)
})

t.Run("should deploy forwarder", func(t *testing.T) {
ab := deployment.NewMemoryAddressBook()
// fake capabilities registry
err := ab.Save(registrySel, "0x0000000000000000000000000000000000000001", crTV)
require.NoError(t, err)

// fake ocr3
err = ab.Save(registrySel, "0x0000000000000000000000000000000000000002", ocrTV)
require.NoError(t, err)
// deploy forwarder
env.ExistingAddresses = ab
resp, err := changeset.DeployForwarder(env, registrySel)
Expand Down
48 changes: 43 additions & 5 deletions deployment/keystone/changeset/deploy_ocr3.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package changeset

import (
"encoding/json"
"fmt"
"io"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock"
"github.com/smartcontractkit/chainlink/deployment"
kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
)
Expand All @@ -27,12 +28,49 @@ func DeployOCR3(env deployment.Environment, registryChainSel uint64) (deployment
return deployment.ChangesetOutput{AddressBook: ab}, nil
}

func ConfigureOCR3Contract(lggr logger.Logger, env deployment.Environment, cfg kslib.ConfigureOCR3Config) (deployment.ChangesetOutput, error) {
var _ deployment.ChangeSet[ConfigureOCR3Config] = ConfigureOCR3Contract

type ConfigureOCR3Config struct {
ChainSel uint64
NodeIDs []string
OCR3Config *kslib.OracleConfigWithSecrets
DryRun bool
WriteGeneratedConfig io.Writer // if not nil, write the generated config to this writer as JSON [OCR2OracleConfig]

UseMCMS bool
}

_, err := kslib.ConfigureOCR3ContractFromJD(&env, cfg)
func ConfigureOCR3Contract(env deployment.Environment, cfg ConfigureOCR3Config) (deployment.ChangesetOutput, error) {
resp, err := kslib.ConfigureOCR3ContractFromJD(&env, kslib.ConfigureOCR3Config{
ChainSel: cfg.ChainSel,
NodeIDs: cfg.NodeIDs,
OCR3Config: cfg.OCR3Config,
DryRun: cfg.DryRun,
UseMCMS: cfg.UseMCMS,
})
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to configure OCR3Capability: %w", err)
}
if w := cfg.WriteGeneratedConfig; w != nil {
b, err := json.MarshalIndent(&resp.OCR2OracleConfig, "", " ")
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to marshal response output: %w", err)
}
env.Logger.Infof("Generated OCR3 config: %s", string(b))
n, err := w.Write(b)
if err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to write response output: %w", err)
}
if n != len(b) {
return deployment.ChangesetOutput{}, fmt.Errorf("failed to write all bytes")
}
}
// does not create any new addresses
return deployment.ChangesetOutput{}, nil
var proposals []timelock.MCMSWithTimelockProposal
if cfg.UseMCMS {
proposals = append(proposals, *resp.Proposal)
}
return deployment.ChangesetOutput{
Proposals: proposals,
}, nil
}
Loading

0 comments on commit bbddf93

Please sign in to comment.