github.com/Finschia/finschia-sdk@v0.49.1/x/fbridge/keeper/auth.go (about)

     1  package keeper
     2  
     3  import (
     4  	"encoding/binary"
     5  	"time"
     6  
     7  	sdk "github.com/Finschia/finschia-sdk/types"
     8  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
     9  	"github.com/Finschia/finschia-sdk/x/fbridge/types"
    10  )
    11  
    12  func (k Keeper) RegisterRoleProposal(ctx sdk.Context, proposer, target sdk.AccAddress, role types.Role) (types.RoleProposal, error) {
    13  	if k.GetRoleMetadata(ctx).Guardian > 0 {
    14  		if k.GetRole(ctx, proposer) != types.RoleGuardian {
    15  			return types.RoleProposal{}, sdkerrors.ErrUnauthorized.Wrapf("only guardian can execute this action")
    16  		}
    17  	} else {
    18  		if proposer.String() != k.authority {
    19  			return types.RoleProposal{}, sdkerrors.ErrUnauthorized.Wrapf("only %s can execute this action", k.authority)
    20  		}
    21  	}
    22  
    23  	if k.GetRole(ctx, target) == role {
    24  		return types.RoleProposal{}, sdkerrors.ErrUnauthorized.Wrap("target already has same role")
    25  	}
    26  
    27  	proposalID := k.GetNextProposalID(ctx)
    28  	proposal := types.RoleProposal{
    29  		Id:        proposalID,
    30  		Proposer:  proposer.String(),
    31  		Target:    target.String(),
    32  		Role:      role,
    33  		ExpiredAt: ctx.BlockTime().Add(time.Duration(k.GetParams(ctx).ProposalPeriod)).UTC(),
    34  	}
    35  
    36  	k.setRoleProposal(ctx, proposal)
    37  	k.setNextProposalID(ctx, proposalID+1)
    38  
    39  	return proposal, nil
    40  }
    41  
    42  func (k Keeper) addVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress, option types.VoteOption) error {
    43  	if k.GetRole(ctx, voter) != types.RoleGuardian {
    44  		return sdkerrors.ErrUnauthorized.Wrap("only guardian can execute this action")
    45  	}
    46  
    47  	_, found := k.GetRoleProposal(ctx, proposalID)
    48  	if !found {
    49  		return types.ErrUnknownProposal.Wrapf("#%d not found", proposalID)
    50  	}
    51  
    52  	if err := types.IsValidVoteOption(option); err != nil {
    53  		return sdkerrors.ErrInvalidRequest.Wrap(err.Error())
    54  	}
    55  
    56  	k.setVote(ctx, proposalID, voter, option)
    57  
    58  	return nil
    59  }
    60  
    61  func (k Keeper) updateRole(ctx sdk.Context, role types.Role, addr sdk.AccAddress) error {
    62  	previousRole := k.GetRole(ctx, addr)
    63  	if previousRole == role {
    64  		return nil
    65  	}
    66  
    67  	roleMeta := k.GetRoleMetadata(ctx)
    68  	nInactive := k.GetBridgeInactiveCounter(ctx)
    69  
    70  	switch previousRole {
    71  	case types.RoleGuardian:
    72  		roleMeta.Guardian--
    73  
    74  		bs, err := k.GetBridgeSwitch(ctx, addr)
    75  		if err != nil {
    76  			return err
    77  		}
    78  
    79  		if bs.Status == types.StatusInactive {
    80  			nInactive--
    81  		}
    82  
    83  		k.deleteBridgeSwitch(ctx, addr)
    84  
    85  	case types.RoleOperator:
    86  		roleMeta.Operator--
    87  	case types.RoleJudge:
    88  		roleMeta.Judge--
    89  	}
    90  
    91  	if role == types.RoleEmpty {
    92  		k.deleteRole(ctx, addr)
    93  		return nil
    94  	} else if err := k.setRole(ctx, role, addr); err != nil {
    95  		return err
    96  	}
    97  
    98  	switch role {
    99  	case types.RoleGuardian:
   100  		roleMeta.Guardian++
   101  		if err := k.setBridgeSwitch(ctx, addr, types.StatusActive); err != nil {
   102  			panic(err)
   103  		}
   104  	case types.RoleOperator:
   105  		roleMeta.Operator++
   106  	case types.RoleJudge:
   107  		roleMeta.Judge++
   108  	}
   109  
   110  	k.setRoleMetadata(ctx, roleMeta)
   111  	k.setBridgeInactiveCounter(ctx, nInactive)
   112  
   113  	return nil
   114  }
   115  
   116  func (k Keeper) updateBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress, status types.BridgeStatus) error {
   117  	if sw, err := k.GetBridgeSwitch(ctx, guardian); err == nil && sw.Status == status {
   118  		return sdkerrors.ErrInvalidRequest.Wrapf("%s already set %s", guardian, status)
   119  	} else if err != nil {
   120  		return err
   121  	}
   122  
   123  	nInactive := k.GetBridgeInactiveCounter(ctx)
   124  	switch status {
   125  	case types.StatusActive:
   126  		nInactive--
   127  	case types.StatusInactive:
   128  		nInactive++
   129  	default:
   130  		return sdkerrors.ErrInvalidRequest.Wrapf("unknown bridge status: %d", status)
   131  	}
   132  	k.setBridgeInactiveCounter(ctx, nInactive)
   133  
   134  	if err := k.setBridgeSwitch(ctx, guardian, status); err != nil {
   135  		return err
   136  	}
   137  
   138  	return nil
   139  }
   140  
   141  func (k Keeper) setNextProposalID(ctx sdk.Context, seq uint64) {
   142  	store := ctx.KVStore(k.storeKey)
   143  	bz := make([]byte, 8)
   144  	binary.BigEndian.PutUint64(bz, seq)
   145  	store.Set(types.KeyNextProposalID, bz)
   146  }
   147  
   148  func (k Keeper) GetNextProposalID(ctx sdk.Context) uint64 {
   149  	store := ctx.KVStore(k.storeKey)
   150  	bz := store.Get(types.KeyNextProposalID)
   151  	if bz == nil {
   152  		panic("next role proposal ID must be set at genesis")
   153  	}
   154  
   155  	return binary.BigEndian.Uint64(bz)
   156  }
   157  
   158  func (k Keeper) setRoleProposal(ctx sdk.Context, proposal types.RoleProposal) {
   159  	store := ctx.KVStore(k.storeKey)
   160  	bz := k.cdc.MustMarshal(&proposal)
   161  	store.Set(types.ProposalKey(proposal.Id), bz)
   162  }
   163  
   164  func (k Keeper) GetRoleProposal(ctx sdk.Context, id uint64) (proposal types.RoleProposal, found bool) {
   165  	store := ctx.KVStore(k.storeKey)
   166  	bz := store.Get(types.ProposalKey(id))
   167  	if bz == nil {
   168  		return proposal, false
   169  	}
   170  
   171  	k.cdc.MustUnmarshal(bz, &proposal)
   172  	return proposal, true
   173  }
   174  
   175  func (k Keeper) deleteRoleProposal(ctx sdk.Context, id uint64) error {
   176  	store := ctx.KVStore(k.storeKey)
   177  	if _, found := k.GetRoleProposal(ctx, id); !found {
   178  		return sdkerrors.ErrNotFound.Wrapf("role proposal #%d not found", id)
   179  	}
   180  
   181  	store.Delete(types.ProposalKey(id))
   182  	return nil
   183  }
   184  
   185  // IterateProposals iterates over the all the role proposals and performs a callback function
   186  func (k Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.RoleProposal) (stop bool)) {
   187  	store := ctx.KVStore(k.storeKey)
   188  
   189  	iterator := sdk.KVStorePrefixIterator(store, types.KeyProposalPrefix)
   190  	defer iterator.Close()
   191  
   192  	for ; iterator.Valid(); iterator.Next() {
   193  		var proposal types.RoleProposal
   194  		k.cdc.MustUnmarshal(iterator.Value(), &proposal)
   195  		if cb(proposal) {
   196  			break
   197  		}
   198  	}
   199  }
   200  
   201  // GetRoleProposals returns all the role proposals from store
   202  func (k Keeper) GetRoleProposals(ctx sdk.Context) (proposals []types.RoleProposal) {
   203  	k.IterateProposals(ctx, func(proposal types.RoleProposal) bool {
   204  		proposals = append(proposals, proposal)
   205  		return false
   206  	})
   207  	return
   208  }
   209  
   210  func (k Keeper) setVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress, option types.VoteOption) {
   211  	store := ctx.KVStore(k.storeKey)
   212  	bz := make([]byte, 4)
   213  	binary.BigEndian.PutUint32(bz, uint32(option))
   214  	store.Set(types.VoterVoteKey(proposalID, voter), bz)
   215  }
   216  
   217  func (k Keeper) GetVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress) (types.VoteOption, error) {
   218  	store := ctx.KVStore(k.storeKey)
   219  	bz := store.Get(types.VoterVoteKey(proposalID, voter))
   220  	if bz == nil {
   221  		return types.OptionEmpty, types.ErrUnknownVote
   222  	}
   223  
   224  	return types.VoteOption(binary.BigEndian.Uint32(bz)), nil
   225  }
   226  
   227  func (k Keeper) GetProposalVotes(ctx sdk.Context, proposalID uint64) []types.Vote {
   228  	store := ctx.KVStore(k.storeKey)
   229  
   230  	votes := make([]types.Vote, 0)
   231  	iterator := sdk.KVStorePrefixIterator(store, types.VotesKey(proposalID))
   232  	defer iterator.Close()
   233  	for ; iterator.Valid(); iterator.Next() {
   234  		_, voter := types.SplitVoterVoteKey(iterator.Key())
   235  		v := types.Vote{
   236  			ProposalId: proposalID,
   237  			Voter:      voter.String(),
   238  			Option:     types.VoteOption(binary.BigEndian.Uint32(iterator.Value())),
   239  		}
   240  		votes = append(votes, v)
   241  	}
   242  
   243  	return votes
   244  }
   245  
   246  func (k Keeper) setRole(ctx sdk.Context, role types.Role, addr sdk.AccAddress) error {
   247  	if err := types.IsValidRole(role); err != nil {
   248  		return sdkerrors.ErrInvalidRequest.Wrap(err.Error())
   249  	}
   250  
   251  	store := ctx.KVStore(k.storeKey)
   252  	bz := make([]byte, 4)
   253  	binary.BigEndian.PutUint32(bz, uint32(role))
   254  	store.Set(types.RoleKey(addr), bz)
   255  
   256  	return nil
   257  }
   258  
   259  func (k Keeper) GetRole(ctx sdk.Context, addr sdk.AccAddress) types.Role {
   260  	store := ctx.KVStore(k.storeKey)
   261  	bz := store.Get(types.RoleKey(addr))
   262  	if bz == nil {
   263  		return types.RoleEmpty
   264  	}
   265  
   266  	return types.Role(binary.BigEndian.Uint32(bz))
   267  }
   268  
   269  func (k Keeper) GetRolePairs(ctx sdk.Context) []types.RolePair {
   270  	store := ctx.KVStore(k.storeKey)
   271  	pairs := make([]types.RolePair, 0)
   272  	iterator := sdk.KVStorePrefixIterator(store, types.KeyRolePrefix)
   273  	defer iterator.Close()
   274  	for ; iterator.Valid(); iterator.Next() {
   275  		assignee := types.SplitRoleKey(iterator.Key())
   276  		pairs = append(pairs, types.RolePair{Address: assignee.String(), Role: types.Role(binary.BigEndian.Uint32(iterator.Value()))})
   277  	}
   278  
   279  	return pairs
   280  }
   281  
   282  func (k Keeper) deleteRole(ctx sdk.Context, addr sdk.AccAddress) {
   283  	store := ctx.KVStore(k.storeKey)
   284  	store.Delete(types.RoleKey(addr))
   285  }
   286  
   287  func (k Keeper) setBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress, status types.BridgeStatus) error {
   288  	if err := types.IsValidBridgeStatus(status); err != nil {
   289  		return sdkerrors.ErrInvalidRequest.Wrap(err.Error())
   290  	}
   291  
   292  	store := ctx.KVStore(k.storeKey)
   293  	bz := make([]byte, 4)
   294  	binary.BigEndian.PutUint32(bz, uint32(status))
   295  	store.Set(types.BridgeSwitchKey(guardian), bz)
   296  	return nil
   297  }
   298  
   299  func (k Keeper) deleteBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress) {
   300  	store := ctx.KVStore(k.storeKey)
   301  	store.Delete(types.BridgeSwitchKey(guardian))
   302  }
   303  
   304  func (k Keeper) GetBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress) (types.BridgeSwitch, error) {
   305  	if k.GetRole(ctx, guardian) != types.RoleGuardian {
   306  		return types.BridgeSwitch{}, sdkerrors.ErrUnauthorized.Wrap("only guardian has bridge switch")
   307  	}
   308  
   309  	store := ctx.KVStore(k.storeKey)
   310  	bz := store.Get(types.BridgeSwitchKey(guardian))
   311  	if bz == nil {
   312  		panic("bridge switch must be set at genesis")
   313  	}
   314  
   315  	return types.BridgeSwitch{Guardian: guardian.String(), Status: types.BridgeStatus(binary.BigEndian.Uint32(bz))}, nil
   316  }
   317  
   318  func (k Keeper) GetBridgeSwitches(ctx sdk.Context) []types.BridgeSwitch {
   319  	store := ctx.KVStore(k.storeKey)
   320  
   321  	bws := make([]types.BridgeSwitch, 0)
   322  	iterator := sdk.KVStorePrefixIterator(store, types.KeyBridgeSwitchPrefix)
   323  	defer iterator.Close()
   324  	for ; iterator.Valid(); iterator.Next() {
   325  		addr := types.SplitBridgeSwitchKey(iterator.Key())
   326  		bws = append(bws, types.BridgeSwitch{Guardian: addr.String(), Status: types.BridgeStatus(binary.BigEndian.Uint32(iterator.Value()))})
   327  	}
   328  
   329  	return bws
   330  }