Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add oracle upgrade proposal tx & cli #576

Merged
merged 13 commits into from
Jan 3, 2023
3 changes: 3 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/cosmos/cosmos-sdk/x/authz"
"github.com/medibloc/panacea-core/v2/x/oracle"
oracleclient "github.com/medibloc/panacea-core/v2/x/oracle/client"
oraclekeeper "github.com/medibloc/panacea-core/v2/x/oracle/keeper"
oracletypes "github.com/medibloc/panacea-core/v2/x/oracle/types"

Expand Down Expand Up @@ -162,6 +163,7 @@ func getGovProposalHandlers() []govclient.ProposalHandler {
upgradeclient.ProposalHandler,
upgradeclient.CancelProposalHandler,
// this line is used by starport scaffolding # stargate/app/govProposalHandler
oracleclient.ProposalHandler,
)
govProposalHandlers = append(govProposalHandlers, wasmclient.ProposalHandlers...)

Expand Down Expand Up @@ -440,6 +442,7 @@ func New(
keys[oracletypes.MemStoreKey],
app.GetSubspace(oracletypes.ModuleName),
)
govRouter.AddRoute(oracletypes.RouterKey, oracle.NewOracleProposalHandler(app.oracleKeeper))

app.datadealKeeper = *datadealkeeper.NewKeeper(
appCodec,
Expand Down
9 changes: 9 additions & 0 deletions proto/panacea/oracle/v2/oracle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,12 @@ message OracleRegistration {
string oracle_commission_max_change_rate = 10 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
bytes encrypted_oracle_priv_key = 11;
}

// OracleUpgradeInfo defines the info of oracle upgrade, which includes the target height of upgrade and unique ID of the new version of oracle
message OracleUpgradeInfo {
option (gogoproto.equal) = true;

string unique_id = 1;

int64 height = 2;
}
25 changes: 25 additions & 0 deletions proto/panacea/oracle/v2/proposal.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
syntax = "proto3";
package panacea.oracle.v2;

option go_package = "github.com/medibloc/panacea-core/x/oracle/types";
option (gogoproto.goproto_getters_all) = false;

import "gogoproto/gogo.proto";

// Plan defines upgrade plan information.
message Plan {
option (gogoproto.equal) = true;

string unique_id = 1;

int64 height = 2;
}

// OracleUpgradeProposal defines the information required for a proposal.
message OracleUpgradeProposal {
option (gogoproto.equal) = true;

string title = 1;
string description = 2;
Plan plan = 3 [(gogoproto.nullable) = false];
}
13 changes: 13 additions & 0 deletions proto/panacea/oracle/v2/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ service Query {
option (google.api.http).get = "/panacea/oracle/v2/oracle-registrations/{unique_id}/{oracle_address}";
}

// OracleUpgradeInfo returns OracleUpgradeInfo of oracle module.
rpc OracleUpgradeInfo(QueryOracleUpgradeInfoRequest) returns (QueryOracleUpgradeInfoResponse) {
option (google.api.http).get = "/panacea/oracle/v2alpha2/oracle-upgrade-info";
audtlr24 marked this conversation as resolved.
Show resolved Hide resolved
}

// Params returns params of oracle module.
rpc Params(QueryOracleParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/panacea/oracle/v2/params";
Expand Down Expand Up @@ -82,6 +87,14 @@ message QueryOracleRegistrationResponse {
OracleRegistration oracle_registration = 1;
}

// QueryOracleUpgradeInfoRequest is the request type for the Query/OracleUpgradeInfo RPC method.
message QueryOracleUpgradeInfoRequest {}

// QueryOracleUpgradeInfoRequest is the response type for the Query/OracleUpgradeInfo RPC method.
message QueryOracleUpgradeInfoResponse {
OracleUpgradeInfo oracle_upgrade_info = 1;
}

// QueryOracleParamsRequest is the request type for the Query/OracleParams RPC method.
message QueryOracleParamsRequest {}

Expand Down
1 change: 1 addition & 0 deletions x/oracle/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
cmd.AddCommand(CmdGetOracle())
cmd.AddCommand(CmdGetOracleRegistrations())
cmd.AddCommand(CmdGetOracleRegistration())
cmd.AddCommand(CmdGetOracleUpgradeInfo())
cmd.AddCommand(CmdGetParams())

return cmd
Expand Down
35 changes: 35 additions & 0 deletions x/oracle/client/cli/queryOracleUpgradeInfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
"github.com/spf13/cobra"
)

func CmdGetOracleUpgradeInfo() *cobra.Command {
cmd := &cobra.Command{
Use: "oracle-upgrade-info",
Short: "Query an oracle upgrade information",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.OracleUpgradeInfo(cmd.Context(), &types.QueryOracleUpgradeInfoRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
100 changes: 100 additions & 0 deletions x/oracle/client/cli/txUpgradeOracleProposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
"github.com/spf13/cobra"
)

const (
FlagUpgradeUniqueID = "upgrade-unique-id"
FlagUpgradeHeight = "upgrade-height"
)

func CmdUpgradeOracleProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "oracle-upgrade (--upgrade-unique-id [uniqueID]) (--upgrade-height [height]) [flags]",
inchori marked this conversation as resolved.
Show resolved Hide resolved
Args: cobra.ExactArgs(0),
Short: "Submit an oracle upgrade proposal",
Long: "Submit an oracle upgrade proposal along with an initial deposit.\n + " +
"You must enter the uniqueID of a new version of oracle and target block height for upgrade.",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
from := clientCtx.GetFromAddress()

depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit)
if err != nil {
return err
}

deposit, err := sdk.ParseCoinsNormalized(depositStr)
if err != nil {
return err
}

content, err := makeProposalContent(cmd)
if err != nil {
return err
}

msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from)
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(govcli.FlagTitle, "", "title of proposal")
cmd.Flags().String(govcli.FlagDescription, "", "description of proposal")
cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal")
cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen")
cmd.Flags().String(FlagUpgradeUniqueID, "", "Oracle's uniqueID to be upgraded")

if err := cmd.MarkFlagRequired(FlagUpgradeHeight); err != nil {
panic(err)
}
if err := cmd.MarkFlagRequired(FlagUpgradeUniqueID); err != nil {
panic(err)
}
return cmd
}

func makeProposalContent(cmd *cobra.Command) (govtypes.Content, error) {
title, err := cmd.Flags().GetString(govcli.FlagTitle)
if err != nil {
return nil, err
}

description, err := cmd.Flags().GetString(govcli.FlagDescription)
if err != nil {
return nil, err
}

height, err := cmd.Flags().GetInt64(FlagUpgradeHeight)
if err != nil {
return nil, err
}

uniqueID, err := cmd.Flags().GetString(FlagUpgradeUniqueID)
if err != nil {
return nil, err
}

plan := types.Plan{UniqueId: uniqueID, Height: height}
if err := plan.ValidateBasic(); err != nil {
return nil, err
}
content := types.NewOracleUpgradeProposal(title, description, plan)
return content, nil
}
10 changes: 10 additions & 0 deletions x/oracle/client/proposal_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package client

import (
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
"github.com/medibloc/panacea-core/v2/x/oracle/client/rest"

"github.com/medibloc/panacea-core/v2/x/oracle/client/cli"
)

var ProposalHandler = govclient.NewProposalHandler(cli.CmdUpgradeOracleProposal, rest.ProposalRESTHandler)
64 changes: 64 additions & 0 deletions x/oracle/client/rest/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package rest

import (
"net/http"

"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/types/rest"
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/medibloc/panacea-core/v2/x/oracle/types"
)

type PlanRequest struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
UpgradeHeight int64 `json:"upgrade_height" yaml:"upgrade_height"`
UpgradeUniqueID string `json:"upgrade_unique_id" yaml:"upgrade_unique_id"`
}

func ProposalRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "oracle",
Handler: newPostPlanHandler(clientCtx),
}
}

func newPostPlanHandler(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req PlanRequest

if !rest.ReadRESTReq(w, r, clientCtx.LegacyAmino, &req) {
return
}

req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}

fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if rest.CheckBadRequestError(w, err) {
return
}

plan := types.Plan{
UniqueId: req.UpgradeUniqueID,
Height: req.UpgradeHeight,
}
content := types.NewOracleUpgradeProposal(req.Title, req.Description, plan)
msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, fromAddr)
if rest.CheckBadRequestError(w, err) {
return
}
if rest.CheckBadRequestError(w, msg.ValidateBasic()) {
return
}

tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg)
}
}
14 changes: 14 additions & 0 deletions x/oracle/keeper/grpc_query_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
"errors"

"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -93,6 +94,19 @@ func (k Keeper) OracleRegistration(goCtx context.Context, request *types.QueryOr
return &types.QueryOracleRegistrationResponse{OracleRegistration: oracleRegistration}, nil
}

func (k Keeper) OracleUpgradeInfo(ctx context.Context, _ *types.QueryOracleUpgradeInfoRequest) (*types.QueryOracleUpgradeInfoResponse, error) {
upgradeInfo, err := k.GetOracleUpgradeInfo(sdk.UnwrapSDKContext(ctx))
if err != nil {
if errors.Is(err, types.ErrOracleUpgradeInfoNotFound) {
return &types.QueryOracleUpgradeInfoResponse{}, nil
}
return nil, err
}
return &types.QueryOracleUpgradeInfoResponse{
OracleUpgradeInfo: upgradeInfo,
}, nil
}

func (k Keeper) Params(goCtx context.Context, _ *types.QueryOracleParamsRequest) (*types.QueryParamsResponse, error) {
params := k.GetParams(sdk.UnwrapSDKContext(goCtx))
return &types.QueryParamsResponse{Params: &params}, nil
Expand Down
24 changes: 20 additions & 4 deletions x/oracle/keeper/grpc_query_oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (suite *queryOracleTestSuite) TestOracleRegistrations() {
OracleCommissionRate: suite.oracleCommissionRate,
OracleCommissionMaxRate: suite.oracleCommissionMaxRate,
OracleCommissionMaxChangeRate: suite.oracleCommissionMaxChangeRate,
EncryptedOraclePrivKey: nil,
EncryptedOraclePrivKey: nil,
}

oracleRegistration2 := &types.OracleRegistration{
Expand All @@ -154,7 +154,7 @@ func (suite *queryOracleTestSuite) TestOracleRegistrations() {
OracleCommissionRate: suite.oracle2CommissionRate,
OracleCommissionMaxRate: suite.oracle2CommissionMaxRate,
OracleCommissionMaxChangeRate: suite.oracle2CommissionMaxChangeRate,
EncryptedOraclePrivKey: nil,
EncryptedOraclePrivKey: nil,
}

anotherUniqueID := "uniqueID2"
Expand All @@ -169,7 +169,7 @@ func (suite *queryOracleTestSuite) TestOracleRegistrations() {
OracleCommissionRate: suite.oracle2CommissionRate,
OracleCommissionMaxRate: suite.oracle2CommissionMaxRate,
OracleCommissionMaxChangeRate: suite.oracle2CommissionMaxChangeRate,
EncryptedOraclePrivKey: nil,
EncryptedOraclePrivKey: nil,
}

err := oracleKeeper.SetOracleRegistration(ctx, oracleRegistration)
Expand Down Expand Up @@ -245,7 +245,7 @@ func (suite *queryOracleTestSuite) TestOracleRegistration() {
OracleCommissionRate: suite.oracleCommissionRate,
OracleCommissionMaxRate: suite.oracleCommissionMaxRate,
OracleCommissionMaxChangeRate: suite.oracleCommissionMaxChangeRate,
EncryptedOraclePrivKey: nil,
EncryptedOraclePrivKey: nil,
}
err := oracleKeeper.SetOracleRegistration(ctx, oracleRegistration)
suite.Require().NoError(err)
Expand All @@ -263,3 +263,19 @@ func (suite *queryOracleTestSuite) TestOracleParams() {

suite.Require().Equal(types.DefaultParams(), *res.Params)
}

func (suite *queryOracleTestSuite) TestOracleUpgradeInfo() {
ctx := suite.Ctx
oracleKeeper := suite.OracleKeeper

upgradeInfo := &types.OracleUpgradeInfo{
UniqueId: "UpgradeUniqueID",
Height: 1000000,
}
suite.Require().NoError(oracleKeeper.SetOracleUpgradeInfo(ctx, upgradeInfo))

getUpgradeInfo, err := oracleKeeper.OracleUpgradeInfo(sdk.WrapSDKContext(ctx), nil)
suite.Require().NoError(err)
suite.Require().Equal(upgradeInfo.UniqueId, getUpgradeInfo.OracleUpgradeInfo.UniqueId)
suite.Require().Equal(upgradeInfo.Height, getUpgradeInfo.OracleUpgradeInfo.Height)
}
Loading