From 315746307aa7d87b3065c7b9991569ddc1f35cd7 Mon Sep 17 00:00:00 2001 From: Connor Stein <connor.stein@mail.mcgill.ca> Date: Thu, 17 Oct 2024 17:41:58 -0400 Subject: [PATCH] Use deterministic OCR configuration (#14775) * Misc * Misc * Pass in shared secret * Both secrets deterministic * Use ocr secrets * Use dummy secrets * Add chain test * Add comment * Sort imports --- .../deployment/ccip/add_chain.go | 2 ++ .../deployment/ccip/add_chain_test.go | 3 ++- .../deployment/ccip/add_lane_test.go | 2 ++ .../ccip/changeset/initial_deploy_test.go | 2 ++ integration-tests/deployment/ccip/deploy.go | 7 +++++++ .../deployment/ccip/deploy_home_chain.go | 8 +++++-- .../deployment/ccip/deploy_test.go | 1 + integration-tests/deployment/ccip/state.go | 10 +++++++++ integration-tests/deployment/environment.go | 3 ++- integration-tests/deployment/helpers.go | 21 +++++++++++++++++++ integration-tests/deployment/multiclient.go | 4 ++-- integration-tests/smoke/ccip_test.go | 3 +++ 12 files changed, 60 insertions(+), 6 deletions(-) diff --git a/integration-tests/deployment/ccip/add_chain.go b/integration-tests/deployment/ccip/add_chain.go index 810cb77f6a9..72455dfdd19 100644 --- a/integration-tests/deployment/ccip/add_chain.go +++ b/integration-tests/deployment/ccip/add_chain.go @@ -25,6 +25,7 @@ import ( // to connect the new chain to the existing chains. func NewChainInboundProposal( e deployment.Environment, + ocrSecrets deployment.OCRSecrets, state CCIPOnChainState, homeChainSel uint64, feedChainSel uint64, @@ -132,6 +133,7 @@ func NewChainInboundProposal( newDONArgs, err := BuildAddDONArgs( e.Logger, + ocrSecrets, state.Chains[newChainSel].OffRamp, e.Chains[newChainSel], feedChainSel, diff --git a/integration-tests/deployment/ccip/add_chain_test.go b/integration-tests/deployment/ccip/add_chain_test.go index 26d9ad79885..5e05fff59ff 100644 --- a/integration-tests/deployment/ccip/add_chain_test.go +++ b/integration-tests/deployment/ccip/add_chain_test.go @@ -53,6 +53,7 @@ func TestAddChainInbound(t *testing.T) { MCMSConfig: NewTestMCMSConfig(t, e.Env), FeeTokenContracts: e.FeeTokenContracts, CapabilityRegistry: state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) state, err = LoadOnchainState(e.Env, e.Ab) @@ -130,7 +131,7 @@ func TestAddChainInbound(t *testing.T) { // Generate and sign inbound proposal to new 4th chain. rmnHomeAddressBytes := common.HexToAddress(rmnHomeAddress).Bytes() - chainInboundProposal, err := NewChainInboundProposal(e.Env, state, e.HomeChainSel, e.FeedChainSel, newChain, initialDeploy, tokenConfig, rmnHomeAddressBytes) + chainInboundProposal, err := NewChainInboundProposal(e.Env, deployment.XXXGenerateTestOCRSecrets(), state, e.HomeChainSel, e.FeedChainSel, newChain, initialDeploy, tokenConfig, rmnHomeAddressBytes) require.NoError(t, err) chainInboundExec := SignProposal(t, e.Env, chainInboundProposal) for _, sel := range initialDeploy { diff --git a/integration-tests/deployment/ccip/add_lane_test.go b/integration-tests/deployment/ccip/add_lane_test.go index 5a47b8f087f..e63d1845774 100644 --- a/integration-tests/deployment/ccip/add_lane_test.go +++ b/integration-tests/deployment/ccip/add_lane_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -27,6 +28,7 @@ func TestAddLane(t *testing.T) { MCMSConfig: NewTestMCMSConfig(t, e.Env), FeeTokenContracts: e.FeeTokenContracts, CapabilityRegistry: state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) diff --git a/integration-tests/deployment/ccip/changeset/initial_deploy_test.go b/integration-tests/deployment/ccip/changeset/initial_deploy_test.go index 12d794a66e3..6cb3bc12d2f 100644 --- a/integration-tests/deployment/ccip/changeset/initial_deploy_test.go +++ b/integration-tests/deployment/ccip/changeset/initial_deploy_test.go @@ -5,6 +5,7 @@ import ( cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/stretchr/testify/require" @@ -44,6 +45,7 @@ func TestInitialDeploy(t *testing.T) { MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), CapabilityRegistry: state.Chains[tenv.HomeChainSel].CapabilityRegistry.Address(), FeeTokenContracts: tenv.FeeTokenContracts, + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) // Get new state after migration. diff --git a/integration-tests/deployment/ccip/deploy.go b/integration-tests/deployment/ccip/deploy.go index 2f7aa43245b..cd7464cbe5f 100644 --- a/integration-tests/deployment/ccip/deploy.go +++ b/integration-tests/deployment/ccip/deploy.go @@ -49,6 +49,7 @@ var ( CancellerManyChainMultisig deployment.ContractType = "CancellerManyChainMultiSig" ProposerManyChainMultisig deployment.ContractType = "ProposerManyChainMultiSig" CCIPHome deployment.ContractType = "CCIPHome" + CCIPConfig deployment.ContractType = "CCIPConfig" RMNHome deployment.ContractType = "RMNHome" RBACTimelock deployment.ContractType = "RBACTimelock" OnRamp deployment.ContractType = "OnRamp" @@ -126,12 +127,17 @@ type DeployCCIPContractConfig struct { // I believe it makes sense to have the same signers across all chains // since that's the point MCMS. MCMSConfig MCMSConfig + // For setting OCR configuration + OCRSecrets deployment.OCRSecrets } // DeployCCIPContracts assumes that the capability registry and ccip home contracts // are already deployed (needed as a first step because the chainlink nodes point to them). // It then deploys func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c DeployCCIPContractConfig) error { + if c.OCRSecrets.IsEmpty() { + return fmt.Errorf("OCR secrets are empty") + } nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) if err != nil || len(nodes) == 0 { e.Logger.Errorw("Failed to get node info", "err", err) @@ -226,6 +232,7 @@ func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c // For each chain, we create a DON on the home chain (2 OCR instances) if err := AddDON( e.Logger, + c.OCRSecrets, capReg, ccipHome, common.HexToAddress(rmnHomeAddress).Bytes(), diff --git a/integration-tests/deployment/ccip/deploy_home_chain.go b/integration-tests/deployment/ccip/deploy_home_chain.go index b854078f79d..fa50a54878c 100644 --- a/integration-tests/deployment/ccip/deploy_home_chain.go +++ b/integration-tests/deployment/ccip/deploy_home_chain.go @@ -263,6 +263,7 @@ func AddChainConfig( func BuildAddDONArgs( lggr logger.Logger, + ocrSecrets deployment.OCRSecrets, offRamp *offramp.OffRamp, dest deployment.Chain, feedChainSel uint64, @@ -317,7 +318,9 @@ func BuildAddDONArgs( if err2 != nil { return nil, err2 } - signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsForTests( + signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsDeterministic( + ocrSecrets.EphemeralSk, + ocrSecrets.SharedSecret, DeltaProgress, DeltaResend, DeltaInitial, @@ -766,6 +769,7 @@ func setupCommitDON( func AddDON( lggr logger.Logger, + ocrSecrets deployment.OCRSecrets, capReg *capabilities_registry.CapabilitiesRegistry, ccipHome *ccip_home.CCIPHome, rmnHomeAddress []byte, @@ -777,7 +781,7 @@ func AddDON( home deployment.Chain, nodes deployment.Nodes, ) error { - ocrConfigs, err := BuildAddDONArgs(lggr, offRamp, dest, feedChainSel, tokenInfo, nodes, rmnHomeAddress) + ocrConfigs, err := BuildAddDONArgs(lggr, ocrSecrets, offRamp, dest, feedChainSel, tokenInfo, nodes, rmnHomeAddress) if err != nil { return err } diff --git a/integration-tests/deployment/ccip/deploy_test.go b/integration-tests/deployment/ccip/deploy_test.go index 6305ac8e069..3742442433e 100644 --- a/integration-tests/deployment/ccip/deploy_test.go +++ b/integration-tests/deployment/ccip/deploy_test.go @@ -41,6 +41,7 @@ func TestDeployCCIPContracts(t *testing.T) { CapabilityRegistry: s.Chains[homeChainSel].CapabilityRegistry.Address(), FeeTokenContracts: feeTokenContracts, MCMSConfig: NewTestMCMSConfig(t, e), + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) state, err := LoadOnchainState(e, ab) diff --git a/integration-tests/deployment/ccip/state.go b/integration-tests/deployment/ccip/state.go index 4fc46c953b0..e4bbe9863a0 100644 --- a/integration-tests/deployment/ccip/state.go +++ b/integration-tests/deployment/ccip/state.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip/view/v1_0" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" @@ -70,6 +71,8 @@ type CCIPChainState struct { CancellerMcm *owner_wrappers.ManyChainMultiSig ProposerMcm *owner_wrappers.ManyChainMultiSig Timelock *owner_wrappers.RBACTimelock + // TODO remove once staging upgraded. + CCIPConfig *ccip_config.CCIPConfig // Test contracts Receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver @@ -362,6 +365,13 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, err } state.CCIPHome = ccipHome + case deployment.NewTypeAndVersion(CCIPConfig, deployment.Version1_0_0).String(): + // TODO: Remove once staging upgraded. + ccipConfig, err := ccip_config.NewCCIPConfig(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + state.CCIPConfig = ccipConfig case deployment.NewTypeAndVersion(CCIPReceiver, deployment.Version1_0_0).String(): mr, err := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(common.HexToAddress(address), chain.Client) if err != nil { diff --git a/integration-tests/deployment/environment.go b/integration-tests/deployment/environment.go index 163a29bf5b4..0b723a358d6 100644 --- a/integration-tests/deployment/environment.go +++ b/integration-tests/deployment/environment.go @@ -33,6 +33,7 @@ type OnchainClient interface { bind.ContractBackend bind.DeployBackend BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) + NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) } type OffchainClient interface { @@ -96,7 +97,7 @@ func ConfirmIfNoError(chain Chain, tx *types.Transaction, err error) (uint64, er var d rpc.DataError ok := errors.As(err, &d) if ok { - return 0, fmt.Errorf("got Data Error: %s", d.ErrorData()) + return 0, fmt.Errorf("transaction reverted: Error %s ErrorData %v", d.Error(), d.ErrorData()) } return 0, err } diff --git a/integration-tests/deployment/helpers.go b/integration-tests/deployment/helpers.go index c691d1a1ec1..226de9a7024 100644 --- a/integration-tests/deployment/helpers.go +++ b/integration-tests/deployment/helpers.go @@ -13,9 +13,30 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" ) +// OCRSecrets are used to disseminate a shared secret to OCR nodes +// through the blockchain where OCR configuration is stored. Its a low value secret used +// to derive transmission order etc. They are extracted here such that they can common +// across signers when multiple signers are signing the same OCR config. +type OCRSecrets struct { + SharedSecret [16]byte + EphemeralSk [32]byte +} + +func (s OCRSecrets) IsEmpty() bool { + return s.SharedSecret == [16]byte{} || s.EphemeralSk == [32]byte{} +} + +func XXXGenerateTestOCRSecrets() OCRSecrets { + var s OCRSecrets + copy(s.SharedSecret[:], crypto.Keccak256([]byte("shared"))[:16]) + copy(s.EphemeralSk[:], crypto.Keccak256([]byte("ephemeral"))) + return s +} + // SimTransactOpts is useful to generate just the calldata for a given gethwrapper method. func SimTransactOpts() *bind.TransactOpts { return &bind.TransactOpts{Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { diff --git a/integration-tests/deployment/multiclient.go b/integration-tests/deployment/multiclient.go index 94dcc95f9ec..65f9e82bd01 100644 --- a/integration-tests/deployment/multiclient.go +++ b/integration-tests/deployment/multiclient.go @@ -87,11 +87,11 @@ func (mc *MultiClient) CodeAt(ctx context.Context, account common.Address, block return code, err } -func (mc *MultiClient) NonceAt(ctx context.Context, account common.Address) (uint64, error) { +func (mc *MultiClient) NonceAt(ctx context.Context, account common.Address, block *big.Int) (uint64, error) { var count uint64 err := mc.retryWithBackups("NonceAt", func(client *ethclient.Client) error { var err error - count, err = client.NonceAt(ctx, account, nil) + count, err = client.NonceAt(ctx, account, block) return err }) return count, err diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 565df6a2dd9..b34876c5b2b 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" @@ -43,6 +45,7 @@ func TestInitialDeployOnLocal(t *testing.T) { MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), CapabilityRegistry: state.Chains[tenv.HomeChainSel].CapabilityRegistry.Address(), FeeTokenContracts: tenv.FeeTokenContracts, + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) // Get new state after migration.