Skip to content

Commit

Permalink
feat: use proposal for cross chain parameter governance (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgao001 authored Feb 24, 2023
1 parent 14f91ec commit 7707c68
Show file tree
Hide file tree
Showing 22 changed files with 864 additions and 66 deletions.
2 changes: 2 additions & 0 deletions proto/cosmos/params/v1beta1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ message ParameterChangeProposal {
string title = 1;
string description = 2;
repeated ParamChange changes = 3 [(gogoproto.nullable) = false];
bool cross_chain = 4; // flag for cross chain proposal
repeated string addresses = 5; // used with cross_chain field to specify destination smart contract address(es)
}

// ParamChange defines an individual parameter change, for use in
Expand Down
2 changes: 0 additions & 2 deletions types/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,10 @@ func (c Context) TransientStore(key storetypes.StoreKey) KVStore {
func (c Context) CacheContext() (cc Context, writeCache func()) {
cms := c.MultiStore().CacheMultiStore()
cc = c.WithMultiStore(cms).WithEventManager(NewEventManager())

writeCache = func() {
c.EventManager().EmitEvents(cc.EventManager().Events())
cms.Write()
}

return cc, writeCache
}

Expand Down
14 changes: 10 additions & 4 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"fmt"
"strings"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

Expand All @@ -13,7 +16,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
)

// Transaction flags for the x/distribution module
Expand Down Expand Up @@ -341,12 +344,15 @@ Where proposal.json contains:
return err
}
content := types.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, recpAddr, amount)

msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from)
govAcctAddress := authtypes.NewModuleAddress(govtypes.ModuleName).String()
contentMsg, err := govv1.NewLegacyContent(content, govAcctAddress)
if err != nil {
return err
}
msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{contentMsg}, deposit, from.String(), "")
if err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
Expand Down
2 changes: 1 addition & 1 deletion x/feegrant/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
}
spendLimit := sdk.NewCoin("stake", sdk.NewInt(1000))

allowMsgs := strings.Join([]string{sdk.MsgTypeURL(&govv1beta1.MsgSubmitProposal{}), sdk.MsgTypeURL(&govv1.MsgVoteWeighted{})}, ",")
allowMsgs := strings.Join([]string{sdk.MsgTypeURL(&govv1.MsgSubmitProposal{}), sdk.MsgTypeURL(&govv1.MsgVoteWeighted{})}, ",")

testCases := []struct {
name string
Expand Down
15 changes: 10 additions & 5 deletions x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {

if passes {
var (
idx int
msg sdk.Msg
idx int
events sdk.Events
msg sdk.Msg
)

// attempt to execute all messages within the passed proposal
Expand All @@ -70,10 +71,13 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
if err == nil {
for idx, msg = range messages {
handler := keeper.Router().Handler(msg)
_, err = handler(cacheCtx, msg)
var res *sdk.Result
res, err = handler(cacheCtx, msg)
if err != nil {
break
}

events = append(events, res.GetEvents()...)
}
}

Expand All @@ -83,9 +87,10 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
proposal.Status = v1.StatusPassed
tagValue = types.AttributeValueProposalPassed
logMsg = "passed"

// write state to the underlying multi-store
writeCache()

// propagate the msg events to the current context
ctx.EventManager().EmitEvents(events)
} else {
proposal.Status = v1.StatusFailed
tagValue = types.AttributeValueProposalFailed
Expand Down
10 changes: 8 additions & 2 deletions x/gov/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"strconv"
"strings"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -186,11 +188,15 @@ $ %s tx gov submit-legacy-proposal --title="Test Proposal" --description="My awe
return fmt.Errorf("failed to create proposal content: unknown proposal type %s", proposal.Type)
}

msg, err := v1beta1.NewMsgSubmitProposal(content, amount, clientCtx.GetFromAddress())
govAcctAddress := authtypes.NewModuleAddress(types.ModuleName).String()
contentMsg, err := v1.NewLegacyContent(content, govAcctAddress)
if err != nil {
return err
}
msg, err := v1.NewMsgSubmitProposal([]sdk.Msg{contentMsg}, amount, clientCtx.GetFromAddress().String(), "")
if err != nil {
return fmt.Errorf("invalid message: %w", err)
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
Expand Down
1 change: 0 additions & 1 deletion x/gov/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, messages []sdk.Msg, metadat
sdk.NewAttribute(types.AttributeKeyProposalMessages, msgsStr),
),
)

return proposal, nil
}

Expand Down
6 changes: 1 addition & 5 deletions x/gov/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
msgServer := keeper.NewMsgServerImpl(am.keeper)
v1beta1.RegisterMsgServer(cfg.MsgServer(), keeper.NewLegacyMsgServerImpl(am.accountKeeper.GetModuleAddress(types.ModuleName).String(), msgServer))
v1.RegisterMsgServer(cfg.MsgServer(), msgServer)

legacyQueryServer := keeper.NewLegacyQueryServer(am.keeper)
v1beta1.RegisterQueryServer(cfg.QueryServer(), legacyQueryServer)
v1.RegisterMsgServer(cfg.MsgServer(), msgServer)
v1.RegisterQueryServer(cfg.QueryServer(), am.keeper)

m := keeper.NewMigrator(am.keeper)
err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
if err != nil {
Expand Down
1 change: 0 additions & 1 deletion x/gov/types/v1/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func NewLegacyContent(content v1beta1.Content, authority string) (*MsgExecLegacy
if !ok {
return nil, fmt.Errorf("%T does not implement proto.Message", content)
}

any, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, err
Expand Down
14 changes: 10 additions & 4 deletions x/params/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import (
"fmt"
"strings"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils"
paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
)
Expand Down Expand Up @@ -75,12 +78,15 @@ Where proposal.json contains:
if err != nil {
return err
}

msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from)
govAcctAddress := authtypes.NewModuleAddress(govtypes.ModuleName).String()
contentMsg, err := govv1.NewLegacyContent(content, govAcctAddress)
if err != nil {
return err
}
msg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{contentMsg}, deposit, from.String(), "")
if err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
Expand Down
36 changes: 36 additions & 0 deletions x/params/client/cli/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,39 @@ func TestParseProposal(t *testing.T) {
},
}, proposal.Changes)
}

func TestParseCrossChainProposal(t *testing.T) {
cdc := codec.NewLegacyAmino()
okJSON := testutil.WriteToNewTempFile(t, `
{
"title": "BSC smart contract upgrade",
"description": "BSC smart contract upgrade",
"changes": [
{
"subspace": "BSC",
"key": "upgrade",
"value": "0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf"
}
],
"deposit": "1000000000000BNB",
"cross_chain": true,
"addresses": ["0x6c615C766EE6b7e69275b0D070eF50acc93ab880"]
}
`)
proposal, err := utils.ParseParamChangeProposalJSON(cdc, okJSON.Name())
require.NoError(t, err)

require.Equal(t, "BSC smart contract upgrade", proposal.Title)
require.Equal(t, "BSC smart contract upgrade", proposal.Description)
require.Equal(t, "1000000000000BNB", proposal.Deposit)

require.Equal(t, true, proposal.CrossChain)
require.Equal(t, "0x6c615C766EE6b7e69275b0D070eF50acc93ab880", proposal.Addresses[0])
require.Equal(t, utils.ParamChangesJSON{
{
Subspace: "BSC",
Key: "upgrade",
Value: []byte{0x22, 0x30, 0x78, 0x38, 0x66, 0x38, 0x36, 0x34, 0x30, 0x33, 0x41, 0x34, 0x44, 0x45, 0x30, 0x42, 0x42, 0x35, 0x37, 0x39, 0x31, 0x66, 0x61, 0x34, 0x36, 0x42, 0x38, 0x65, 0x37, 0x39, 0x35, 0x43, 0x35, 0x34, 0x37, 0x39, 0x34, 0x32, 0x66, 0x45, 0x34, 0x43, 0x66, 0x22},
},
}, proposal.Changes)
}
3 changes: 3 additions & 0 deletions x/params/client/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type (
// ParamChangesJSON defines a slice of ParamChangeJSON objects which can be
// converted to a slice of ParamChange objects.
ParamChangesJSON []ParamChangeJSON
Addresses []string

// ParamChangeJSON defines a parameter change used in JSON input. This
// allows values to be specified in raw JSON instead of being string encoded.
Expand All @@ -28,6 +29,8 @@ type (
Description string `json:"description" yaml:"description"`
Changes ParamChangesJSON `json:"changes" yaml:"changes"`
Deposit string `json:"deposit" yaml:"deposit"`
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
Addresses Addresses `json:"addresses" yaml:"addresses"`
}
)

Expand Down
16 changes: 11 additions & 5 deletions x/params/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import (

// Keeper of the global paramstore
type Keeper struct {
cdc codec.BinaryCodec
legacyAmino *codec.LegacyAmino
key storetypes.StoreKey
tkey storetypes.StoreKey
spaces map[string]*types.Subspace
cdc codec.BinaryCodec
legacyAmino *codec.LegacyAmino
key storetypes.StoreKey
tkey storetypes.StoreKey
spaces map[string]*types.Subspace
crossChainKeeper *types.CrossChainKeeper
}

// NewKeeper constructs a params keeper
Expand All @@ -29,6 +30,11 @@ func NewKeeper(cdc codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey
}
}

// SetCrossChainKeeper sets the crosschainkeeper after its initialization
func (k *Keeper) SetCrossChainKeeper(crossChainKeeper types.CrossChainKeeper) {
k.crossChainKeeper = &crossChainKeeper
}

// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+proposal.ModuleName)
Expand Down
84 changes: 84 additions & 0 deletions x/params/keeper/sync_params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package keeper

import (
"encoding/hex"
"math/big"

"github.com/cosmos/cosmos-sdk/bsc/rlp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
types "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
)

func (k Keeper) RegisterCrossChainSyncParamsApp() error {
return (*k.crossChainKeeper).RegisterChannel(types.SyncParamsChannel, types.SyncParamsChannelID, k)
}

func (k Keeper) SyncParams(ctx sdk.Context, p *types.ParameterChangeProposal) error {
// this validates content and size of changes is not empty
if err := p.ValidateBasic(); err != nil {
return err
}

values := make([]byte, 0)
addresses := make([]byte, 0)

for i, c := range p.Changes {
var value []byte
var err error
if c.Key == types.KeyUpgrade {
value, err = sdk.AccAddressFromHexUnsafe(c.Value)
if err != nil {
return sdkerrors.Wrapf(types.ErrAddressNotValid, "smart contract address is not valid %s", c.Value)
}
} else {
value, err = hex.DecodeString(c.Value)
if err != nil {
return sdkerrors.Wrapf(types.ErrInvalidValue, "value is not valid %s", c.Value)
}
}
values = append(values, value...)
addr, err := sdk.AccAddressFromHexUnsafe(p.Addresses[i])
if err != nil {
return sdkerrors.Wrapf(types.ErrAddressNotValid, "smart contract address is not valid %s", p.Addresses[i])
}
addresses = append(addresses, addr.Bytes()...)
}

pack := types.SyncParamsPackage{
Key: p.Changes[0].Key,
Value: values,
Target: addresses,
}

encodedPackage, err := rlp.EncodeToBytes(pack)
if err != nil {
return sdkerrors.Wrapf(types.ErrInvalidUpgradeProposal, "encode sync params package error")
}
_, err = (*k.crossChainKeeper).CreateRawIBCPackageWithFee(
ctx,
types.SyncParamsChannelID,
sdk.SynCrossChainPackageType,
encodedPackage,
big.NewInt(0),
big.NewInt(0),
)
return err
}

// Need these in order to register paramsKeeper to be a CrosschainApp so that it can register channel(3)

func (k Keeper) ExecuteSynPackage(ctx sdk.Context, appCtx *sdk.CrossChainAppContext, payload []byte) sdk.ExecuteResult {
k.Logger(ctx).Error("received sync params sync package", "payload", hex.EncodeToString(payload))
return sdk.ExecuteResult{}
}

func (k Keeper) ExecuteAckPackage(ctx sdk.Context, header *sdk.CrossChainAppContext, payload []byte) sdk.ExecuteResult {
k.Logger(ctx).Error("received sync params in ack package", "payload", hex.EncodeToString(payload))
return sdk.ExecuteResult{}
}

func (k Keeper) ExecuteFailAckPackage(ctx sdk.Context, header *sdk.CrossChainAppContext, payload []byte) sdk.ExecuteResult {
k.Logger(ctx).Error("received sync params fail ack package", "payload", hex.EncodeToString(payload))
return sdk.ExecuteResult{}
}
6 changes: 6 additions & 0 deletions x/params/proposal_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ func NewParamChangeProposalHandler(k keeper.Keeper) govtypes.Handler {
}

func handleParameterChangeProposal(ctx sdk.Context, k keeper.Keeper, p *proposal.ParameterChangeProposal) error {
// for govv1.MsgExecLegacyContent, validation is applied by writing to cache Subspace store, since gnfd does not hold
// the subspace for crosschain parameters. the validation is skipped.
if p.CrossChain {
return k.SyncParams(ctx, p)
}

for _, c := range p.Changes {
ss, ok := k.GetSubspace(c.Subspace)
if !ok {
Expand Down
Loading

0 comments on commit 7707c68

Please sign in to comment.