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 }