Skip to content

Commit

Permalink
added initial work on traversing initialized chains that are to-be-la…
Browse files Browse the repository at this point in the history
…unched
  • Loading branch information
insumity committed Jul 31, 2024
1 parent e69d248 commit 7dcb03c
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 9 deletions.
29 changes: 25 additions & 4 deletions x/ccv/provider/keeper/permissionless.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
storetypes "cosmossdk.io/store/types"
"encoding/binary"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -198,8 +199,28 @@ func (k Keeper) DeleteClientIdToConsumerId(ctx sdk.Context, clientId string) {
store.Delete(types.ClientIdToConsumerIdKey(clientId))
}

// IsConsumerLaunched returns true if the consumer chain with the provided id is launched
func (k Keeper) IsConsumerLaunched(ctx sdk.Context, consumerId string) bool {
_, found := k.GetConsumerClientId(ctx, consumerId)
return found
// GetInitializedConsumersReadyToLaunch returns the consumer ids of the pending initialized consumer chains
// that are ready to launch, i.e., consumer clients to be created.
func (k Keeper) GetInitializedConsumersReadyToLaunch(ctx sdk.Context) []string {
store := ctx.KVStore(k.storeKey)
iterator := storetypes.KVStorePrefixIterator(store, types.ConsumerIdToInitializationRecordKeyNameKeyPrefix())
defer iterator.Close()

var consumerIds []string

for ; iterator.Valid(); iterator.Next() {
var record types.ConsumerInitializationRecord
err := record.Unmarshal(iterator.Value())
if err != nil {
panic(fmt.Errorf("failed to unmarshal consumer record: %w for consumer id: %s", err, string(iterator.Value())))
}

if !ctx.BlockTime().Before(record.SpawnTime) {
// the `consumerId` resides in the whole key, but we skip the first byte (because it's the `ConsumerIdKey`)
// plus 8 more bytes for the `uint64` in the key that contains the length of the `consumerId`
consumerIds = append(consumerIds, string(iterator.Key()[1+8:]))
}
}

return consumerIds
}
52 changes: 47 additions & 5 deletions x/ccv/provider/keeper/permissionless_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
"github.com/stretchr/testify/require"
"testing"
Expand Down Expand Up @@ -192,13 +193,54 @@ func TestConsumerIdToOwnerAddress(t *testing.T) {
require.False(t, found)
}

func TestIsConsumerLaunched(t *testing.T) {
// TestConsumerIdToPhase tests the getter, setter, and deletion methods of the consumer id to phase methods
func TestConsumerIdToPhase(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

require.False(t, providerKeeper.IsConsumerLaunched(ctx, "consumerId"))
_, found := providerKeeper.GetConsumerIdToPhase(ctx, "consumerId")
require.False(t, found)

providerKeeper.SetConsumerIdToPhase(ctx, "consumerId", keeper.Registered)
phase, found := providerKeeper.GetConsumerIdToPhase(ctx, "consumerId")
require.True(t, found)
require.Equal(t, keeper.Registered, phase)

providerKeeper.SetConsumerIdToPhase(ctx, "consumerId", keeper.Launched)
phase, found = providerKeeper.GetConsumerIdToPhase(ctx, "consumerId")
require.True(t, found)
require.Equal(t, keeper.Launched, phase)
}

// TestGetInitializedConsumersReadyToLaunch tests that the ready to-be-launched consumer chains are returned
func TestGetInitializedConsumersReadyToLaunch(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

// no chains to-be-launched exist
require.Empty(t, providerKeeper.GetInitializedConsumersReadyToLaunch(ctx))

// set 3 initialization records with different spawn times
providerKeeper.SetConsumerIdToInitializationRecord(ctx, "consumerId1",
providertypes.ConsumerInitializationRecord{SpawnTime: time.Unix(10, 0)})
providerKeeper.SetConsumerIdToInitializationRecord(ctx, "consumerId2",
providertypes.ConsumerInitializationRecord{SpawnTime: time.Unix(20, 0)})
providerKeeper.SetConsumerIdToInitializationRecord(ctx, "consumerId3",
providertypes.ConsumerInitializationRecord{SpawnTime: time.Unix(30, 0)})

// time has not yet reached the spawn time of "consumerId1"
ctx = ctx.WithBlockTime(time.Unix(9, 999999999))
require.Empty(t, providerKeeper.GetInitializedConsumersReadyToLaunch(ctx))

// time has reached the spawn time of "consumerId1"
ctx = ctx.WithBlockTime(time.Unix(10, 0))
require.Equal(t, []string{"consumerId1"}, providerKeeper.GetInitializedConsumersReadyToLaunch(ctx))

// time has reached the spawn time of "consumerId1" and "consumerId2"
ctx = ctx.WithBlockTime(time.Unix(20, 0))
require.Equal(t, []string{"consumerId1", "consumerId2"}, providerKeeper.GetInitializedConsumersReadyToLaunch(ctx))

// set a consumer client id which is what happens when the chain launches
providerKeeper.SetConsumerClientId(ctx, "consumerId", "clientId")
require.True(t, providerKeeper.IsConsumerLaunched(ctx, "consumerId"))
// time has reached the spawn time of all chains
ctx = ctx.WithBlockTime(time.Unix(30, 0))
require.Equal(t, []string{"consumerId1", "consumerId2", "consumerId3"}, providerKeeper.GetInitializedConsumersReadyToLaunch(ctx))
}
16 changes: 16 additions & 0 deletions x/ccv/provider/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,22 @@ func (k Keeper) GetPendingConsumerAdditionProp(ctx sdk.Context, spawnTime time.T
// See: https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/methods.md#ccv-pcf-bblock-init1
// Spec tag:[CCV-PCF-BBLOCK-INIT.1]
func (k Keeper) BeginBlockInit(ctx sdk.Context) {
// TODO (PERMISSIONLESS)
//consumerIds := k.GetInitializedConsumersReadyToLaunch(ctx)
//
//for _, consumerId := range consumerIds {
// record, found := k.GetConsumerIdToInitializationRecord(ctx, consumerId)
// if !found {
// // something is off
// }
// // set the chain ...(have it all in one method)
// // call the method LaunchConsumer
// // cachedCtx, ...
// // k.LaunchConsumerChain(cachedTx, ...)
// // k.SetPhase(Launched)
//
// // CHANGE THEIR PHASE ...
//}
propsToExecute := k.GetConsumerAdditionPropsToExecute(ctx)

for i, prop := range propsToExecute {
Expand Down
5 changes: 5 additions & 0 deletions x/ccv/provider/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,11 @@ func ConsumerIdToRegistrationRecordKey(consumerId string) []byte {
return ConsumerIdWithLenKey(mustGetKeyPrefix(ConsumerIdToRegistrationRecordKeyName), consumerId)
}

// ConsumerIdToInitializationRecordKeyNameKeyPrefix returns the key prefix for storing consumer initialization records
func ConsumerIdToInitializationRecordKeyNameKeyPrefix() []byte {
return []byte{mustGetKeyPrefix(ConsumerIdToInitializationRecordKeyName)}
}

// ConsumerIdToInitializationRecordKey returns the key used to store the initialization record that corresponds to this consumer id
func ConsumerIdToInitializationRecordKey(consumerId string) []byte {
return ConsumerIdWithLenKey(mustGetKeyPrefix(ConsumerIdToInitializationRecordKeyName), consumerId)
Expand Down

0 comments on commit 7dcb03c

Please sign in to comment.