Skip to content

Commit ba9f2e9

Browse files
authored
Add changeset to add bidirectional lanes (#17015)
* Add changeset to add bidirectional lanes * Add tests * Fix * Goimports * Comments * Lint * Fix link * Fix build
1 parent 07d030b commit ba9f2e9

File tree

2 files changed

+649
-0
lines changed

2 files changed

+649
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
package v1_6
2+
3+
import (
4+
"fmt"
5+
"math/big"
6+
7+
"github.com/smartcontractkit/mcms"
8+
9+
"github.com/smartcontractkit/chainlink/deployment"
10+
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
11+
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
12+
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_6_0/fee_quoter"
13+
)
14+
15+
// UpdateBidirectionalLanesChangeset enables or disables multiple bidirectional lanes on CCIP.
16+
// It batches all lane updates into a single MCMS proposal.
17+
var UpdateBidirectionalLanesChangeset = deployment.CreateChangeSet(updateBidirectionalLanesLogic, updateBidirectionalLanesPrecondition)
18+
19+
// BidirectionalLaneDefinition indicates two chains that we want to connect.
20+
type BidirectionalLaneDefinition struct {
21+
// IsDisabled indicates if the lane should be disabled.
22+
// We use IsDisabled instead of IsEnabled because enabling a lane should be the default action.
23+
IsDisabled bool
24+
Chains [2]ChainDefinition
25+
}
26+
27+
// laneDefinition defines a lane between source and destination.
28+
type laneDefinition struct {
29+
// Source defines the source chain.
30+
Source ChainDefinition
31+
// Dest defines the destination chain.
32+
Dest ChainDefinition
33+
}
34+
35+
// UpdateBidirectionalLanesConfig is a configuration struct for UpdateBidirectionalLanesChangeset.
36+
type UpdateBidirectionalLanesConfig struct {
37+
// MCMSConfig defines the MCMS configuration for the changeset.
38+
MCMSConfig *proposalutils.TimelockConfig
39+
// Lanes describes the lanes that we want to create.
40+
Lanes []BidirectionalLaneDefinition
41+
// TestRouter indicates if we want to enable these lanes on the test router.
42+
TestRouter bool
43+
}
44+
45+
type UpdateBidirectionalLanesChangesetConfigs struct {
46+
UpdateFeeQuoterDestsConfig UpdateFeeQuoterDestsConfig
47+
UpdateFeeQuoterPricesConfig UpdateFeeQuoterPricesConfig
48+
UpdateOnRampDestsConfig UpdateOnRampDestsConfig
49+
UpdateOffRampSourcesConfig UpdateOffRampSourcesConfig
50+
UpdateRouterRampsConfig UpdateRouterRampsConfig
51+
}
52+
53+
func (c UpdateBidirectionalLanesConfig) BuildConfigs() UpdateBidirectionalLanesChangesetConfigs {
54+
onRampUpdatesByChain := make(map[uint64]map[uint64]OnRampDestinationUpdate)
55+
offRampUpdatesByChain := make(map[uint64]map[uint64]OffRampSourceUpdate)
56+
routerUpdatesByChain := make(map[uint64]RouterUpdates)
57+
feeQuoterDestUpdatesByChain := make(map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig)
58+
feeQuoterPriceUpdatesByChain := make(map[uint64]FeeQuoterPriceUpdatePerSource)
59+
60+
for _, lane := range c.Lanes {
61+
isEnabled := !lane.IsDisabled
62+
chainA := lane.Chains[0]
63+
chainB := lane.Chains[1]
64+
65+
laneAToB := laneDefinition{
66+
Source: chainA,
67+
Dest: chainB,
68+
}
69+
laneBToA := laneDefinition{
70+
Source: chainB,
71+
Dest: chainA,
72+
}
73+
74+
for _, laneDef := range []laneDefinition{laneAToB, laneBToA} {
75+
// Setting the destination on the on ramp
76+
if onRampUpdatesByChain[laneDef.Source.Selector] == nil {
77+
onRampUpdatesByChain[laneDef.Source.Selector] = make(map[uint64]OnRampDestinationUpdate)
78+
}
79+
onRampUpdatesByChain[laneDef.Source.Selector][laneDef.Dest.Selector] = OnRampDestinationUpdate{
80+
IsEnabled: isEnabled,
81+
TestRouter: c.TestRouter,
82+
AllowListEnabled: laneDef.Dest.AllowListEnabled,
83+
}
84+
85+
// Setting the source on the off ramp
86+
if offRampUpdatesByChain[laneDef.Dest.Selector] == nil {
87+
offRampUpdatesByChain[laneDef.Dest.Selector] = make(map[uint64]OffRampSourceUpdate)
88+
}
89+
offRampUpdatesByChain[laneDef.Dest.Selector][laneDef.Source.Selector] = OffRampSourceUpdate{
90+
IsEnabled: isEnabled,
91+
TestRouter: c.TestRouter,
92+
IsRMNVerificationDisabled: laneDef.Source.RMNVerificationDisabled,
93+
}
94+
95+
// Setting the on ramp on the source router
96+
routerUpdatesOnSource := routerUpdatesByChain[laneDef.Source.Selector]
97+
if routerUpdatesByChain[laneDef.Source.Selector].OnRampUpdates == nil {
98+
routerUpdatesOnSource.OnRampUpdates = make(map[uint64]bool)
99+
}
100+
routerUpdatesOnSource.OnRampUpdates[laneDef.Dest.Selector] = isEnabled
101+
routerUpdatesByChain[laneDef.Source.Selector] = routerUpdatesOnSource
102+
103+
// Setting the off ramp on the dest router
104+
routerUpdatesOnDest := routerUpdatesByChain[laneDef.Dest.Selector]
105+
if routerUpdatesByChain[laneDef.Dest.Selector].OffRampUpdates == nil {
106+
routerUpdatesOnDest.OffRampUpdates = make(map[uint64]bool)
107+
}
108+
routerUpdatesOnDest.OffRampUpdates[laneDef.Source.Selector] = isEnabled
109+
routerUpdatesByChain[laneDef.Dest.Selector] = routerUpdatesOnDest
110+
111+
// Setting the fee quoter destination on the source chain
112+
if feeQuoterDestUpdatesByChain[laneDef.Source.Selector] == nil {
113+
feeQuoterDestUpdatesByChain[laneDef.Source.Selector] = make(map[uint64]fee_quoter.FeeQuoterDestChainConfig)
114+
}
115+
feeQuoterDestUpdatesByChain[laneDef.Source.Selector][laneDef.Dest.Selector] = laneDef.Dest.FeeQuoterDestChainConfig
116+
117+
// Setting the destination gas prices on the source chain
118+
feeQuoterPriceUpdatesOnSource := feeQuoterPriceUpdatesByChain[laneDef.Source.Selector]
119+
if feeQuoterPriceUpdatesOnSource.GasPrices == nil {
120+
feeQuoterPriceUpdatesOnSource.GasPrices = make(map[uint64]*big.Int)
121+
}
122+
feeQuoterPriceUpdatesOnSource.GasPrices[laneDef.Dest.Selector] = laneDef.Dest.GasPrice
123+
feeQuoterPriceUpdatesByChain[laneDef.Source.Selector] = feeQuoterPriceUpdatesOnSource
124+
}
125+
}
126+
127+
routerMCMSConfig := c.MCMSConfig
128+
if c.TestRouter {
129+
routerMCMSConfig = nil // Test router is never owned by MCMS
130+
}
131+
132+
return UpdateBidirectionalLanesChangesetConfigs{
133+
UpdateFeeQuoterDestsConfig: UpdateFeeQuoterDestsConfig{
134+
MCMS: c.MCMSConfig,
135+
UpdatesByChain: feeQuoterDestUpdatesByChain,
136+
},
137+
UpdateFeeQuoterPricesConfig: UpdateFeeQuoterPricesConfig{
138+
MCMS: c.MCMSConfig,
139+
PricesByChain: feeQuoterPriceUpdatesByChain,
140+
},
141+
UpdateOnRampDestsConfig: UpdateOnRampDestsConfig{
142+
MCMS: c.MCMSConfig,
143+
UpdatesByChain: onRampUpdatesByChain,
144+
},
145+
UpdateOffRampSourcesConfig: UpdateOffRampSourcesConfig{
146+
MCMS: c.MCMSConfig,
147+
UpdatesByChain: offRampUpdatesByChain,
148+
},
149+
UpdateRouterRampsConfig: UpdateRouterRampsConfig{
150+
TestRouter: c.TestRouter,
151+
MCMS: routerMCMSConfig,
152+
UpdatesByChain: routerUpdatesByChain,
153+
},
154+
}
155+
}
156+
157+
func updateBidirectionalLanesPrecondition(e deployment.Environment, c UpdateBidirectionalLanesConfig) error {
158+
configs := c.BuildConfigs()
159+
state, err := changeset.LoadOnchainState(e)
160+
if err != nil {
161+
return fmt.Errorf("failed to load onchain state: %w", err)
162+
}
163+
164+
err = configs.UpdateFeeQuoterDestsConfig.Validate(e)
165+
if err != nil {
166+
return fmt.Errorf("failed to validate UpdateFeeQuoterDestsConfig: %w", err)
167+
}
168+
169+
err = configs.UpdateFeeQuoterPricesConfig.Validate(e)
170+
if err != nil {
171+
return fmt.Errorf("failed to validate UpdateFeeQuoterPricesConfig: %w", err)
172+
}
173+
174+
err = configs.UpdateOnRampDestsConfig.Validate(e)
175+
if err != nil {
176+
return fmt.Errorf("failed to validate UpdateOnRampDestsConfig: %w", err)
177+
}
178+
179+
err = configs.UpdateOffRampSourcesConfig.Validate(e, state)
180+
if err != nil {
181+
return fmt.Errorf("failed to validate UpdateOffRampSourcesConfig: %w", err)
182+
}
183+
184+
err = configs.UpdateRouterRampsConfig.Validate(e, state)
185+
if err != nil {
186+
return fmt.Errorf("failed to validate UpdateRouterRampsConfig: %w", err)
187+
}
188+
189+
return nil
190+
}
191+
192+
func updateBidirectionalLanesLogic(e deployment.Environment, c UpdateBidirectionalLanesConfig) (deployment.ChangesetOutput, error) {
193+
proposals := make([]mcms.TimelockProposal, 0)
194+
configs := c.BuildConfigs()
195+
196+
out, err := UpdateFeeQuoterDestsChangeset(e, configs.UpdateFeeQuoterDestsConfig)
197+
if err != nil {
198+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateFeeQuoterDestsChangeset: %w", err)
199+
}
200+
proposals = append(proposals, out.MCMSTimelockProposals...)
201+
e.Logger.Info("Destination configs updated on FeeQuoters")
202+
203+
out, err = UpdateFeeQuoterPricesChangeset(e, configs.UpdateFeeQuoterPricesConfig)
204+
if err != nil {
205+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateFeeQuoterPricesChangeset: %w", err)
206+
}
207+
proposals = append(proposals, out.MCMSTimelockProposals...)
208+
e.Logger.Info("Gas prices updated on FeeQuoters")
209+
210+
out, err = UpdateOnRampsDestsChangeset(e, configs.UpdateOnRampDestsConfig)
211+
if err != nil {
212+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateOnRampDestsChangeset: %w", err)
213+
}
214+
proposals = append(proposals, out.MCMSTimelockProposals...)
215+
e.Logger.Info("Destination configs updated on OnRamps")
216+
217+
out, err = UpdateOffRampSourcesChangeset(e, configs.UpdateOffRampSourcesConfig)
218+
if err != nil {
219+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateOffRampSourcesChangeset: %w", err)
220+
}
221+
proposals = append(proposals, out.MCMSTimelockProposals...)
222+
e.Logger.Info("Source configs updated on OffRamps")
223+
224+
out, err = UpdateRouterRampsChangeset(e, configs.UpdateRouterRampsConfig)
225+
if err != nil {
226+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to run UpdateRouterRampsChangeset: %w", err)
227+
}
228+
proposals = append(proposals, out.MCMSTimelockProposals...)
229+
e.Logger.Info("Ramps updated on Routers")
230+
231+
state, err := changeset.LoadOnchainState(e)
232+
if err != nil {
233+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to load onchain state: %w", err)
234+
}
235+
proposal, err := proposalutils.AggregateProposals(e, state.EVMMCMSStateByChain(), proposals, nil, "Update multiple bidirectional lanes", c.MCMSConfig)
236+
if err != nil {
237+
return deployment.ChangesetOutput{}, fmt.Errorf("failed to aggregate proposals: %w", err)
238+
}
239+
if proposal == nil {
240+
return deployment.ChangesetOutput{}, nil
241+
}
242+
243+
return deployment.ChangesetOutput{
244+
MCMSTimelockProposals: []mcms.TimelockProposal{*proposal},
245+
}, nil
246+
}

0 commit comments

Comments
 (0)