Skip to content

Commit 58bdfd0

Browse files
authored
Merge branch 'main' into julien/fi
2 parents 5c4bc32 + 13fb77d commit 58bdfd0

12 files changed

Lines changed: 63 additions & 199 deletions

File tree

.github/workflows/integration_test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ jobs:
165165
# replace the github.com/evstack/ev-abci module with the local version
166166
go mod edit -replace github.com/evstack/ev-abci=$GO_EXECUTION_ABCI_DIR
167167
168+
# pin dependency versions to avoid compatibility issues
169+
go mod edit -replace github.com/libp2p/go-libp2p-quic-transport=github.com/libp2p/go-libp2p-quic-transport@v0.33.1
170+
go mod edit -replace github.com/libp2p/go-libp2p=github.com/libp2p/go-libp2p@v0.43.0
171+
go mod edit -replace github.com/quic-go/quic-go=github.com/quic-go/quic-go@v0.54.1
172+
go mod edit -replace github.com/quic-go/webtransport-go=github.com/quic-go/webtransport-go@v0.9.0
173+
go mod edit -replace github.com/multiformats/go-multiaddr=github.com/multiformats/go-multiaddr@v0.16.1
174+
go mod edit -replace buf.build/go/protovalidate=buf.build/go/protovalidate@v0.12.0
175+
168176
# download dependencies and update go.mod/go.sum
169177
go mod tidy
170178

Dockerfile

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ RUN ignite app install github.com/ignite/apps/evolve@${IGNITE_EVOLVE_APP_VERSION
2828

2929
RUN go mod edit -replace github.com/evstack/ev-node=github.com/evstack/ev-node@${EVNODE_VERSION} && \
3030
go mod edit -replace github.com/evstack/ev-abci=/workspace/ev-abci && \
31-
go mod tidy
31+
go mod edit -replace github.com/libp2p/go-libp2p-quic-transport=github.com/libp2p/go-libp2p-quic-transport@v0.33.1 && \
32+
go mod edit -replace github.com/libp2p/go-libp2p=github.com/libp2p/go-libp2p@v0.43.0 && \
33+
go mod edit -replace github.com/quic-go/quic-go=github.com/quic-go/quic-go@v0.54.1 && \
34+
go mod edit -replace github.com/quic-go/webtransport-go=github.com/quic-go/webtransport-go@v0.9.0 && \
35+
go mod edit -replace github.com/multiformats/go-multiaddr=github.com/multiformats/go-multiaddr@v0.16.1 && \
36+
go mod edit -replace buf.build/go/protovalidate=buf.build/go/protovalidate@v0.12.0 && \
37+
go mod tidy && \
38+
go mod download
39+
40+
# Verify pinned module versions are effective in build context
41+
RUN go list -m all | grep -E 'github.com/libp2p/go-libp2p|github.com/multiformats/go-multiaddr'
3242

3343
# TODO: replace this with proper ignite flag to skip IBC registration when available
3444
# Patch out IBC registration (comment out the call and its error handling)

Dockerfile.cosmos-sdk

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ RUN if [ "$ENABLE_IBC" = "false" ]; then \
3535
echo "IBC enabled, leaving registration intact."; \
3636
fi
3737

38+
# Pin dependency versions to avoid compatibility issues
39+
RUN go mod edit -replace github.com/libp2p/go-libp2p-quic-transport=github.com/libp2p/go-libp2p-quic-transport@v0.33.1 && \
40+
go mod edit -replace github.com/libp2p/go-libp2p=github.com/libp2p/go-libp2p@v0.43.0 && \
41+
go mod edit -replace github.com/quic-go/quic-go=github.com/quic-go/quic-go@v0.54.1 && \
42+
go mod edit -replace github.com/quic-go/webtransport-go=github.com/quic-go/webtransport-go@v0.9.0 && \
43+
go mod edit -replace github.com/multiformats/go-multiaddr=github.com/multiformats/go-multiaddr@v0.16.1 && \
44+
go mod edit -replace buf.build/go/protovalidate=buf.build/go/protovalidate@v0.12.0 && \
45+
go mod tidy && \
46+
go mod download
47+
48+
# Verify pinned module versions are effective in build context
49+
RUN go list -m all | grep -E 'github.com/libp2p/go-libp2p|github.com/multiformats/go-multiaddr'
50+
3851
# Build the Cosmos SDK binary
3952
RUN ignite chain build --skip-proto
4053

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ replace (
1414
replace (
1515
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.0-beta
1616
github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.50.14
17+
github.com/libp2p/go-libp2p => github.com/libp2p/go-libp2p v0.43.0
18+
github.com/libp2p/go-libp2p-quic-transport => github.com/libp2p/go-libp2p-quic-transport v0.33.1
19+
github.com/quic-go/quic-go => github.com/quic-go/quic-go v0.54.1
20+
github.com/quic-go/webtransport-go => github.com/quic-go/webtransport-go v0.9.0
1721
)
1822

1923
exclude github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2

modules/migrationmngr/README.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,11 @@ The core of the migration is handled by returning `abci.ValidatorUpdate` message
116116
- **Removing Old Validators**: The existing validators that are not part of the new sequencer/attester set have their power reduced to `0`.
117117
- **Adding New Participants**: The new sequencer and/or attesters are added to the consensus set with a power of `1`.
118118

119-
### IBC-Aware Migrations
119+
### Migration Execution
120120

121-
A critical feature of the migration manager is its awareness of the Inter-Blockchain Communication (IBC) protocol. A sudden, drastic change in the validator set can cause IBC light clients on other chains to fail their verification checks, leading to a broken connection.
121+
The migration is performed in a single, atomic step. At the migration start height, all old validators are removed, and the new sequencer/attesters are added in one atomic update.
122122

123-
To prevent this, the module first checks if IBC is enabled by verifying the existence of the IBC module's store key.
124-
125-
- **If IBC is Enabled**: The migration is "smoothed" over a period of blocks (currently `30` blocks, defined by `IBCSmoothingFactor`). In each block during this period, a fraction of the old validators are removed, and a fraction of the new attesters are added. This gradual change ensures that IBC light clients can safely update their trusted validator sets without interruption. On the first block of the migration, all validators are set to have an equal power of `1` to prevent any single validator from having a disproportionate amount of power during the transition.
126-
- **If IBC is Not Enabled**: The migration can be performed "immediately" in a single block. All old validators are removed, and the new sequencer/attesters are added in one atomic update at the migration start height.
123+
**Note:** IBC light client updates must be performed at height H+1 (one block after the migration) to ensure proper verification of the validator set changes.
127124

128125
### The Chain Halt: A Coordinated Upgrade
129126

@@ -143,7 +140,7 @@ If you are a validator or node operator on a chain using this module, you must b
143140

144141
1. **Monitor Governance**: The migration will be initiated by a governance proposal. Stay informed about upcoming proposals. The proposal will define the target block height for the migration.
145142

146-
2. **Prepare for the Chain Halt**: Your node **will stop** at a predictable block height, calculated from the migration's start height (`block_height` in the proposal). With IBC enabled, the halt is at `block_height + 31`; without IBC, it is `block_height + 2`. This is expected. Check your node's logs for the specific "MIGRATE" error message.
143+
2. **Prepare for the Chain Halt**: Your node **will stop** at a predictable block height, calculated from the migration's start height (`block_height` in the proposal). The halt occurs at `block_height + 2`. This is expected. Check your node's logs for the specific "MIGRATE" error message.
147144

148145
3. **Perform the Upgrade**: Once the chain has halted, you must perform the following steps:
149146
a. **Install the New Binary**: You will need to replace your current node software (e.g., `gmd`) with the new version required for the rollup.

modules/migrationmngr/depinject.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,10 @@ func init() {
2828
type ModuleInputs struct {
2929
depinject.In
3030

31-
Config *modulev1.Module
32-
Cdc codec.Codec
33-
StoreService store.KVStoreService
34-
AddressCodec address.Codec
35-
// optional, used to detect if IBC module is enabled.
36-
// When IBC module is present, use `depinject.Provide(IBCStoreKey(ibcStoreKey))`
37-
IBCStoreKey keeper.IbcKVStoreKeyAlias `optional:"true"`
38-
31+
Config *modulev1.Module
32+
Cdc codec.Codec
33+
StoreService store.KVStoreService
34+
AddressCodec address.Codec
3935
StakingKeeper types.StakingKeeper
4036
}
4137

@@ -59,7 +55,6 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
5955
in.StoreService,
6056
in.AddressCodec,
6157
in.StakingKeeper,
62-
in.IBCStoreKey,
6358
authority.String(),
6459
)
6560
m := NewAppModule(in.Cdc, k)

modules/migrationmngr/keeper/abci.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,9 @@ func (k Keeper) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) {
7777
}
7878

7979
var updates []abci.ValidatorUpdate
80-
if !k.isIBCEnabled(ctx) {
81-
// if IBC is not enabled, we can migrate immediately
82-
// but only return updates on the first block of migration (start height)
83-
if uint64(sdkCtx.BlockHeight()) == start {
84-
updates, err = k.migrateNow(ctx, migration, validatorSet)
85-
if err != nil {
86-
return nil, err
87-
}
88-
}
89-
} else {
90-
updates, err = k.migrateOver(sdkCtx, migration, validatorSet)
80+
// Always perform immediate migration updates at the start height.
81+
if uint64(sdkCtx.BlockHeight()) == start {
82+
updates, err = k.migrateNow(ctx, migration, validatorSet)
9183
if err != nil {
9284
return nil, err
9385
}

modules/migrationmngr/keeper/grpc_query_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ func initFixture(tb testing.TB) *fixture {
7474
storeService,
7575
addressCodec,
7676
stakingKeeper,
77-
nil,
7877
sdk.AccAddress(address.Module(types.ModuleName)).String(),
7978
)
8079

@@ -144,7 +143,6 @@ func TestIsMigrating_IBCEnabled(t *testing.T) {
144143
storeService,
145144
addressCodec,
146145
stakingKeeper,
147-
func() *storetypes.KVStoreKey { return key },
148146
sdk.AccAddress(address.Module(types.ModuleName)).String(),
149147
)
150148

@@ -159,7 +157,7 @@ func TestIsMigrating_IBCEnabled(t *testing.T) {
159157
require.NoError(t, err)
160158
require.True(t, resp.IsMigrating)
161159
require.Equal(t, uint64(1), resp.StartBlockHeight)
162-
require.Equal(t, 1+keeper.IBCSmoothingFactor, resp.EndBlockHeight)
160+
require.Equal(t, uint64(2), resp.EndBlockHeight)
163161
}
164162

165163
func TestSequencer_Migrating(t *testing.T) {

modules/migrationmngr/keeper/keeper.go

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,18 @@ import (
88
"cosmossdk.io/core/address"
99
corestore "cosmossdk.io/core/store"
1010
"cosmossdk.io/log"
11-
storetypes "cosmossdk.io/store/types"
1211
"github.com/cosmos/cosmos-sdk/codec"
1312
sdk "github.com/cosmos/cosmos-sdk/types"
1413

1514
"github.com/evstack/ev-abci/modules/migrationmngr/types"
1615
)
1716

18-
// IbcStoreKey is the store key used for IBC-related data.
19-
// It is an alias for storetypes.StoreKey to allow depinject to resolve it as a dependency (as runtime assumes 1 module = 1 store key maximum).
20-
type IbcKVStoreKeyAlias = func() *storetypes.KVStoreKey
21-
2217
type Keeper struct {
2318
storeService corestore.KVStoreService
2419
cdc codec.BinaryCodec
2520
addressCodec address.Codec
2621
authority string
2722

28-
ibcStoreKey IbcKVStoreKeyAlias
2923
stakingKeeper types.StakingKeeper
3024

3125
Schema collections.Schema
@@ -40,7 +34,6 @@ func NewKeeper(
4034
storeService corestore.KVStoreService,
4135
addressCodec address.Codec,
4236
stakingKeeper types.StakingKeeper,
43-
ibcStoreKey IbcKVStoreKeyAlias,
4437
authority string,
4538
) Keeper {
4639
// ensure that authority is a valid account address
@@ -55,7 +48,6 @@ func NewKeeper(
5548
authority: authority,
5649
addressCodec: addressCodec,
5750
stakingKeeper: stakingKeeper,
58-
ibcStoreKey: ibcStoreKey,
5951
Sequencer: collections.NewItem(
6052
sb,
6153
types.SequencerKey,
@@ -103,42 +95,12 @@ func (k Keeper) IsMigrating(ctx context.Context) (start, end uint64, ok bool) {
10395
return 0, 0, false
10496
}
10597

106-
// smoothen the migration over IBCSmoothingFactor blocks, in order to migrate the validator set to the sequencer or attesters network when IBC is enabled.
107-
migrationEndHeight := migration.BlockHeight + IBCSmoothingFactor
108-
109-
// If IBC is not enabled, the migration can be done in one block.
110-
if !k.isIBCEnabled(ctx) {
111-
migrationEndHeight = migration.BlockHeight + 1
112-
}
98+
// Migration is performed in a single step.
99+
migrationEndHeight := migration.BlockHeight + 1
113100

114101
sdkCtx := sdk.UnwrapSDKContext(ctx)
115102
currentHeight := uint64(sdkCtx.BlockHeight())
116103
migrationInProgress := currentHeight >= migration.BlockHeight && currentHeight <= migrationEndHeight
117104

118105
return migration.BlockHeight, migrationEndHeight, migrationInProgress
119106
}
120-
121-
// isIBCEnabled checks if IBC is enabled on the chain.
122-
// In order to not import the IBC module, we only check if the IBC store exists,
123-
// but not the ibc params. This should be sufficient for our use case.
124-
func (k Keeper) isIBCEnabled(ctx context.Context) bool {
125-
enabled := true
126-
127-
if k.ibcStoreKey == nil {
128-
return false
129-
}
130-
131-
sdkCtx := sdk.UnwrapSDKContext(ctx)
132-
133-
ms := sdkCtx.MultiStore().CacheMultiStore()
134-
defer func() {
135-
if r := recover(); r != nil {
136-
// If we panic, it means the store does not exist, so IBC is not enabled.
137-
enabled = false
138-
}
139-
}()
140-
ms.GetKVStore(k.ibcStoreKey())
141-
142-
// has not panicked, so store exists
143-
return enabled
144-
}

modules/migrationmngr/keeper/migration.go

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@ package keeper
22

33
import (
44
"context"
5-
"errors"
65

7-
"cosmossdk.io/collections"
86
abci "github.com/cometbft/cometbft/abci/types"
97
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
108
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
119

1210
"github.com/evstack/ev-abci/modules/migrationmngr/types"
1311
)
1412

15-
// IBCSmoothingFactor is the factor used to smooth the migration process when IBC is enabled. It determines how many blocks the migration will take.
16-
var IBCSmoothingFactor uint64 = 30
17-
1813
// migrateNow migrates the chain to evolve immediately.
19-
// this method is used when ibc is not enabled, so no migration smoothing is needed.
2014
func (k Keeper) migrateNow(
2115
ctx context.Context,
2216
migrationData types.EvolveMigration,
@@ -116,122 +110,3 @@ func migrateToAttesters(
116110

117111
return initialValUpdates, nil
118112
}
119-
120-
// migrateOver migrates the chain to evolve over a period of blocks.
121-
// this is to ensure ibc light client verification keep working while changing the whole validator set.
122-
// the migration step is tracked in store.
123-
func (k Keeper) migrateOver(
124-
ctx context.Context,
125-
migrationData types.EvolveMigration,
126-
lastValidatorSet []stakingtypes.Validator,
127-
) (initialValUpdates []abci.ValidatorUpdate, err error) {
128-
step, err := k.MigrationStep.Get(ctx)
129-
if err != nil && !errors.Is(err, collections.ErrNotFound) {
130-
return nil, sdkerrors.ErrInvalidRequest.Wrapf("failed to get migration step: %v", err)
131-
}
132-
133-
if step >= IBCSmoothingFactor {
134-
// migration complete, just return the final set (same as migrateNow)
135-
if err := k.MigrationStep.Remove(ctx); err != nil {
136-
return nil, sdkerrors.ErrInvalidRequest.Wrapf("failed to remove migration step: %v", err)
137-
}
138-
return k.migrateNow(ctx, migrationData, lastValidatorSet)
139-
}
140-
141-
switch len(migrationData.Attesters) {
142-
case 0:
143-
// no attesters, migrate to a single sequencer over smoothing period
144-
// remove all validators except the sequencer, add sequencer at the end
145-
seq := migrationData.Sequencer
146-
var oldValsToRemove []stakingtypes.Validator
147-
for _, val := range lastValidatorSet {
148-
if !val.ConsensusPubkey.Equal(seq.ConsensusPubkey) {
149-
oldValsToRemove = append(oldValsToRemove, val)
150-
}
151-
}
152-
removePerStep := (len(oldValsToRemove) + int(IBCSmoothingFactor) - 1) / int(IBCSmoothingFactor)
153-
startRemove := int(step) * removePerStep
154-
endRemove := min(startRemove+removePerStep, len(oldValsToRemove))
155-
for _, val := range oldValsToRemove[startRemove:endRemove] {
156-
powerUpdate := val.ABCIValidatorUpdateZero()
157-
initialValUpdates = append(initialValUpdates, powerUpdate)
158-
}
159-
default:
160-
// attesters present, migrate as before
161-
attesterPubKeys := make(map[string]struct{})
162-
for _, attester := range migrationData.Attesters {
163-
attesterPubKeys[attester.ConsensusPubkey.String()] = struct{}{}
164-
}
165-
var oldValsToRemove []stakingtypes.Validator
166-
for _, val := range lastValidatorSet {
167-
if _, ok := attesterPubKeys[val.ConsensusPubkey.String()]; !ok {
168-
oldValsToRemove = append(oldValsToRemove, val)
169-
}
170-
}
171-
lastValPubKeys := make(map[string]struct{})
172-
for _, val := range lastValidatorSet {
173-
lastValPubKeys[val.ConsensusPubkey.String()] = struct{}{}
174-
}
175-
var newAttestersToAdd []types.Attester
176-
for _, attester := range migrationData.Attesters {
177-
if _, ok := lastValPubKeys[attester.ConsensusPubkey.String()]; !ok {
178-
newAttestersToAdd = append(newAttestersToAdd, attester)
179-
}
180-
}
181-
removePerStep := (len(oldValsToRemove) + int(IBCSmoothingFactor) - 1) / int(IBCSmoothingFactor)
182-
addPerStep := (len(newAttestersToAdd) + int(IBCSmoothingFactor) - 1) / int(IBCSmoothingFactor)
183-
startRemove := int(step) * removePerStep
184-
endRemove := min(startRemove+removePerStep, len(oldValsToRemove))
185-
for _, val := range oldValsToRemove[startRemove:endRemove] {
186-
powerUpdate := val.ABCIValidatorUpdateZero()
187-
initialValUpdates = append(initialValUpdates, powerUpdate)
188-
}
189-
startAdd := int(step) * addPerStep
190-
endAdd := min(startAdd+addPerStep, len(newAttestersToAdd))
191-
for _, attester := range newAttestersToAdd[startAdd:endAdd] {
192-
pk, err := attester.TmConsPublicKey()
193-
if err != nil {
194-
return nil, sdkerrors.ErrInvalidRequest.Wrapf("failed to get attester pubkey: %v", err)
195-
}
196-
attesterUpdate := abci.ValidatorUpdate{
197-
PubKey: pk,
198-
Power: 1,
199-
}
200-
initialValUpdates = append(initialValUpdates, attesterUpdate)
201-
}
202-
}
203-
204-
// increment and persist the step
205-
if err := k.MigrationStep.Set(ctx, step+1); err != nil {
206-
return nil, sdkerrors.ErrInvalidRequest.Wrapf("failed to set migration step: %v", err)
207-
}
208-
209-
// the first time, we set the whole validator set to the same validator power. This is to avoid a validator ends up with >= 33% or worse >= 66%
210-
// vp during the migration.
211-
// TODO: add a test
212-
if step == 0 {
213-
// Create a map of existing updates for O(1) lookup
214-
existingUpdates := make(map[string]bool)
215-
for _, powerUpdate := range initialValUpdates {
216-
existingUpdates[powerUpdate.PubKey.String()] = true
217-
}
218-
219-
// set the whole validator set to the same power
220-
for _, val := range lastValidatorSet {
221-
valPubKey, err := val.CmtConsPublicKey()
222-
if err != nil {
223-
return nil, sdkerrors.ErrInvalidRequest.Wrapf("failed to get validator pubkey: %v", err)
224-
}
225-
226-
if !existingUpdates[valPubKey.String()] {
227-
powerUpdate := abci.ValidatorUpdate{
228-
PubKey: valPubKey,
229-
Power: 1,
230-
}
231-
initialValUpdates = append(initialValUpdates, powerUpdate)
232-
}
233-
}
234-
}
235-
236-
return initialValUpdates, nil
237-
}

0 commit comments

Comments
 (0)