Skip to content

Commit

Permalink
Merge pull request #1861 from mesg-foundation/feature/credit-minter
Browse files Browse the repository at this point in the history
Add msg to mint credits module credit
  • Loading branch information
Nicolas Mahé authored Jun 4, 2020
2 parents 44b3aab + b54d454 commit 21a662e
Show file tree
Hide file tree
Showing 22 changed files with 516 additions and 17 deletions.
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ func NewInitApp(
app.subspaces[gov.ModuleName] = app.paramsKeeper.Subspace(gov.DefaultParamspace)
app.subspaces[evidence.ModuleName] = app.paramsKeeper.Subspace(evidence.DefaultParamspace)
app.subspaces[crisis.ModuleName] = app.paramsKeeper.Subspace(crisis.DefaultParamspace)
app.subspaces[credit.ModuleName] = app.paramsKeeper.Subspace(credit.DefaultParamspace)

// The AccountKeeper handles address -> account lookups
app.accountKeeper = auth.NewAccountKeeper(
Expand Down Expand Up @@ -305,7 +306,7 @@ func NewInitApp(
)

// Engine's module keepers
app.creditKeeper = credit.NewKeeper(app.cdc, keys[credit.StoreKey])
app.creditKeeper = credit.NewKeeper(app.cdc, app.accountKeeper, keys[credit.StoreKey], app.subspaces[credit.ModuleName])
app.ownershipKeeper = ownership.NewKeeper(app.cdc, keys[ownership.StoreKey], app.bankKeeper)
app.serviceKeeper = service.NewKeeper(app.cdc, keys[service.StoreKey], app.ownershipKeeper)
app.instanceKeeper = instance.NewKeeper(app.cdc, keys[instance.StoreKey], app.serviceKeeper)
Expand Down
8 changes: 8 additions & 0 deletions dev-chain/validator/config/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@
"params": {
"minPrice": "10000atto"
}
},
"credit": {
"credits": {},
"params": {
"minters": [
"mesg1s6mqusxaq93d70jeekqehg7aepwt7zs306ctq7"
]
}
}
}
}
1 change: 1 addition & 0 deletions e2e/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func TestAPI(t *testing.T) {

// run tests
t.Run("account-sequence", testAccountSequence)
t.Run("credit", testCredit)
t.Run("service", testService)
t.Run("runner", testRunner)
t.Run("process", testProcess)
Expand Down
57 changes: 57 additions & 0 deletions e2e/credit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
creditmodule "github.com/mesg-foundation/engine/x/credit"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
)

func testCredit(t *testing.T) {
var (
newAddr = sdk.AccAddress(crypto.AddressHash([]byte("addr")))
)
t.Run("account does not exist", func(t *testing.T) {
var accR *auth.BaseAccount
require.NoError(t, lcd.Get("auth/accounts/"+newAddr.String(), &accR))
require.True(t, accR.Address.Empty())
})
t.Run("add 1000 credits", func(t *testing.T) {
t.Run("balance before", func(t *testing.T) {
var balance sdk.Int
require.NoError(t, lcd.Get("credit/get/"+newAddr.String(), &balance))
require.Equal(t, sdk.NewInt(0), balance)
})
t.Run("add credits", func(t *testing.T) {
msg := creditmodule.MsgAdd{
Signer: cliAddress,
Address: newAddr,
Amount: sdk.NewInt(1000),
}
_, err = lcd.BroadcastMsg(msg)
require.NoError(t, err)
})
t.Run("balance after", func(t *testing.T) {
var balance sdk.Int
require.NoError(t, lcd.Get("credit/get/"+newAddr.String(), &balance))
require.Equal(t, sdk.NewInt(1000), balance)
})
})
t.Run("account exists", func(t *testing.T) {
var accR *auth.BaseAccount
require.NoError(t, lcd.Get("auth/accounts/"+newAddr.String(), &accR))
require.False(t, accR.Address.Empty())
})
t.Run("not authorized", func(t *testing.T) {
msg := creditmodule.MsgAdd{
Signer: engineAddress,
Address: newAddr,
Amount: sdk.NewInt(1000),
}
_, err = lcdEngine.BroadcastMsg(msg)
require.EqualError(t, err, "transaction returned with invalid code 4: unauthorized: the signer is not a minter: failed to execute message; message index: 0")
})
}
1 change: 1 addition & 0 deletions scripts/build-proto.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ protoc --gogo_out=paths=source_relative:. x/process/internal/types/msg.proto
protoc --gogo_out=paths=source_relative:. x/runner/internal/types/msg.proto
protoc --gogo_out=paths=source_relative:. x/execution/internal/types/msg.proto
protoc --gogo_out=paths=source_relative:. x/ownership/internal/types/msg.proto
protoc --gogo_out=paths=source_relative:. x/credit/internal/types/msg.proto

# generate gRPC api
protoc --gogo_out=paths=source_relative,plugins=grpc:. server/grpc/runner/runner.proto
Expand Down
17 changes: 11 additions & 6 deletions x/credit/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (

// const aliases
const (
ModuleName = types.ModuleName
RouterKey = types.RouterKey
StoreKey = types.StoreKey
QuerierRoute = types.QuerierRoute
ModuleName = types.ModuleName
RouterKey = types.RouterKey
StoreKey = types.StoreKey
DefaultParamspace = types.DefaultParamspace
QuerierRoute = types.QuerierRoute
)

// functions and variable aliases
Expand All @@ -22,8 +23,9 @@ var (
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis

ModuleCdc = types.ModuleCdc
QueryGet = types.QueryGet
ModuleCdc = types.ModuleCdc
QueryGet = types.QueryGet
QueryParameters = types.QueryParameters

EventType = types.EventType
AttributeActionAdded = types.AttributeActionAdded
Expand All @@ -34,4 +36,7 @@ var (
type (
Keeper = keeper.Keeper
GenesisState = types.GenesisState
Params = types.Params

MsgAdd = types.MsgAdd
)
23 changes: 23 additions & 0 deletions x/credit/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
creditQueryCmd.AddCommand(
flags.GetCommands(
GetCmdGet(queryRoute, cdc),
GetCmdQueryParams(queryRoute, cdc),
)...,
)

Expand All @@ -51,3 +52,25 @@ func GetCmdGet(queryRoute string, cdc *codec.Codec) *cobra.Command {
},
}
}

// GetCmdQueryParams implements the params query command.
func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "params",
Short: "Query the parameters",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)

route := fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryParameters)
bz, _, err := cliCtx.QueryWithData(route, nil)
if err != nil {
return err
}

var params types.Params
cdc.MustUnmarshalJSON(bz, &params)
return cliCtx.PrintOutput(params)
},
}
}
47 changes: 46 additions & 1 deletion x/credit/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package cli

import (
"bufio"
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
"github.com/mesg-foundation/engine/x/credit/internal/types"
"github.com/spf13/cobra"
)
Expand All @@ -21,6 +26,46 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
RunE: client.ValidateCmd,
}

creditTxCmd.AddCommand(flags.PostCommands()...)
creditTxCmd.AddCommand(flags.PostCommands(
GetCmdAdd(cdc),
)...)
return creditTxCmd
}

// GetCmdAdd is the command to create a execution.
func GetCmdAdd(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "add [address] [amount]",
Short: "Add credits to an address",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc)

txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))

address, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return fmt.Errorf("address: %w", err)
}
amount, ok := sdk.NewIntFromString(args[1])
if !ok {
return fmt.Errorf("cannot parse amount")
}
if cliCtx.FromAddress.Empty() {
return fmt.Errorf("flag --from is required")
}

msg := types.MsgAdd{
Address: address,
Amount: amount,
Signer: cliCtx.FromAddress,
}
if err := msg.ValidateBasic(); err != nil {
return err
}

return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
25 changes: 25 additions & 0 deletions x/credit/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
"/credit/get/{address}",
queryGetHandlerFn(cliCtx),
).Methods(http.MethodGet)

r.HandleFunc(
"/execution/parameters",
queryParamsHandlerFn(cliCtx),
).Methods("GET")
}

func queryGetHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
Expand All @@ -38,3 +43,23 @@ func queryGetHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
rest.PostProcessResponse(w, cliCtx, res)
}
}

func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
if !ok {
return
}

route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryParameters)

res, height, err := cliCtx.QueryWithData(route, nil)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}

cliCtx = cliCtx.WithHeight(height)
rest.PostProcessResponse(w, cliCtx, res)
}
}
4 changes: 3 additions & 1 deletion x/credit/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ func InitGenesis(ctx sdk.Context, k Keeper, data types.GenesisState) []abci.Vali
if err := k.Import(ctx, data.Credits); err != nil {
panic(err)
}
k.SetParams(ctx, data.Params)
return []abci.ValidatorUpdate{}
}

// ExportGenesis writes the current store values to a genesis file, which can be imported again with InitGenesis.
func ExportGenesis(ctx sdk.Context, k Keeper) (data types.GenesisState) {
params := k.GetParams(ctx)
execs, err := k.Export(ctx)
if err != nil {
panic(err)
}
return types.NewGenesisState(execs)
return types.NewGenesisState(params, execs)
}
32 changes: 32 additions & 0 deletions x/credit/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,41 @@ func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case MsgAdd:
return handleMsgAdd(ctx, k, msg)
default:
errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
}
}
}

// handleMsgAdd adds credits to an address.
func handleMsgAdd(ctx sdk.Context, k Keeper, msg MsgAdd) (*sdk.Result, error) {
// check if signer is a minter
minters := k.Minters(ctx)
isMinter := false
for _, minter := range minters {
if msg.Signer.Equals(minter) {
isMinter = true
break
}
}
if !isMinter {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "the signer is not a minter")
}
if _, err := k.Add(ctx, msg.Address, msg.Amount); err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, ModuleName),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Signer.String()),
),
)

return &sdk.Result{
Events: ctx.EventManager().Events(),
}, nil
}
17 changes: 12 additions & 5 deletions x/credit/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ import (

// Keeper of the credit store
type Keeper struct {
storeKey sdk.StoreKey
cdc *codec.Codec
storeKey sdk.StoreKey
cdc *codec.Codec
ak types.AccountKeeper
paramstore types.ParamSubspace
}

// NewKeeper creates a credit keeper
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey) Keeper {
func NewKeeper(cdc *codec.Codec, ak types.AccountKeeper, key sdk.StoreKey, paramstore types.ParamSubspace) Keeper {
keeper := Keeper{
storeKey: key,
cdc: cdc,
storeKey: key,
cdc: cdc,
ak: ak,
paramstore: paramstore.WithKeyTable(types.ParamKeyTable()),
}
return keeper
}
Expand Down Expand Up @@ -70,6 +74,9 @@ func (k Keeper) Sub(ctx sdk.Context, address sdk.AccAddress, amount sdk.Int) (sd

// Set a number of credit to a specific address
func (k Keeper) set(ctx sdk.Context, address sdk.AccAddress, balance sdk.Int) (sdk.Int, error) {
if k.ak.GetAccount(ctx, address) == nil {
k.ak.SetAccount(ctx, k.ak.NewAccountWithAddress(ctx, address))
}
store := ctx.KVStore(k.storeKey)
encoded, err := k.cdc.MarshalBinaryLengthPrefixed(balance)
if err != nil {
Expand Down
Loading

0 comments on commit 21a662e

Please sign in to comment.