add custom errors

This commit is contained in:
rhuairahrighairigh 2020-03-29 20:43:25 +01:00
parent e228aa6659
commit 074bb246a8
10 changed files with 86 additions and 58 deletions

View File

@ -217,7 +217,8 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
app.committeeKeeper = committee.NewKeeper( app.committeeKeeper = committee.NewKeeper(
app.cdc, app.cdc,
keys[committee.StoreKey], keys[committee.StoreKey],
committeeGovRouter) // TODO blacklist module addresses?) committeeGovRouter,
committee.DefaultCodespace) // TODO blacklist module addresses?)
govRouter := gov.NewRouter() govRouter := gov.NewRouter()
govRouter. govRouter.
AddRoute(gov.RouterKey, gov.ProposalHandler). AddRoute(gov.RouterKey, gov.ProposalHandler).

View File

@ -16,6 +16,11 @@ const (
AttributeValueProposalFailed = types.AttributeValueProposalFailed AttributeValueProposalFailed = types.AttributeValueProposalFailed
AttributeValueProposalPassed = types.AttributeValueProposalPassed AttributeValueProposalPassed = types.AttributeValueProposalPassed
AttributeValueProposalTimeout = types.AttributeValueProposalTimeout AttributeValueProposalTimeout = types.AttributeValueProposalTimeout
CodeInvalidCommittee = types.CodeInvalidCommittee
CodeInvalidGenesis = types.CodeInvalidGenesis
CodeInvalidProposal = types.CodeInvalidProposal
CodeProposalExpired = types.CodeProposalExpired
CodeUnknownItem = types.CodeUnknownItem
DefaultCodespace = types.DefaultCodespace DefaultCodespace = types.DefaultCodespace
DefaultNextProposalID = types.DefaultNextProposalID DefaultNextProposalID = types.DefaultNextProposalID
DefaultParamspace = types.DefaultParamspace DefaultParamspace = types.DefaultParamspace
@ -45,6 +50,14 @@ var (
NewKeeper = keeper.NewKeeper NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier NewQuerier = keeper.NewQuerier
DefaultGenesisState = types.DefaultGenesisState DefaultGenesisState = types.DefaultGenesisState
ErrInvalidCommittee = types.ErrInvalidCommittee
ErrInvalidGenesis = types.ErrInvalidGenesis
ErrInvalidPubProposal = types.ErrInvalidPubProposal
ErrNoProposalHandlerExists = types.ErrNoProposalHandlerExists
ErrProposalExpired = types.ErrProposalExpired
ErrUnknownCommittee = types.ErrUnknownCommittee
ErrUnknownProposal = types.ErrUnknownProposal
ErrUnknownVote = types.ErrUnknownVote
GetKeyFromID = types.GetKeyFromID GetKeyFromID = types.GetKeyFromID
GetVoteKey = types.GetVoteKey GetVoteKey = types.GetVoteKey
NewCommittee = types.NewCommittee NewCommittee = types.NewCommittee

View File

@ -50,7 +50,7 @@ func handleMsgVote(ctx sdk.Context, k keeper.Keeper, msg types.MsgVote) sdk.Resu
// get the proposal just to add fields to the event // get the proposal just to add fields to the event
proposal, found := k.GetProposal(ctx, msg.ProposalID) proposal, found := k.GetProposal(ctx, msg.ProposalID)
if !found { if !found {
return sdk.ErrInternal("proposal not found").Result() return ErrUnknownProposal(DefaultCodespace, msg.ProposalID).Result()
} }
err := k.AddVote(ctx, msg.ProposalID, msg.Voter) err := k.AddVote(ctx, msg.ProposalID, msg.Voter)

View File

@ -14,12 +14,13 @@ import (
type Keeper struct { type Keeper struct {
cdc *codec.Codec cdc *codec.Codec
storeKey sdk.StoreKey storeKey sdk.StoreKey
codespace sdk.CodespaceType
// Proposal router // Proposal router
router govtypes.Router router govtypes.Router
} }
func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, router govtypes.Router) Keeper { func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, router govtypes.Router, codespace sdk.CodespaceType) Keeper {
// Logic in the keeper methods assume the set of gov handlers is fixed. // Logic in the keeper methods assume the set of gov handlers is fixed.
// So the gov router must be sealed so no handlers can be added or removed after the keeper is created. // So the gov router must be sealed so no handlers can be added or removed after the keeper is created.
router.Seal() router.Seal()
@ -27,6 +28,7 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, router govtypes.Router)
return Keeper{ return Keeper{
cdc: cdc, cdc: cdc,
storeKey: storeKey, storeKey: storeKey,
codespace: codespace,
router: router, router: router,
} }
} }
@ -87,7 +89,7 @@ func (k Keeper) GetNextProposalID(ctx sdk.Context) (uint64, sdk.Error) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
bz := store.Get(types.NextProposalIDKey) bz := store.Get(types.NextProposalIDKey)
if bz == nil { if bz == nil {
return 0, sdk.ErrInternal("proposal ID not set at genesis") return 0, types.ErrInvalidGenesis(k.codespace, "next proposal ID not set at genesis")
} }
return types.Uint64FromBytes(bz), nil return types.Uint64FromBytes(bz), nil
} }

View File

@ -13,15 +13,15 @@ func (k Keeper) SubmitProposal(ctx sdk.Context, proposer sdk.AccAddress, committ
// Limit proposals to only be submitted by committee members // Limit proposals to only be submitted by committee members
com, found := k.GetCommittee(ctx, committeeID) com, found := k.GetCommittee(ctx, committeeID)
if !found { if !found {
return 0, sdk.ErrInternal("committee doesn't exist") return 0, types.ErrUnknownCommittee(k.codespace, committeeID)
} }
if !com.HasMember(proposer) { if !com.HasMember(proposer) {
return 0, sdk.ErrInternal("only member can propose proposals") return 0, sdk.ErrUnauthorized("proposer not member of committee")
} }
// Check committee has permissions to enact proposal. // Check committee has permissions to enact proposal.
if !com.HasPermissionsFor(pubProposal) { if !com.HasPermissionsFor(pubProposal) {
return 0, sdk.ErrInternal("committee does not have permissions to enact proposal") return 0, sdk.ErrUnauthorized("committee does not have permissions to enact proposal")
} }
// Check proposal is valid // Check proposal is valid
@ -51,17 +51,17 @@ func (k Keeper) AddVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress
// Validate // Validate
pr, found := k.GetProposal(ctx, proposalID) pr, found := k.GetProposal(ctx, proposalID)
if !found { if !found {
return sdk.ErrInternal("proposal not found") return types.ErrUnknownProposal(k.codespace, proposalID)
} }
if pr.HasExpiredBy(ctx.BlockTime()) { if pr.HasExpiredBy(ctx.BlockTime()) {
return sdk.ErrInternal("proposal expired") return types.ErrProposalExpired(k.codespace, ctx.BlockTime(), pr.Deadline)
} }
com, found := k.GetCommittee(ctx, pr.CommitteeID) com, found := k.GetCommittee(ctx, pr.CommitteeID)
if !found { if !found {
return sdk.ErrInternal("committee disbanded") return types.ErrUnknownCommittee(k.codespace, pr.CommitteeID)
} }
if !com.HasMember(voter) { if !com.HasMember(voter) {
return sdk.ErrInternal("not authorized to vote on proposal") return sdk.ErrUnauthorized("voter must be a member of committee")
} }
// Store vote, overwriting any prior vote // Store vote, overwriting any prior vote
@ -81,11 +81,11 @@ func (k Keeper) AddVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress
func (k Keeper) GetProposalResult(ctx sdk.Context, proposalID uint64) (bool, sdk.Error) { func (k Keeper) GetProposalResult(ctx sdk.Context, proposalID uint64) (bool, sdk.Error) {
pr, found := k.GetProposal(ctx, proposalID) pr, found := k.GetProposal(ctx, proposalID)
if !found { if !found {
return false, sdk.ErrInternal("proposal not found") return false, types.ErrUnknownProposal(k.codespace, proposalID)
} }
com, found := k.GetCommittee(ctx, pr.CommitteeID) com, found := k.GetCommittee(ctx, pr.CommitteeID)
if !found { if !found {
return false, sdk.ErrInternal("committee disbanded") return false, types.ErrUnknownCommittee(k.codespace, pr.CommitteeID)
} }
numVotes := k.TallyVotes(ctx, proposalID) numVotes := k.TallyVotes(ctx, proposalID)
@ -111,7 +111,7 @@ func (k Keeper) TallyVotes(ctx sdk.Context, proposalID uint64) int64 {
func (k Keeper) EnactProposal(ctx sdk.Context, proposalID uint64) sdk.Error { func (k Keeper) EnactProposal(ctx sdk.Context, proposalID uint64) sdk.Error {
pr, found := k.GetProposal(ctx, proposalID) pr, found := k.GetProposal(ctx, proposalID)
if !found { if !found {
return sdk.ErrInternal("proposal not found") return types.ErrUnknownProposal(k.codespace, proposalID)
} }
// Run the proposal's changes through the associated handler, but using a cached version of state to ensure changes are not permanent if an error occurs. // Run the proposal's changes through the associated handler, but using a cached version of state to ensure changes are not permanent if an error occurs.
@ -128,14 +128,14 @@ func (k Keeper) EnactProposal(ctx sdk.Context, proposalID uint64) sdk.Error {
// ValidatePubProposal checks if a pubproposal is valid. // ValidatePubProposal checks if a pubproposal is valid.
func (k Keeper) ValidatePubProposal(ctx sdk.Context, pubProposal types.PubProposal) sdk.Error { func (k Keeper) ValidatePubProposal(ctx sdk.Context, pubProposal types.PubProposal) sdk.Error {
if pubProposal == nil { if pubProposal == nil {
return sdk.ErrInternal("proposal is empty") return types.ErrInvalidPubProposal(k.codespace, "pub proposal cannot be nil")
} }
if err := pubProposal.ValidateBasic(); err != nil { if err := pubProposal.ValidateBasic(); err != nil {
return err return err
} }
if !k.router.HasRoute(pubProposal.ProposalRoute()) { if !k.router.HasRoute(pubProposal.ProposalRoute()) {
return sdk.ErrInternal("no handler found for proposal") return types.ErrNoProposalHandlerExists(k.codespace, pubProposal)
} }
// Run the proposal's changes through the associated handler using a cached version of state to ensure changes are not permanent. // Run the proposal's changes through the associated handler using a cached version of state to ensure changes are not permanent.

View File

@ -29,8 +29,6 @@ func NewQuerier(keeper Keeper) sdk.Querier {
return queryVote(ctx, path[1:], req, keeper) return queryVote(ctx, path[1:], req, keeper)
case types.QueryTally: case types.QueryTally:
return queryTally(ctx, path[1:], req, keeper) return queryTally(ctx, path[1:], req, keeper)
// case types.QueryParams:
// return queryParams(ctx, path[1:], req, keeper)
default: default:
return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown %s query endpoint", types.ModuleName)) return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown %s query endpoint", types.ModuleName))
@ -64,7 +62,7 @@ func queryCommittee(ctx sdk.Context, path []string, req abci.RequestQuery, keepe
committee, found := keeper.GetCommittee(ctx, params.CommitteeID) committee, found := keeper.GetCommittee(ctx, params.CommitteeID)
if !found { if !found {
return nil, sdk.ErrInternal("not found") ///types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID) return nil, types.ErrUnknownCommittee(types.DefaultCodespace, params.CommitteeID)
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, committee) bz, err := codec.MarshalJSONIndent(keeper.cdc, committee)
@ -107,7 +105,7 @@ func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
proposal, found := keeper.GetProposal(ctx, params.ProposalID) proposal, found := keeper.GetProposal(ctx, params.ProposalID)
if !found { if !found {
return nil, sdk.ErrInternal("not found") // TODO types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID) return nil, types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID)
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, proposal) bz, err := codec.MarshalJSONIndent(keeper.cdc, proposal)
@ -149,7 +147,7 @@ func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Kee
vote, found := keeper.GetVote(ctx, params.ProposalID, params.Voter) vote, found := keeper.GetVote(ctx, params.ProposalID, params.Voter)
if !found { if !found {
return nil, sdk.ErrInternal("not found") return nil, types.ErrUnknownVote(types.DefaultCodespace, params.ProposalID, params.Voter)
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, vote) bz, err := codec.MarshalJSONIndent(keeper.cdc, vote)
@ -170,7 +168,7 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke
_, found := keeper.GetProposal(ctx, params.ProposalID) _, found := keeper.GetProposal(ctx, params.ProposalID)
if !found { if !found {
return nil, sdk.ErrInternal("proposal not found") return nil, types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID)
} }
numVotes := keeper.TallyVotes(ctx, params.ProposalID) numVotes := keeper.TallyVotes(ctx, params.ProposalID)
@ -180,30 +178,3 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke
} }
return bz, nil return bz, nil
} }
// ---------- Params ----------
// func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
// switch path[0] {
// case types.ParamDeposit:
// bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetDepositParams(ctx))
// if err != nil {
// return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
// }
// return bz, nil
// case types.ParamVoting:
// bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetVotingParams(ctx))
// if err != nil {
// return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
// }
// return bz, nil
// case types.ParamTallying:
// bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetTallyParams(ctx))
// if err != nil {
// return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
// }
// return bz, nil
// default:
// return nil, sdk.ErrUnknownRequest(fmt.Sprintf("%s is not a valid query request path", req.Path))
// }
// }

View File

@ -24,7 +24,7 @@ func NewProposalHandler(k Keeper) govtypes.Handler {
func handleCommitteeChangeProposal(ctx sdk.Context, k Keeper, committeeProposal CommitteeChangeProposal) sdk.Error { func handleCommitteeChangeProposal(ctx sdk.Context, k Keeper, committeeProposal CommitteeChangeProposal) sdk.Error {
if err := committeeProposal.ValidateBasic(); err != nil { if err := committeeProposal.ValidateBasic(); err != nil {
return sdk.ErrInternal(err.Error()) return ErrInvalidCommittee(DefaultCodespace, err.Error())
} }
// Remove all committee's ongoing proposals // Remove all committee's ongoing proposals
@ -46,7 +46,7 @@ func handleCommitteeChangeProposal(ctx sdk.Context, k Keeper, committeeProposal
func handleCommitteeDeleteProposal(ctx sdk.Context, k Keeper, committeeProposal CommitteeDeleteProposal) sdk.Error { func handleCommitteeDeleteProposal(ctx sdk.Context, k Keeper, committeeProposal CommitteeDeleteProposal) sdk.Error {
if err := committeeProposal.ValidateBasic(); err != nil { if err := committeeProposal.ValidateBasic(); err != nil {
return sdk.ErrInternal(err.Error()) return ErrInvalidPubProposal(DefaultCodespace, err.Error())
} }
// Remove all committee's ongoing proposals // Remove all committee's ongoing proposals

View File

@ -1,9 +1,50 @@
package types package types
import ( import (
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
const ( const (
DefaultCodespace sdk.CodespaceType = ModuleName DefaultCodespace sdk.CodespaceType = ModuleName
CodeProposalExpired sdk.CodeType = 1
CodeUnknownItem sdk.CodeType = 2
CodeInvalidGenesis sdk.CodeType = 3
CodeInvalidProposal sdk.CodeType = 4
CodeInvalidCommittee sdk.CodeType = 5
) )
func ErrUnknownCommittee(codespace sdk.CodespaceType, id uint64) sdk.Error {
return sdk.NewError(codespace, CodeUnknownItem, fmt.Sprintf("committee with id '%d' not found", id))
}
func ErrInvalidCommittee(codespace sdk.CodespaceType, msg string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidCommittee, msg)
}
func ErrUnknownProposal(codespace sdk.CodespaceType, id uint64) sdk.Error {
return sdk.NewError(codespace, CodeUnknownItem, fmt.Sprintf("proposal with id '%d' not found", id))
}
func ErrProposalExpired(codespace sdk.CodespaceType, blockTime, expiry time.Time) sdk.Error {
return sdk.NewError(codespace, CodeProposalExpired, fmt.Sprintf("proposal expired at %s, current blocktime %s", expiry, blockTime))
}
func ErrInvalidPubProposal(codespace sdk.CodespaceType, msg string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidProposal, msg)
}
func ErrUnknownVote(codespace sdk.CodespaceType, proposalID uint64, voter sdk.AccAddress) sdk.Error {
return sdk.NewError(codespace, CodeUnknownItem, fmt.Sprintf("vote with for proposal '%d' and voter %s not found", proposalID, voter))
}
func ErrInvalidGenesis(codespace sdk.CodespaceType, msg string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidGenesis, msg)
}
func ErrNoProposalHandlerExists(codespace sdk.CodespaceType, content interface{}) sdk.Error {
return sdk.NewError(codespace, CodeUnknownItem, fmt.Sprintf("'%T' does not have a corresponding handler", content))
}

View File

@ -53,7 +53,7 @@ func (ccp CommitteeChangeProposal) ValidateBasic() sdk.Error {
return err return err
} }
if err := ccp.NewCommittee.Validate(); err != nil { if err := ccp.NewCommittee.Validate(); err != nil {
return sdk.ErrInternal(err.Error()) return ErrInvalidCommittee(DefaultCodespace, err.Error())
} }
return nil return nil
} }

View File

@ -36,7 +36,7 @@ func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgSubmitProposal) ValidateBasic() sdk.Error { func (msg MsgSubmitProposal) ValidateBasic() sdk.Error {
if msg.PubProposal == nil { if msg.PubProposal == nil {
return sdk.ErrInternal("no proposal") return ErrInvalidPubProposal(DefaultCodespace, "pub proposal cannot be nil")
} }
if msg.Proposer.Empty() { if msg.Proposer.Empty() {
return sdk.ErrInvalidAddress(msg.Proposer.String()) return sdk.ErrInvalidAddress(msg.Proposer.String())