Skip to content

Commit

Permalink
feat: set metadata for launched consumer chains (#3308)
Browse files Browse the repository at this point in the history
* bump ICS

* deal with TODOs

* set metadata for launched consumer chains

* set description

* fix linter

* bump ICS

* bump ICS

* TopN chains need both create and update
  • Loading branch information
mpoke authored Sep 4, 2024
1 parent b799d18 commit 22abde1
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 45 deletions.
207 changes: 165 additions & 42 deletions app/upgrades/v20/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ func CreateUpgradeHandler(
return vm, errorsmod.Wrapf(err, "migrating ICS legacy proposals during migration")
}

ctx.Logger().Info("Setting ICS consumers metadata...")
err = SetICSConsumerMetadata(ctx, keepers.ProviderKeeper)
if err != nil {
return vm, errorsmod.Wrapf(err, "setting ICS consumers metadata during migration")
}

ctx.Logger().Info("Upgrade v20 complete")
return vm, nil
}
Expand Down Expand Up @@ -137,13 +143,21 @@ func InitializeLastProviderConsensusValidatorSet(

// MigrateICSLegacyProposals migrates ICS legacy proposals
func MigrateICSLegacyProposals(ctx sdk.Context, msgServer providertypes.MsgServer, providerKeeper providerkeeper.Keeper, govKeeper govkeeper.Keeper) error {
return govKeeper.Proposals.Walk(ctx, nil, func(key uint64, proposal govtypes.Proposal) (stop bool, err error) {
err = MigrateProposal(ctx, msgServer, providerKeeper, govKeeper, proposal)
proposals := []govtypes.Proposal{}
err := govKeeper.Proposals.Walk(ctx, nil, func(key uint64, proposal govtypes.Proposal) (stop bool, err error) {
proposals = append(proposals, proposal)
return false, nil // go through the entire collection
})
if err != nil {
return errorsmod.Wrapf(err, "iterating through proposals")
}
for _, proposal := range proposals {
err := MigrateProposal(ctx, msgServer, providerKeeper, govKeeper, proposal)
if err != nil {
return true, errorsmod.Wrapf(err, "migrating proposal %d", key)
return errorsmod.Wrapf(err, "migrating proposal %d", proposal.Id)
}
return false, nil
})
}
return nil
}

// MigrateProposal migrates an ICS proposal
Expand Down Expand Up @@ -253,27 +267,57 @@ func MigrateConsumerAdditionProposal(
return nil
}
}

// This proposal would have been handled in a future block.
// If the proposal is invalid, just ignore it.
// Otherwise, call CreateConsumer, which will schedule the consumer
// chain to be launched at msg.SpawnTime.

// create a new consumer chain with all the parameters
metadata, err := metadataFromCAP(msg)
if err != nil {
return err
}
metadata := metadataFromCAP(msg)
initParams, err := initParamsFromCAP(msg)
if err != nil {
return err
// invalid init params -- ignore proposal
ctx.Logger().Error(
fmt.Sprintf(
"Proposal with ID(%d) was skipped as the init params are invalid, chainID(%s), spawnTime(%s): %s",
proposal.Id, msg.ChainId, msg.SpawnTime.String(), err.Error(),
),
)
return nil
}
powerShapingParams, err := powerShapingParamsFromCAP(msg)
if err != nil {
return err
// invalid power shaping params -- ignore proposal
ctx.Logger().Error(
fmt.Sprintf(
"Proposal with ID(%d) was skipped as the power shaping params are invalid, chainID(%s), spawnTime(%s): %s",
proposal.Id, msg.ChainId, msg.SpawnTime.String(), err.Error(),
),
)
return nil
}
// first, create an Opt-In consumer chain
msgCreateConsumer := providertypes.MsgCreateConsumer{
Signer: govKeeper.GetAuthority(),
ChainId: msg.ChainId,
Metadata: metadata,
InitializationParameters: nil,
PowerShapingParameters: nil,
}
resp, err := msgServer.CreateConsumer(ctx, &msgCreateConsumer)
if err != nil {
return err
}
// second, update the consumer chain to be TopN
msgUpdateConsumer := providertypes.MsgUpdateConsumer{
Signer: govKeeper.GetAuthority(),
ConsumerId: resp.ConsumerId,
Metadata: nil,
InitializationParameters: &initParams,
PowerShapingParameters: &powerShapingParams,
}
resp, err := msgServer.CreateConsumer(ctx, &msgCreateConsumer)
_, err = msgServer.UpdateConsumer(ctx, &msgUpdateConsumer)
if err != nil {
return err
}
Expand All @@ -284,13 +328,42 @@ func MigrateConsumerAdditionProposal(
),
)
} else {
// ConsumerAdditionProposal that was submitted, but not yet passed
// ConsumerAdditionProposal that was submitted, but not yet passed.
// If the proposal is invalid, remove it.
// Otherwise, create a new consumer chain (MsgCreateConsumer), and
// replace the proposal's content with a MsgUpdateConsumer

// first, create a new consumer chain to get a consumer ID
metadata, err := metadataFromCAP(msg)
metadata := metadataFromCAP(msg)
initParams, err := initParamsFromCAP(msg)
if err != nil {
return err
// invalid init params -- delete proposal
if err := govKeeper.DeleteProposal(ctx, proposal.Id); err != nil {
return err
}
ctx.Logger().Error(
fmt.Sprintf(
"Proposal with ID(%d) was deleted as the init params are invalid, chainID(%s), spawnTime(%s): %s",
proposal.Id, msg.ChainId, msg.SpawnTime.String(), err.Error(),
),
)
return nil
}
powerShapingParams, err := powerShapingParamsFromCAP(msg)
if err != nil {
// invalid power shaping params -- delete proposal
if err := govKeeper.DeleteProposal(ctx, proposal.Id); err != nil {
return err
}
ctx.Logger().Error(
fmt.Sprintf(
"Proposal with ID(%d) was deleted as the power shaping params are invalid, chainID(%s), spawnTime(%s): %s",
proposal.Id, msg.ChainId, msg.SpawnTime.String(), err.Error(),
),
)
return nil
}

// first, create a new consumer chain to get a consumer ID
msgCreateConsumer := providertypes.MsgCreateConsumer{
Signer: govKeeper.GetAuthority(),
ChainId: msg.ChainId,
Expand All @@ -310,14 +383,6 @@ func MigrateConsumerAdditionProposal(
)

// second, replace the message in the proposal with a MsgUpdateConsumer
initParams, err := initParamsFromCAP(msg)
if err != nil {
return err
}
powerShapingParams, err := powerShapingParamsFromCAP(msg)
if err != nil {
return err
}
msgUpdateConsumer := providertypes.MsgUpdateConsumer{
Signer: govKeeper.GetAuthority(),
ConsumerId: resp.ConsumerId,
Expand All @@ -330,7 +395,6 @@ func MigrateConsumerAdditionProposal(
return err
}
proposal.Messages[0] = anyMsg
// TODO: check if we can call SetProposal within govKeeper.Proposals.Walk
if err := govKeeper.SetProposal(ctx, proposal); err != nil {
return err
}
Expand All @@ -345,19 +409,18 @@ func MigrateConsumerAdditionProposal(
}

// metadataFromCAP returns ConsumerMetadata from a ConsumerAdditionProposal
func metadataFromCAP(
prop *providertypes.ConsumerAdditionProposal,
) (providertypes.ConsumerMetadata, error) {
func metadataFromCAP(prop *providertypes.ConsumerAdditionProposal) providertypes.ConsumerMetadata {
metadata := providertypes.ConsumerMetadata{
Name: prop.Title,
Description: prop.Description,
Metadata: "TBA",
}
err := providertypes.ValidateConsumerMetadata(metadata)
// TODO: avoid returning an error here;
// for this, we need to make sure the validation works always
// (e.g., truncate the fields)
return metadata, err
if err != nil {
metadata.Name = providertypes.TruncateString(metadata.Name, providertypes.MaxNameLength)
metadata.Description = providertypes.TruncateString(metadata.Description, providertypes.MaxDescriptionLength)
}
return metadata
}

// initParamsFromCAP returns ConsumerInitializationParameters from
Expand All @@ -379,8 +442,6 @@ func initParamsFromCAP(
DistributionTransmissionChannel: prop.DistributionTransmissionChannel,
}
err := providertypes.ValidateInitializationParameters(initParams)
// TODO: avoid returning an error here;
// for this, we need to make sure the validation works always
return initParams, err
}

Expand All @@ -398,8 +459,6 @@ func powerShapingParamsFromCAP(
AllowInactiveVals: prop.AllowInactiveVals,
}
err := providertypes.ValidatePowerShapingParameters(powerShapingParams)
// TODO: avoid returning an error here;
// for this, we need to make sure the validation works always
return powerShapingParams, err
}

Expand Down Expand Up @@ -482,7 +541,6 @@ func MigrateConsumerRemovalProposal(
return err
}
proposal.Messages[0] = anyMsg
// TODO: check if we can call SetProposal within govKeeper.Proposals.Walk
if err := govKeeper.SetProposal(ctx, proposal); err != nil {
return err
}
Expand Down Expand Up @@ -546,7 +604,17 @@ func MigrateConsumerModificationProposal(
// replace the message in the proposal with a MsgUpdateConsumer
powerShapingParams, err := powerShapingParamsFromCMP(msg)
if err != nil {
return err
// invalid power shaping params -- delete proposal
if err := govKeeper.DeleteProposal(ctx, proposal.Id); err != nil {
return err
}
ctx.Logger().Error(
fmt.Sprintf(
"Proposal with ID(%d) was deleted as the power shaping params are invalid, consumerID(%s), chainID(%s): %s",
proposal.Id, modifyConsumerID, msg.ChainId, err.Error(),
),
)
return nil
}
msgUpdateConsumer := providertypes.MsgUpdateConsumer{
Signer: govKeeper.GetAuthority(),
Expand All @@ -560,7 +628,6 @@ func MigrateConsumerModificationProposal(
return err
}
proposal.Messages[0] = anyMsg
// TODO: check if we can call SetProposal within govKeeper.Proposals.Walk
if err := govKeeper.SetProposal(ctx, proposal); err != nil {
return err
}
Expand All @@ -587,8 +654,6 @@ func powerShapingParamsFromCMP(
AllowInactiveVals: prop.AllowInactiveVals,
}
err := providertypes.ValidatePowerShapingParameters(powerShapingParams)
// TODO: avoid returning an error here;
// for this, we need to make sure the validation works always
return powerShapingParams, err
}

Expand Down Expand Up @@ -635,7 +700,6 @@ func MigrateChangeRewardDenomsProposal(
return err
}
proposal.Messages[0] = anyMsg
// TODO: check if we can call SetProposal within govKeeper.Proposals.Walk
if err := govKeeper.SetProposal(ctx, proposal); err != nil {
return err
}
Expand All @@ -645,3 +709,62 @@ func MigrateChangeRewardDenomsProposal(
}
return nil
}

// SetICSConsumerMetadata sets the metadata for launched consumer chains
func SetICSConsumerMetadata(ctx sdk.Context, providerKeeper providerkeeper.Keeper) error {
for _, consumerID := range providerKeeper.GetAllActiveConsumerIds(ctx) {
phase := providerKeeper.GetConsumerPhase(ctx, consumerID)
if phase != providertypes.ConsumerPhase_CONSUMER_PHASE_LAUNCHED {
continue
}
chainID, err := providerKeeper.GetConsumerChainId(ctx, consumerID)
if err != nil {
ctx.Logger().Error(
fmt.Sprintf("cannot get chain ID for consumer chain, consumerID(%s)", consumerID),
)
continue
}

if chainID == "stride-1" {
metadata := providertypes.ConsumerMetadata{
Name: "Stride",
Description: "The Stride blockchain has a single purpose: to provide the best liquid staking service for chains in the Cosmos ecosystem. " +
"Stride protocol currently provides liquid staking for seven Cosmos chains, and has over 80%% of Cosmos ecosystem liquid staking market share.\n" +
"With Stride's stTokens integrated into major DeFi apps across the Cosmos, a rapidly growing TVL, and more IBC traffic than almost any other Cosmos chain - the Stride blockchain has clearly achieved product market fit.\n" +
"Stride's top priority is security; it always has been and always will be. " +
"Like the Cosmos Hub, Stride is a highly secure minimalist blockchain, with no smart contracts and no other apps beside the core liquid staking protocol. " +
"The Stride codebase has been fully audited by numerous security firms, and receives continuous auditing from Informal Systems. " +
"And the Stride blockchain is protected by IBC rate-limiting.",
Metadata: "https://github.com/Stride-Labs/stride",
}
err = providerKeeper.SetConsumerMetadata(ctx, consumerID, metadata)
if err != nil {
ctx.Logger().Error(
fmt.Sprintf("cannot set consumer metadata, consumerID(%s), chainID(%s): %s", consumerID, chainID, err.Error()),
)
continue
}
} else if chainID == "neutron-1" {
metadata := providertypes.ConsumerMetadata{
Name: "Neutron",
Description: "Neutron is the only blockchain network specifically designed to support Integrated Applications. " +
"By granting contracts the power of an appchain, Neutron minimises development overhead, facilitates improved mechanism design, lowers risk and enhances the scalability of decentralised applications.\n" +
"Unlike typical smart contracts, Integrated Applications have access to components of the blockchain that exist outside of their virtual machine: " +
"begin and end block automation, mempools, transaction fee mechanisms, consensus votes, interchain transactions and queries, and more.\n" +
"Integrated Applications can customise their network's blockspace to provide gasless onboarding to newly acquired users and do away with network selectors to onboard deposits from any connected blockchain in a single click. " +
"They can deploy and manage capital and integrations across multiple chains, maximising network effects and the ubiquity of their denominations.\n" +
"These features allow Integrated Applications to establish stronger moats around their technology and business model, while providing a competitive edge that standard applications lack. " +
"This makes them inherently more attractive and competitive, as they operate on an enhanced platform offering higher performance and broader reach compared to traditional applications.",
Metadata: "https://github.com/neutron-org/neutron",
}
err = providerKeeper.SetConsumerMetadata(ctx, consumerID, metadata)
if err != nil {
ctx.Logger().Error(
fmt.Sprintf("cannot set consumer metadata, consumerID(%s), chainID(%s): %s", consumerID, chainID, err.Error()),
)
continue
}
}
}
return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/cosmos/ibc-apps/modules/rate-limiting/v8 v8.0.0
github.com/cosmos/ibc-go/modules/capability v1.0.1
github.com/cosmos/ibc-go/v8 v8.5.0
github.com/cosmos/interchain-security/v5 v5.0.0-20240830143040-6262e42539b0
github.com/cosmos/interchain-security/v5 v5.0.0-20240904071545-7301916eeafa
github.com/google/gofuzz v1.2.0
github.com/gorilla/mux v1.8.1
github.com/ory/dockertest/v3 v3.11.0
Expand Down
8 changes: 6 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,12 @@ github.com/cosmos/ibc-go/v8 v8.5.0 h1:OjaSXz480JT8ZuMrASxGgS7XzloZ2NuuJPwZB/fKDg
github.com/cosmos/ibc-go/v8 v8.5.0/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo=
github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU=
github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0=
github.com/cosmos/interchain-security/v5 v5.0.0-20240830143040-6262e42539b0 h1:eUVYAtMBOjZIByoY+TVpGx85tjeLAGJGvxSXx6TxumA=
github.com/cosmos/interchain-security/v5 v5.0.0-20240830143040-6262e42539b0/go.mod h1:y3LdR1GPxF8SMFRb/V38OWGZNwEriJDFlka/hoH1GEk=
github.com/cosmos/interchain-security/v5 v5.0.0-20240903101737-5f1a27cf0307 h1:9wk1rNi8ZWCn7EXuhVGd5EJYZaWiNpzHi6y+NaiSpZ8=
github.com/cosmos/interchain-security/v5 v5.0.0-20240903101737-5f1a27cf0307/go.mod h1:y3LdR1GPxF8SMFRb/V38OWGZNwEriJDFlka/hoH1GEk=
github.com/cosmos/interchain-security/v5 v5.0.0-20240903195423-6b148c74e014 h1:kV9hr0QCuDAhrqzsjO4UsXLPXEFTpEzOc+JgT/dM/Lc=
github.com/cosmos/interchain-security/v5 v5.0.0-20240903195423-6b148c74e014/go.mod h1:y3LdR1GPxF8SMFRb/V38OWGZNwEriJDFlka/hoH1GEk=
github.com/cosmos/interchain-security/v5 v5.0.0-20240904071545-7301916eeafa h1:AXkCUx2/N1kd6RvvptcKQHwOEkrq5MkJKSqi0jqFwbw=
github.com/cosmos/interchain-security/v5 v5.0.0-20240904071545-7301916eeafa/go.mod h1:y3LdR1GPxF8SMFRb/V38OWGZNwEriJDFlka/hoH1GEk=
github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo=
github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA=
github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM=
Expand Down

0 comments on commit 22abde1

Please sign in to comment.