Skip to content

Commit

Permalink
CCIP-4320 : Part 1 - Parameterize ocr inputs (#15377)
Browse files Browse the repository at this point in the history
* verify if token prices are getting updated without lanes

* parameterize ocr inputs

* fix test

* revert

* comments

* add rmn signature timeout

* addressed review comments

* fix tests
  • Loading branch information
AnieeG authored Nov 22, 2024
1 parent ac7a739 commit a2a67f8
Show file tree
Hide file tree
Showing 17 changed files with 408 additions and 89 deletions.
11 changes: 8 additions & 3 deletions deployment/ccip/changeset/active_candidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,20 @@ func SetCandidatePluginChangeset(
tokenConfig TokenConfig,
pluginType cctypes.PluginType,
) (deployment.ChangesetOutput, error) {
ccipOCRParams := DefaultOCRParams(
feedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[newChainSel].LinkToken, state.Chains[newChainSel].Weth9),
nil,
)
newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome(
ocrSecrets,
state.Chains[newChainSel].OffRamp,
e.Chains[newChainSel],
feedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[newChainSel].LinkToken, state.Chains[newChainSel].Weth9),
nodes.NonBootstraps(),
state.Chains[homeChainSel].RMNHome.Address(),
nil,
ccipOCRParams.OCRParameters,
ccipOCRParams.CommitOffChainConfig,
ccipOCRParams.ExecuteOffChainConfig,
)
if err != nil {
return deployment.ChangesetOutput{}, err
Expand Down
11 changes: 8 additions & 3 deletions deployment/ccip/changeset/active_candidate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,20 @@ func TestActiveCandidate(t *testing.T) {
// commit and exec plugin we will be using
rmnHomeAddress := state.Chains[tenv.HomeChainSel].RMNHome.Address()
tokenConfig := NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds)
ccipOCRParams := DefaultOCRParams(
tenv.FeedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[tenv.FeedChainSel].LinkToken, state.Chains[tenv.FeedChainSel].Weth9),
nil,
)
ocr3ConfigMap, err := internal.BuildOCR3ConfigForCCIPHome(
deployment.XXXGenerateTestOCRSecrets(),
state.Chains[tenv.FeedChainSel].OffRamp,
e.Chains[tenv.FeedChainSel],
tenv.FeedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[tenv.FeedChainSel].LinkToken, state.Chains[tenv.FeedChainSel].Weth9),
nodes.NonBootstraps(),
rmnHomeAddress,
nil,
ccipOCRParams.OCRParameters,
ccipOCRParams.CommitOffChainConfig,
ccipOCRParams.ExecuteOffChainConfig,
)
require.NoError(t, err)

Expand Down
11 changes: 8 additions & 3 deletions deployment/ccip/changeset/add_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,20 @@ func AddDonAndSetCandidateChangeset(
tokenConfig TokenConfig,
pluginType types.PluginType,
) (deployment.ChangesetOutput, error) {
ccipOCRParams := DefaultOCRParams(
feedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[newChainSel].LinkToken, state.Chains[newChainSel].Weth9),
nil,
)
newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome(
ocrSecrets,
state.Chains[newChainSel].OffRamp,
e.Chains[newChainSel],
feedChainSel,
tokenConfig.GetTokenInfo(e.Logger, state.Chains[newChainSel].LinkToken, state.Chains[newChainSel].Weth9),
nodes.NonBootstraps(),
state.Chains[homeChainSel].RMNHome.Address(),
nil,
ccipOCRParams.OCRParameters,
ccipOCRParams.CommitOffChainConfig,
ccipOCRParams.ExecuteOffChainConfig,
)
if err != nil {
return deployment.ChangesetOutput{}, err
Expand Down
7 changes: 6 additions & 1 deletion deployment/ccip/changeset/add_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ func TestAddChainInbound(t *testing.T) {
require.NoError(t, e.Env.ExistingAddresses.Merge(out.AddressBook))
newAddresses = deployment.NewMemoryAddressBook()
tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds)
ocrParams := make(map[uint64]CCIPOCRParams)
for _, chain := range initialDeploy {
ocrParams[chain] = DefaultOCRParams(e.FeedChainSel, nil, nil)
}
err = deployCCIPContracts(e.Env, newAddresses, NewChainsConfig{
HomeChainSel: e.HomeChainSel,
FeedChainSel: e.FeedChainSel,
ChainsToDeploy: initialDeploy,
TokenConfig: tokenConfig,
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
OCRParams: ocrParams,
})
require.NoError(t, err)

Expand All @@ -75,7 +80,7 @@ func TestAddChainInbound(t *testing.T) {
for _, source := range initialDeploy {
for _, dest := range initialDeploy {
if source != dest {
require.NoError(t, AddLaneWithDefaultPrices(e.Env, state, source, dest))
require.NoError(t, AddLaneWithDefaultPricesAndFeeQuoterConfig(e.Env, state, source, dest, false))
}
}
}
Expand Down
115 changes: 107 additions & 8 deletions deployment/ccip/changeset/add_lane.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package changeset

import (
"encoding/hex"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccipevm"
Expand All @@ -15,25 +17,122 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
)

var _ deployment.ChangeSet[AddLanesConfig] = AddLanesWithTestRouter

type InitialPrices struct {
LinkPrice *big.Int // USD to the power of 18 (e18) per LINK
WethPrice *big.Int // USD to the power of 18 (e18) per WETH
GasPrice *big.Int // uint224 packed gas price in USD (112 for exec // 112 for da)
}

func (p InitialPrices) Validate() error {
if p.LinkPrice == nil {
return fmt.Errorf("missing link price")
}
if p.WethPrice == nil {
return fmt.Errorf("missing weth price")
}
if p.GasPrice == nil {
return fmt.Errorf("missing gas price")
}
return nil
}

type LaneConfig struct {
SourceSelector uint64
DestSelector uint64
InitialPricesBySource InitialPrices
FeeQuoterDestChain fee_quoter.FeeQuoterDestChainConfig
}

type AddLanesConfig struct {
LaneConfigs []LaneConfig
}

func (c AddLanesConfig) Validate() error {
for _, pair := range c.LaneConfigs {
if pair.SourceSelector == pair.DestSelector {
return fmt.Errorf("cannot add lane to the same chain")
}
if err := pair.InitialPricesBySource.Validate(); err != nil {
return fmt.Errorf("error in validating initial prices for chain %d : %w", pair.SourceSelector, err)
}
// TODO: add more FeeQuoterDestChainConfigArgs validation
if pair.FeeQuoterDestChain == (fee_quoter.FeeQuoterDestChainConfig{}) {
return fmt.Errorf("missing fee quoter dest chain config")
}
}
return nil
}

// AddLanesWithTestRouter adds lanes between chains using the test router.
// AddLanesWithTestRouter is run while the contracts are still owned by the deployer.
// This is useful to test the initial deployment to enable lanes between chains.
// Once the testrouter is enabled, the lanes can be used to send messages between chains with testrouter.
// On successful verification with testrouter, the lanes can be enabled with the main router with different AddLane ChangeSet.
func AddLanesWithTestRouter(e deployment.Environment, cfg AddLanesConfig) (deployment.ChangesetOutput, error) {
if err := cfg.Validate(); err != nil {
return deployment.ChangesetOutput{}, fmt.Errorf("invalid AddLanesConfig: %w", err)
}
newAddresses := deployment.NewMemoryAddressBook()
err := addLanes(e, cfg)
if err != nil {
e.Logger.Errorw("Failed to add lanes", "err", err)
return deployment.ChangesetOutput{}, err
}
return deployment.ChangesetOutput{
Proposals: []timelock.MCMSWithTimelockProposal{},
AddressBook: newAddresses,
JobSpecs: nil,
}, nil
}

var DefaultInitialPrices = InitialPrices{
LinkPrice: deployment.E18Mult(20),
WethPrice: deployment.E18Mult(4000),
GasPrice: ToPackedFee(big.NewInt(8e14), big.NewInt(0)),
}

func AddLaneWithDefaultPrices(e deployment.Environment, state CCIPOnChainState, from, to uint64) error {
return AddLane(e, state, from, to, DefaultInitialPrices)
func addLanes(e deployment.Environment, cfg AddLanesConfig) error {
state, err := LoadOnchainState(e)
if err != nil {
return fmt.Errorf("failed to load onchain state: %w", err)
}
for _, laneCfg := range cfg.LaneConfigs {
e.Logger.Infow("Enabling lane with test router", "from", laneCfg.SourceSelector, "to", laneCfg.DestSelector)
if err := AddLane(e, state, laneCfg, true); err != nil {
return err
}
}
return nil
}

func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64, initialPrices InitialPrices) error {
func AddLaneWithDefaultPricesAndFeeQuoterConfig(e deployment.Environment, state CCIPOnChainState, from, to uint64, isTestRouter bool) error {
cfg := LaneConfig{
SourceSelector: from,
DestSelector: to,
InitialPricesBySource: DefaultInitialPrices,
FeeQuoterDestChain: DefaultFeeQuoterDestChainConfig(),
}
return AddLane(e, state, cfg, isTestRouter)
}

func AddLane(e deployment.Environment, state CCIPOnChainState, config LaneConfig, isTestRouter bool) error {
// TODO: Batch
tx, err := state.Chains[from].Router.ApplyRampUpdates(e.Chains[from].DeployerKey, []router.RouterOnRamp{
var fromRouter *router.Router
var toRouter *router.Router
from := config.SourceSelector
to := config.DestSelector
feeQuoterDestChainConfig := config.FeeQuoterDestChain
initialPrices := config.InitialPricesBySource
if isTestRouter {
fromRouter = state.Chains[from].TestRouter
toRouter = state.Chains[to].TestRouter
} else {
fromRouter = state.Chains[from].Router
toRouter = state.Chains[to].Router
}
tx, err := fromRouter.ApplyRampUpdates(e.Chains[from].DeployerKey, []router.RouterOnRamp{
{
DestChainSelector: to,
OnRamp: state.Chains[from].OnRamp.Address(),
Expand All @@ -46,7 +145,7 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64,
[]onramp.OnRampDestChainConfigArgs{
{
DestChainSelector: to,
Router: state.Chains[from].Router.Address(),
Router: fromRouter.Address(),
},
})
if _, err := deployment.ConfirmIfNoError(e.Chains[from], tx, err); err != nil {
Expand Down Expand Up @@ -80,7 +179,7 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64,
[]fee_quoter.FeeQuoterDestChainConfigArgs{
{
DestChainSelector: to,
DestChainConfig: DefaultFeeQuoterDestChainConfig(),
DestChainConfig: feeQuoterDestChainConfig,
},
})
if _, err := deployment.ConfirmIfNoError(e.Chains[from], tx, err); err != nil {
Expand All @@ -90,7 +189,7 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64,
tx, err = state.Chains[to].OffRamp.ApplySourceChainConfigUpdates(e.Chains[to].DeployerKey,
[]offramp.OffRampSourceChainConfigArgs{
{
Router: state.Chains[to].Router.Address(),
Router: toRouter.Address(),
SourceChainSelector: from,
IsEnabled: true,
OnRamp: common.LeftPadBytes(state.Chains[from].OnRamp.Address().Bytes(), 32),
Expand All @@ -99,7 +198,7 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64,
if _, err := deployment.ConfirmIfNoError(e.Chains[to], tx, err); err != nil {
return err
}
tx, err = state.Chains[to].Router.ApplyRampUpdates(e.Chains[to].DeployerKey, []router.RouterOnRamp{}, []router.RouterOffRamp{}, []router.RouterOffRamp{
tx, err = toRouter.ApplyRampUpdates(e.Chains[to].DeployerKey, []router.RouterOnRamp{}, []router.RouterOffRamp{}, []router.RouterOffRamp{
{
SourceChainSelector: from,
OffRamp: state.Chains[to].OffRamp.Address(),
Expand Down
46 changes: 44 additions & 2 deletions deployment/ccip/changeset/add_lane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,48 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/logger"
)

func TestAddLanesWithTestRouter(t *testing.T) {
e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil)
// Here we have CR + nodes set up, but no CCIP contracts deployed.
state, err := LoadOnchainState(e.Env)
require.NoError(t, err)

selectors := e.Env.AllChainSelectors()
chain1, chain2 := selectors[0], selectors[1]

_, err = AddLanesWithTestRouter(e.Env, AddLanesConfig{
LaneConfigs: []LaneConfig{
{
SourceSelector: chain1,
DestSelector: chain2,
InitialPricesBySource: DefaultInitialPrices,
FeeQuoterDestChain: DefaultFeeQuoterDestChainConfig(),
},
},
})
require.NoError(t, err)
// Need to keep track of the block number for each chain so that event subscription can be done from that block.
startBlocks := make(map[uint64]*uint64)
// Send a message from each chain to every other chain.
expectedSeqNumExec := make(map[SourceDestPair][]uint64)
latesthdr, err := e.Env.Chains[chain2].Client.HeaderByNumber(testcontext.Get(t), nil)
require.NoError(t, err)
block := latesthdr.Number.Uint64()
startBlocks[chain2] = &block
msgSentEvent := TestSendRequest(t, e.Env, state, chain1, chain2, true, router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(state.Chains[chain2].Receiver.Address().Bytes(), 32),
Data: []byte("hello"),
TokenAmounts: nil,
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
})
expectedSeqNumExec[SourceDestPair{
SourceChainSelector: chain1,
DestChainSelector: chain2,
}] = []uint64{msgSentEvent.SequenceNumber}
ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks)
}

// TestAddLane covers the workflow of adding a lane between two chains and enabling it.
// It also covers the case where the onRamp is disabled on the OffRamp contract initially and then enabled.
func TestAddLane(t *testing.T) {
Expand All @@ -41,7 +83,7 @@ func TestAddLane(t *testing.T) {
require.NoError(t, err)

// Add one lane from chain1 to chain 2 and send traffic.
require.NoError(t, AddLaneWithDefaultPrices(e.Env, state, chain1, chain2))
require.NoError(t, AddLaneWithDefaultPricesAndFeeQuoterConfig(e.Env, state, chain1, chain2, false))

ReplayLogs(t, e.Env.Offchain, replayBlocks)
time.Sleep(30 * time.Second)
Expand Down Expand Up @@ -87,7 +129,7 @@ func TestAddLane(t *testing.T) {
require.Equal(t, uint64(1), msgSentEvent1.SequenceNumber)

// Add another lane
require.NoError(t, AddLaneWithDefaultPrices(e.Env, state, chain2, chain1))
require.NoError(t, AddLaneWithDefaultPricesAndFeeQuoterConfig(e.Env, state, chain2, chain1, false))

// Send traffic on the second lane and it should succeed
latesthdr, err = e.Env.Chains[chain1].Client.HeaderByNumber(testcontext.Get(t), nil)
Expand Down
Loading

0 comments on commit a2a67f8

Please sign in to comment.