github.com/Finschia/finschia-sdk@v0.48.1/x/gov/keeper/proposal.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Finschia/finschia-sdk/client"
     7  	sdk "github.com/Finschia/finschia-sdk/types"
     8  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
     9  	"github.com/Finschia/finschia-sdk/x/gov/types"
    10  )
    11  
    12  // SubmitProposal create new proposal given a content
    13  func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, error) {
    14  	if !keeper.router.HasRoute(content.ProposalRoute()) {
    15  		return types.Proposal{}, sdkerrors.Wrap(types.ErrNoProposalHandlerExists, content.ProposalRoute())
    16  	}
    17  
    18  	// Execute the proposal content in a new context branch (with branched store)
    19  	// to validate the actual parameter changes before the proposal proceeds
    20  	// through the governance process. State is not persisted.
    21  	cacheCtx, _ := ctx.CacheContext()
    22  	handler := keeper.router.GetRoute(content.ProposalRoute())
    23  	if err := handler(cacheCtx, content); err != nil {
    24  		return types.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalContent, err.Error())
    25  	}
    26  
    27  	proposalID, err := keeper.GetProposalID(ctx)
    28  	if err != nil {
    29  		return types.Proposal{}, err
    30  	}
    31  
    32  	submitTime := ctx.BlockHeader().Time
    33  	depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
    34  
    35  	proposal, err := types.NewProposal(content, proposalID, submitTime, submitTime.Add(depositPeriod))
    36  	if err != nil {
    37  		return types.Proposal{}, err
    38  	}
    39  
    40  	keeper.SetProposal(ctx, proposal)
    41  	keeper.InsertInactiveProposalQueue(ctx, proposalID, proposal.DepositEndTime)
    42  	keeper.SetProposalID(ctx, proposalID+1)
    43  
    44  	// called right after a proposal is submitted
    45  	keeper.AfterProposalSubmission(ctx, proposalID)
    46  
    47  	ctx.EventManager().EmitEvent(
    48  		sdk.NewEvent(
    49  			types.EventTypeSubmitProposal,
    50  			sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposalID)),
    51  		),
    52  	)
    53  
    54  	return proposal, nil
    55  }
    56  
    57  // GetProposal get proposal from store by ProposalID
    58  func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) (types.Proposal, bool) {
    59  	store := ctx.KVStore(keeper.storeKey)
    60  
    61  	bz := store.Get(types.ProposalKey(proposalID))
    62  	if bz == nil {
    63  		return types.Proposal{}, false
    64  	}
    65  
    66  	var proposal types.Proposal
    67  	keeper.MustUnmarshalProposal(bz, &proposal)
    68  
    69  	return proposal, true
    70  }
    71  
    72  // SetProposal set a proposal to store
    73  func (keeper Keeper) SetProposal(ctx sdk.Context, proposal types.Proposal) {
    74  	store := ctx.KVStore(keeper.storeKey)
    75  
    76  	bz := keeper.MustMarshalProposal(proposal)
    77  
    78  	store.Set(types.ProposalKey(proposal.ProposalId), bz)
    79  }
    80  
    81  // DeleteProposal deletes a proposal from store
    82  func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
    83  	store := ctx.KVStore(keeper.storeKey)
    84  	proposal, ok := keeper.GetProposal(ctx, proposalID)
    85  	if !ok {
    86  		panic(fmt.Sprintf("couldn't find proposal with id#%d", proposalID))
    87  	}
    88  	keeper.RemoveFromInactiveProposalQueue(ctx, proposalID, proposal.DepositEndTime)
    89  	keeper.RemoveFromActiveProposalQueue(ctx, proposalID, proposal.VotingEndTime)
    90  	store.Delete(types.ProposalKey(proposalID))
    91  }
    92  
    93  // IterateProposals iterates over the all the proposals and performs a callback function
    94  func (keeper Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.Proposal) (stop bool)) {
    95  	store := ctx.KVStore(keeper.storeKey)
    96  
    97  	iterator := sdk.KVStorePrefixIterator(store, types.ProposalsKeyPrefix)
    98  	defer iterator.Close()
    99  
   100  	for ; iterator.Valid(); iterator.Next() {
   101  		var proposal types.Proposal
   102  		err := keeper.UnmarshalProposal(iterator.Value(), &proposal)
   103  		if err != nil {
   104  			panic(err)
   105  		}
   106  
   107  		if cb(proposal) {
   108  			break
   109  		}
   110  	}
   111  }
   112  
   113  // GetProposals returns all the proposals from store
   114  func (keeper Keeper) GetProposals(ctx sdk.Context) (proposals types.Proposals) {
   115  	keeper.IterateProposals(ctx, func(proposal types.Proposal) bool {
   116  		proposals = append(proposals, proposal)
   117  		return false
   118  	})
   119  	return
   120  }
   121  
   122  // GetProposalsFiltered retrieves proposals filtered by a given set of params which
   123  // include pagination parameters along with voter and depositor addresses and a
   124  // proposal status. The voter address will filter proposals by whether or not
   125  // that address has voted on proposals. The depositor address will filter proposals
   126  // by whether or not that address has deposited to them. Finally, status will filter
   127  // proposals by status.
   128  //
   129  // NOTE: If no filters are provided, all proposals will be returned in paginated
   130  // form.
   131  func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, params types.QueryProposalsParams) types.Proposals {
   132  	proposals := keeper.GetProposals(ctx)
   133  	filteredProposals := make([]types.Proposal, 0, len(proposals))
   134  
   135  	for _, p := range proposals {
   136  		matchVoter, matchDepositor, matchStatus := true, true, true
   137  
   138  		// match status (if supplied/valid)
   139  		if types.ValidProposalStatus(params.ProposalStatus) {
   140  			matchStatus = p.Status == params.ProposalStatus
   141  		}
   142  
   143  		// match voter address (if supplied)
   144  		if len(params.Voter) > 0 {
   145  			_, matchVoter = keeper.GetVote(ctx, p.ProposalId, params.Voter)
   146  		}
   147  
   148  		// match depositor (if supplied)
   149  		if len(params.Depositor) > 0 {
   150  			_, matchDepositor = keeper.GetDeposit(ctx, p.ProposalId, params.Depositor)
   151  		}
   152  
   153  		if matchVoter && matchDepositor && matchStatus {
   154  			filteredProposals = append(filteredProposals, p)
   155  		}
   156  	}
   157  
   158  	start, end := client.Paginate(len(filteredProposals), params.Page, params.Limit, 100)
   159  	if start < 0 || end < 0 {
   160  		filteredProposals = []types.Proposal{}
   161  	} else {
   162  		filteredProposals = filteredProposals[start:end]
   163  	}
   164  
   165  	return filteredProposals
   166  }
   167  
   168  // GetProposalID gets the highest proposal ID
   169  func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err error) {
   170  	store := ctx.KVStore(keeper.storeKey)
   171  	bz := store.Get(types.ProposalIDKey)
   172  	if bz == nil {
   173  		return 0, sdkerrors.Wrap(types.ErrInvalidGenesis, "initial proposal ID hasn't been set")
   174  	}
   175  
   176  	proposalID = types.GetProposalIDFromBytes(bz)
   177  	return proposalID, nil
   178  }
   179  
   180  // SetProposalID sets the new proposal ID to the store
   181  func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) {
   182  	store := ctx.KVStore(keeper.storeKey)
   183  	store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID))
   184  }
   185  
   186  func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) {
   187  	proposal.VotingStartTime = ctx.BlockHeader().Time
   188  	votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
   189  	proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)
   190  	proposal.Status = types.StatusVotingPeriod
   191  	keeper.SetProposal(ctx, proposal)
   192  
   193  	keeper.RemoveFromInactiveProposalQueue(ctx, proposal.ProposalId, proposal.DepositEndTime)
   194  	keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)
   195  }
   196  
   197  func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) {
   198  	bz, err := keeper.cdc.Marshal(&proposal)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	return bz, nil
   203  }
   204  
   205  func (keeper Keeper) UnmarshalProposal(bz []byte, proposal *types.Proposal) error {
   206  	err := keeper.cdc.Unmarshal(bz, proposal)
   207  	if err != nil {
   208  		return err
   209  	}
   210  	return nil
   211  }
   212  
   213  func (keeper Keeper) MustMarshalProposal(proposal types.Proposal) []byte {
   214  	bz, err := keeper.MarshalProposal(proposal)
   215  	if err != nil {
   216  		panic(err)
   217  	}
   218  	return bz
   219  }
   220  
   221  func (keeper Keeper) MustUnmarshalProposal(bz []byte, proposal *types.Proposal) {
   222  	err := keeper.UnmarshalProposal(bz, proposal)
   223  	if err != nil {
   224  		panic(err)
   225  	}
   226  }