Skip to content

Commit

Permalink
Merge branch 'feat/permissionless' into sainoe/consu-valset-query
Browse files Browse the repository at this point in the history
  • Loading branch information
sainoe committed Aug 27, 2024
2 parents fca239b + 19be098 commit cc4f6b9
Show file tree
Hide file tree
Showing 16 changed files with 1,046 additions and 433 deletions.
2 changes: 1 addition & 1 deletion testutil/ibc_testing/generic_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp](
providerKeeper.SetConsumerInitializationParameters(providerChain.GetContext(), consumerId, initializationParameters)
providerKeeper.SetConsumerPowerShapingParameters(providerChain.GetContext(), consumerId, powerShapingParameters)
providerKeeper.SetConsumerPhase(providerChain.GetContext(), consumerId, keeper.Initialized)
providerKeeper.AppendSpawnTimeForConsumerToBeLaunched(providerChain.GetContext(), consumerId, coordinator.CurrentTime)
providerKeeper.AppendConsumerToBeLaunchedOnSpawnTime(providerChain.GetContext(), consumerId, coordinator.CurrentTime)

// opt-in all validators
lastVals, err := providerApp.GetProviderKeeper().GetLastBondedValidators(providerChain.GetContext())
Expand Down
2 changes: 1 addition & 1 deletion testutil/keeper/unit_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ func GetTestConsumerMetadata() providertypes.ConsumerMetadata {

func GetTestInitializationParameters() providertypes.ConsumerInitializationParameters {
initialHeight := clienttypes.NewHeight(4, 5)
spawnTime := time.Now()
spawnTime := time.Now().UTC()
ccvTimeoutPeriod := types.DefaultCCVTimeoutPeriod
transferTimeoutPeriod := types.DefaultTransferTimeoutPeriod
unbondingPeriod := types.DefaultConsumerUnbondingPeriod
Expand Down
22 changes: 11 additions & 11 deletions x/ccv/provider/keeper/distribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,33 +74,33 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) {
return
}

// Iterate over all registered consumer chains
for _, consumerChainID := range k.GetAllRegisteredConsumerIds(ctx) {
// Iterate over all launched consumer chains
for _, consumerId := range k.GetAllRegisteredConsumerIds(ctx) {

// note that it's possible that no rewards are collected even though the
// reward pool isn't empty. This can happen if the reward pool holds some tokens
// of non-whitelisted denominations.
alloc := k.GetConsumerRewardsAllocation(ctx, consumerChainID)
alloc := k.GetConsumerRewardsAllocation(ctx, consumerId)
if alloc.Rewards.IsZero() {
continue
}

// temporary workaround to keep CanWithdrawInvariant happy
// general discussions here: https://github.com/cosmos/cosmos-sdk/issues/2906#issuecomment-441867634
if k.ComputeConsumerTotalVotingPower(ctx, consumerChainID) == 0 {
if k.ComputeConsumerTotalVotingPower(ctx, consumerId) == 0 {
rewardsToSend, rewardsChange := alloc.Rewards.TruncateDecimal()
err := k.distributionKeeper.FundCommunityPool(context.Context(ctx), rewardsToSend, k.accountKeeper.GetModuleAccount(ctx, types.ConsumerRewardsPool).GetAddress())
if err != nil {
k.Logger(ctx).Error(
"fail to allocate rewards from consumer chain %s to community pool: %s",
consumerChainID,
consumerId,
err,
)
}

// set the consumer allocation to the remaining reward decimals
alloc.Rewards = rewardsChange
k.SetConsumerRewardsAllocation(ctx, consumerChainID, alloc)
k.SetConsumerRewardsAllocation(ctx, consumerId, alloc)

return
}
Expand All @@ -112,7 +112,7 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) {
if err != nil {
k.Logger(ctx).Error(
"cannot get community tax while allocating rewards from consumer chain %s: %s",
consumerChainID,
consumerId,
err,
)
continue
Expand All @@ -132,7 +132,7 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) {
if err != nil {
k.Logger(ctx).Error(
"cannot send rewards to distribution module account %s: %s",
consumerChainID,
consumerId,
err,
)
continue
Expand All @@ -141,7 +141,7 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) {
// allocate tokens to consumer validators
k.AllocateTokensToConsumerValidators(
ctx,
consumerChainID,
consumerId,
sdk.NewDecCoinsFromCoins(validatorsRewardsTrunc...),
)

Expand All @@ -151,15 +151,15 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) {
if err != nil {
k.Logger(ctx).Error(
"fail to allocate rewards from consumer chain %s to community pool: %s",
consumerChainID,
consumerId,
err,
)
continue
}

// set consumer allocations to the remaining rewards decimals
alloc.Rewards = validatorsRewardsChange.Add(remainingChanges...)
k.SetConsumerRewardsAllocation(ctx, consumerChainID, alloc)
k.SetConsumerRewardsAllocation(ctx, consumerId, alloc)
}
}

Expand Down
46 changes: 21 additions & 25 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get last validators: %s", err))
}
minPower := int64(0)
if topN := k.GetTopN(ctx, consumerId); topN > 0 {
// in a Top-N chain, we automatically opt in all validators that belong to the top N
// of the active validators
Expand All @@ -367,19 +368,14 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get active validators: %s", err))
}

minPower, err := k.ComputeMinPowerInTopN(ctx, activeValidators, topN)
minPower, err = k.ComputeMinPowerInTopN(ctx, activeValidators, topN)
if err != nil {
// we panic, since the only way to proceed would be to opt in all validators, which is not the intended behavior
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to compute min power to opt in for chain %s: %s", consumerId, err))
}

// set the minimal power of validators in the top N in the store
k.SetMinimumPowerInTopN(ctx, consumerId, minPower)

k.OptInTopNValidators(ctx, consumerId, activeValidators, minPower)
}

consumerValSet = k.ComputeNextValidators(ctx, consumerId, bondedValidators)
consumerValSet = k.ComputeNextValidators(ctx, consumerId, bondedValidators, minPower)

// sort the address of the validators by ascending lexical order as they were persisted to the store
sort.Slice(consumerValSet, func(i, j int) bool {
Expand Down Expand Up @@ -483,29 +479,29 @@ func (k Keeper) hasToValidate(
if err != nil {
return false, nil
}

minPowerToOptIn := int64(0)
// If the consumer is TopN compute the minimum power
if topN := k.GetTopN(ctx, consumerId); topN > 0 {
// in a Top-N chain, we automatically opt in all validators that belong to the top N
minPower, found := k.GetMinimumPowerInTopN(ctx, consumerId)
if found {
k.OptInTopNValidators(ctx, consumerId, activeValidators, minPower)
} else {
k.Logger(ctx).Error("did not find min power in top N for chain", "chain", consumerId)
// compute the minimum power to opt-in since the one in the state is stale
// Note that the effective min power will be computed at the end of the epoch
minPowerToOptIn, err = k.ComputeMinPowerInTopN(ctx, activeValidators, topN)
if err != nil {
return false, err
}
}

// if the validator is opted in and belongs to the validators of the next epoch, then if nothing changes
// if the validator belongs to the validators of the next epoch, then if nothing changes
// the validator would have to validate in the next epoch
if k.IsOptedIn(ctx, consumerId, provAddr) {
lastVals, err := k.GetLastBondedValidators(ctx)
if err != nil {
return false, err
}
nextValidators := k.ComputeNextValidators(ctx, consumerId, lastVals)
for _, v := range nextValidators {
consAddr := sdk.ConsAddress(v.ProviderConsAddr)
if provAddr.ToSdkConsAddr().Equals(consAddr) {
return true, nil
}
lastVals, err := k.GetLastBondedValidators(ctx)
if err != nil {
return false, err
}
nextValidators := k.ComputeNextValidators(ctx, consumerId, lastVals, minPowerToOptIn)
for _, v := range nextValidators {
consAddr := sdk.ConsAddress(v.ProviderConsAddr)
if provAddr.ToSdkConsAddr().Equals(consAddr) {
return true, nil
}
}

Expand Down
47 changes: 11 additions & 36 deletions x/ccv/provider/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,44 +115,19 @@ func (h Hooks) AfterProposalSubmission(goCtx context.Context, proposalId uint64)
return fmt.Errorf("cannot retrieve proposal with id: %d", proposalId)
}

hasUpdateConsumerMsg := false
for _, msg := range p.GetMessages() {
sdkMsg, isMsgUpdateConsumer := msg.GetCachedValue().(*providertypes.MsgUpdateConsumer)
if isMsgUpdateConsumer {
// A `MsgUpdateConsumer` can only succeed if the owner of the consumer chain is the gov module.
// If that's not the case, we immediately fail the proposal.
// Note that someone could potentially change the owner of a chain to be that of the gov module
// while a proposal is active and before the proposal is executed. Even then, we still do not allow
// `MsgUpdateConsumer` proposals if the owner of the chain is not the gov module to avoid someone forgetting
// to change the owner address while the proposal is active.
ownerAddress, err := h.k.GetConsumerOwnerAddress(ctx, sdkMsg.ConsumerId)
if err != nil {
return fmt.Errorf("cannot find owner address for consumer with consumer id (%s): %s", sdkMsg.ConsumerId, err.Error())
} else if ownerAddress != h.k.GetAuthority() {
return fmt.Errorf("owner address (%s) is not the gov module (%s)", ownerAddress, h.k.GetAuthority())
}

if hasUpdateConsumerMsg {
return fmt.Errorf("proposal can contain at most one `MsgUpdateConsumer` message")
}
hasUpdateConsumerMsg = true
h.k.SetProposalIdToConsumerId(ctx, proposalId, sdkMsg.ConsumerId)
}
err = DoesNotHaveDeprecatedMessage(&p)
if err != nil {
return err
}

// if the proposal contains a deprecated message, cancel the proposal
_, isMsgConsumerAddition := msg.GetCachedValue().(*providertypes.MsgConsumerAddition)
if isMsgConsumerAddition {
return fmt.Errorf("proposal cannot contain deprecated `MsgConsumerAddition`; use `MsgCreateConsumer` instead")
}
msgUpdateConsumer, err := h.k.HasAtMostOnceCorrectMsgUpdateConsumer(ctx, &p)
if err != nil {
return err
}

_, isMsgConsumerModification := msg.GetCachedValue().(*providertypes.MsgConsumerModification)
if isMsgConsumerModification {
return fmt.Errorf("proposal cannot contain deprecated `MsgConsumerModification`; use `MsgUpdateConsumer` instead")
}
_, isMsgConsumerRemoval := msg.GetCachedValue().(*providertypes.MsgConsumerRemoval)
if isMsgConsumerRemoval {
return fmt.Errorf("proposal cannot contain deprecated `MsgConsumerRemoval`; use `MsgRemoveConsumer` instead")
}
if msgUpdateConsumer != nil {
// a correctly set `MsgUpdateConsumer` was found
h.k.SetProposalIdToConsumerId(ctx, proposalId, msgUpdateConsumer.ConsumerId)
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion x/ccv/provider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ func (k Keeper) GetAllActiveConsumerIds(ctx sdk.Context) []string {
}

consumerIds := []string{}
for i := uint64(0); i <= latestConsumerId; i++ {
for i := uint64(0); i < latestConsumerId; i++ {
consumerId := fmt.Sprintf("%d", i)
phase, foundPhase := k.GetConsumerPhase(ctx, consumerId)
if !foundPhase || (phase != Registered && phase != Initialized && phase != Launched) {
Expand Down
Loading

0 comments on commit cc4f6b9

Please sign in to comment.