Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add role-based access control for bridge #1350

Merged
merged 51 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
427ac1d
add submitting role proposal feature
tkxkd0159 May 2, 2024
754496b
chore
tkxkd0159 May 2, 2024
e30a99d
feat: addVote
tkxkd0159 May 2, 2024
1693f60
feat: role proposal confirmation logic
tkxkd0159 May 2, 2024
90d7aca
add gRPC for RBAC
tkxkd0159 May 2, 2024
38d0969
fix checking trustLevel condition
tkxkd0159 May 2, 2024
f21efb6
validate role metadata during initialization
tkxkd0159 May 2, 2024
25f2722
add invariants for metadata
tkxkd0159 May 3, 2024
b6dedb9
chore
tkxkd0159 May 3, 2024
f902e67
delete expired proposal at begin blocker
tkxkd0159 May 3, 2024
2cb61cd
chore
tkxkd0159 May 3, 2024
4460ca3
add memStore and halting feature
tkxkd0159 May 3, 2024
59962c2
chore
tkxkd0159 May 3, 2024
e4727c2
remove redundant gRPC queries
tkxkd0159 May 3, 2024
cb2f2b9
fix endblock logic
tkxkd0159 May 3, 2024
79fe412
chore
tkxkd0159 May 3, 2024
200c366
add Params test
tkxkd0159 May 3, 2024
83b042e
add dummy guardian for testing
tkxkd0159 May 3, 2024
dae3f09
remove redundant invariants
tkxkd0159 May 3, 2024
41b5197
Merge `pjdp1`
tkxkd0159 May 3, 2024
72b4a68
set bridge switch at missing parts
tkxkd0159 May 3, 2024
c6ea9b8
fix typo
tkxkd0159 May 3, 2024
77959dd
add gov authority
tkxkd0159 May 3, 2024
d0d5dfb
add guardian invariant
tkxkd0159 May 3, 2024
5ceb48b
chore
tkxkd0159 May 3, 2024
428d0e6
Merge `pjdp1`
tkxkd0159 May 3, 2024
1a6e281
add single member query
tkxkd0159 May 3, 2024
e41f7ef
return error if the address has no role
tkxkd0159 May 3, 2024
cdebadd
append genesis validation
tkxkd0159 May 3, 2024
b502673
chore
tkxkd0159 May 3, 2024
1ad0782
add CLI
tkxkd0159 May 3, 2024
b4f3b6c
return all registered members if there is no query string
tkxkd0159 May 4, 2024
f1dba4f
add unit tests for RBAC
tkxkd0159 May 6, 2024
7cb0469
merge `halt` with `resume` as `set-bridge-status`
tkxkd0159 May 6, 2024
948acae
lint
tkxkd0159 May 6, 2024
72ff22f
Add CHANGELOG
tkxkd0159 May 6, 2024
1a50d25
add ERRORS docs
tkxkd0159 May 6, 2024
d8bbd64
chore
tkxkd0159 May 6, 2024
0694e1e
apply 0tech review
tkxkd0159 May 7, 2024
00aefbf
enhance bridge switch unit test
tkxkd0159 May 7, 2024
73dd078
chore
tkxkd0159 May 7, 2024
369647d
chore
tkxkd0159 May 7, 2024
3aa2233
chore
tkxkd0159 May 7, 2024
de9cfde
maintain bridge status metadata based on permanent states
tkxkd0159 May 7, 2024
4136321
change panic msg for unimplemented features
tkxkd0159 May 7, 2024
b6c2f13
check duplicate seq in genesis
tkxkd0159 May 7, 2024
0d21ba2
bridge inactive counter must always be initialization
tkxkd0159 May 7, 2024
26fe40d
bridge is always inactive if there is no guardian
tkxkd0159 May 7, 2024
bc831be
lint
tkxkd0159 May 7, 2024
c245173
start fbridge module after auth/bank
tkxkd0159 May 7, 2024
3e332f7
remove redundant invariant checking
tkxkd0159 May 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -12703,7 +12703,7 @@ MsgTransfer is input values required for bridge transfer
| `Claim` | [MsgClaim](#lbm.fbridge.v1.MsgClaim) | [MsgClaimResponse](#lbm.fbridge.v1.MsgClaimResponse) | Claim processes the claiming of a provision with a specific sequence number | |
| `SuggestRole` | [MsgSuggestRole](#lbm.fbridge.v1.MsgSuggestRole) | [MsgSuggestRoleResponse](#lbm.fbridge.v1.MsgSuggestRoleResponse) | SuggestRole suggests updating the role of an address in the bridge module. The role can be one of the following: guardian, operator, judge. The proposal will be passed only with the consent of +2/3 Guardian members. | |
| `AddVoteForRole` | [MsgAddVoteForRole](#lbm.fbridge.v1.MsgAddVoteForRole) | [MsgAddVoteForRoleResponse](#lbm.fbridge.v1.MsgAddVoteForRoleResponse) | AddVoteForRole adds a vote for a role change proposal. | |
| `SetBridgeStatus` | [MsgSetBridgeStatus](#lbm.fbridge.v1.MsgSetBridgeStatus) | [MsgSetBridgeStatusResponse](#lbm.fbridge.v1.MsgSetBridgeStatusResponse) | SetBridgeStatus operates a switch to halt/resume the bridge module. If the ratio of active bridge switches does not exceed TrustLevel, the bridge module halts. | |
| `SetBridgeStatus` | [MsgSetBridgeStatus](#lbm.fbridge.v1.MsgSetBridgeStatus) | [MsgSetBridgeStatusResponse](#lbm.fbridge.v1.MsgSetBridgeStatusResponse) | SetBridgeStatus operates a switch to halt/resume the bridge module. If the ratio of inactive bridge switches exceed TrustLevel, the bridge module halts. | |

<!-- end services -->

Expand Down
1 change: 1 addition & 0 deletions proto/lbm/fbridge/v1/fbridge.proto
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ enum BridgeStatus {

// BRIDGE_STATUS_UNSPECIFIED defines an unspecified bridge status.
BRIDGE_STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "StatusEmpty"];

// BRIDGE_STATUS_ACTIVE defines an active bridge status.
BRIDGE_STATUS_ACTIVE = 1 [(gogoproto.enumvalue_customname) = "StatusActive"];
// BRIDGE_STATUS_INACTIVE defines an inactive bridge status.
Expand Down
2 changes: 1 addition & 1 deletion proto/lbm/fbridge/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ service Msg {
rpc AddVoteForRole(MsgAddVoteForRole) returns (MsgAddVoteForRoleResponse);

// SetBridgeStatus operates a switch to halt/resume the bridge module.
// If the ratio of active bridge switches does not exceed TrustLevel, the bridge module halts.
// If the ratio of inactive bridge switches exceed TrustLevel, the bridge module halts.
rpc SetBridgeStatus(MsgSetBridgeStatus) returns (MsgSetBridgeStatusResponse);
}

Expand Down
20 changes: 15 additions & 5 deletions x/fbridge/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,71 @@
"github.com/Finschia/finschia-sdk/x/fbridge/types"
)

func (k Keeper) BeginBlocker(ctx sdk.Context) {
k.InitMemStore(ctx)

Check warning on line 11 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L10-L11

Added lines #L10 - L11 were not covered by tests

proposals := k.GetRoleProposals(ctx)
for _, proposal := range proposals {
if ctx.BlockTime().After(proposal.ExpiredAt) {
k.deleteRoleProposal(ctx, proposal.Id)

Check warning on line 16 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L13-L16

Added lines #L13 - L16 were not covered by tests
}
}
}

func (k Keeper) EndBlocker(ctx sdk.Context) {
guardianTrustLevel := k.GetParams(ctx).GuardianTrustLevel
proposals := k.GetRoleProposals(ctx)
for _, proposal := range proposals {
votes := k.GetProposalVotes(ctx, proposal.Id)

Check warning on line 25 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L21-L25

Added lines #L21 - L25 were not covered by tests

var voteYes uint64 = 0
for _, vote := range votes {
if vote.Option == types.OptionYes {
voteYes++

Check warning on line 30 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L27-L30

Added lines #L27 - L30 were not covered by tests
}
}

if types.CheckTrustLevelThreshold(k.GetRoleMetadata(ctx).Guardian, voteYes, guardianTrustLevel) || proposal.Proposer == k.GetAuthority() {
0Tech marked this conversation as resolved.
Show resolved Hide resolved
if err := k.updateRole(ctx, proposal.Role, sdk.MustAccAddressFromBech32(proposal.Target)); err != nil {
panic(err)

Check warning on line 36 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L34-L36

Added lines #L34 - L36 were not covered by tests
}

k.deleteRoleProposal(ctx, proposal.Id)

Check warning on line 39 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L39

Added line #L39 was not covered by tests
}
}
}

// RegisterInvariants registers the fbridge module invariants
func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ir.RegisterRoute(types.ModuleName, "guardian-invariant", GuardianInvariant(k))

Check warning on line 46 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L45-L46

Added lines #L45 - L46 were not covered by tests
}

func GuardianInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
numGuardian := 0
for _, p := range k.GetRolePairs(ctx) {
if p.Role == types.RoleGuardian {
numGuardian++

Check warning on line 54 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L49-L54

Added lines #L49 - L54 were not covered by tests
}
}

numBridgeSw := len(k.GetBridgeSwitches(ctx))
if numGuardian != numBridgeSw {
return sdk.FormatInvariant(
types.ModuleName, "guardian-invariant",
fmt.Sprintf("number of guardians(%d) != number of bridge switches(%d)", numGuardian, numBridgeSw),
), true

Check warning on line 63 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L58-L63

Added lines #L58 - L63 were not covered by tests
}

broken := numGuardian != numBridgeSw
bsMeta := k.GetBridgeStatusMetadata(ctx)
roleMeta := k.GetRoleMetadata(ctx)
if (bsMeta.Inactive + bsMeta.Active) != roleMeta.Guardian {
return sdk.FormatInvariant(
types.ModuleName, "guardian-invariant",
fmt.Sprintf("Bridge status metadata (%+v) does not match with guardian role metadata(%d)", bsMeta, roleMeta.Guardian),
), true

Check warning on line 72 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L66-L72

Added lines #L66 - L72 were not covered by tests
}

return sdk.FormatInvariant(
types.ModuleName, "guardian-invariant",
fmt.Sprintf("number of guardians(%d) != number of bridge switches(%d)", numGuardian, numBridgeSw),
), broken
return sdk.FormatInvariant(types.ModuleName, "guardian-invariant", ""), false

Check warning on line 75 in x/fbridge/keeper/abci.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/abci.go#L75

Added line #L75 was not covered by tests
}
}
48 changes: 26 additions & 22 deletions x/fbridge/keeper/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
}

if k.GetRole(ctx, target) == role {
return types.RoleProposal{}, sdkerrors.ErrUnauthorized.Wrap("target already has same role")

Check warning on line 25 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L25

Added line #L25 was not covered by tests
}

proposalID := k.GetNextProposalID(ctx)
Expand All @@ -42,16 +42,16 @@

func (k Keeper) addVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress, option types.VoteOption) error {
if k.GetRole(ctx, voter) != types.RoleGuardian {
return sdkerrors.ErrUnauthorized.Wrap("only guardian can execute this action")

Check warning on line 45 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L45

Added line #L45 was not covered by tests
}

_, found := k.GetRoleProposal(ctx, proposalID)
if !found {
return types.ErrUnknownProposal.Wrapf("#%d not found", proposalID)

Check warning on line 50 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L50

Added line #L50 was not covered by tests
}

if err := types.IsValidVoteOption(option); err != nil {
return err
return sdkerrors.ErrInvalidRequest.Wrap(err.Error())

Check warning on line 54 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L54

Added line #L54 was not covered by tests
}

k.setVote(ctx, proposalID, voter, option)
Expand All @@ -66,82 +66,76 @@
}

roleMeta := k.GetRoleMetadata(ctx)
bsMeta := k.GetBridgeStatusMetadata(ctx)
nInactive := k.GetBridgeInactiveCounter(ctx)

switch previousRole {
case types.RoleGuardian:
roleMeta.Guardian--

sw, err := k.GetBridgeSwitch(ctx, addr)
bs, err := k.GetBridgeSwitch(ctx, addr)
if err != nil {
panic(err)
return err

Check warning on line 77 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L77

Added line #L77 was not covered by tests
}

switch sw.Status {
case types.StatusActive:
bsMeta.Active--
case types.StatusInactive:
bsMeta.Inactive--
default:
return sdkerrors.ErrInvalidRequest.Wrap("invalid bridge switch status")
if bs.Status == types.StatusInactive {
nInactive--

Check warning on line 81 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L81

Added line #L81 was not covered by tests
}

k.deleteBridgeSwitch(ctx, addr)

case types.RoleOperator:
roleMeta.Operator--
case types.RoleJudge:
roleMeta.Judge--

Check warning on line 89 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L86-L89

Added lines #L86 - L89 were not covered by tests
}

if role == types.RoleEmpty {
k.deleteRole(ctx, addr)
return nil

Check warning on line 94 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L93-L94

Added lines #L93 - L94 were not covered by tests
} else {
k.setRole(ctx, role, addr)
if err := k.setRole(ctx, role, addr); err != nil {
return err

Check warning on line 97 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L97

Added line #L97 was not covered by tests
}
}

switch role {
case types.RoleGuardian:
roleMeta.Guardian++
tkxkd0159 marked this conversation as resolved.
Show resolved Hide resolved
if err := k.setBridgeSwitch(ctx, addr, types.StatusActive); err != nil {
panic(err)

Check warning on line 105 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L105

Added line #L105 was not covered by tests
}
bsMeta.Active++
case types.RoleOperator:
roleMeta.Operator++
case types.RoleJudge:
roleMeta.Judge++

Check warning on line 110 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L109-L110

Added lines #L109 - L110 were not covered by tests
}

k.setRoleMetadata(ctx, roleMeta)
k.setBridgeStatusMetadata(ctx, bsMeta)
k.setBridgeInactiveCounter(ctx, nInactive)

return nil
}

func (k Keeper) updateBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress, status types.BridgeStatus) error {
if sw, err := k.GetBridgeSwitch(ctx, guardian); err == nil && sw.Status == status {
return sdkerrors.ErrInvalidRequest.Wrapf("%s already set %s", guardian, status)

Check warning on line 121 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L121

Added line #L121 was not covered by tests
} else if err != nil {
return err

Check warning on line 123 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L123

Added line #L123 was not covered by tests
}

bsMeta := k.GetBridgeStatusMetadata(ctx)
nInactive := k.GetBridgeInactiveCounter(ctx)
switch status {
tkxkd0159 marked this conversation as resolved.
Show resolved Hide resolved
case types.StatusActive:
bsMeta.Active++
bsMeta.Inactive--
nInactive--
case types.StatusInactive:
bsMeta.Inactive++
bsMeta.Active--
nInactive++
default:
return sdkerrors.ErrInvalidRequest.Wrap("invalid bridge switch status")
return sdkerrors.ErrInvalidRequest.Wrapf("unknown bridge status: %d", status)

Check warning on line 133 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L132-L133

Added lines #L132 - L133 were not covered by tests
}
k.setBridgeStatusMetadata(ctx, bsMeta)
k.setBridgeInactiveCounter(ctx, nInactive)

if err := k.setBridgeSwitch(ctx, guardian, status); err != nil {
return err

Check warning on line 138 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L138

Added line #L138 was not covered by tests
}

return nil
Expand All @@ -158,7 +152,7 @@
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyNextProposalID)
if bz == nil {
panic("next role proposal ID must be set at genesis")

Check warning on line 155 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L155

Added line #L155 was not covered by tests
}

return binary.BigEndian.Uint64(bz)
Expand All @@ -174,44 +168,44 @@
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.ProposalKey(id))
if bz == nil {
return proposal, false

Check warning on line 171 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L171

Added line #L171 was not covered by tests
}

k.cdc.MustUnmarshal(bz, &proposal)
return proposal, true
}

func (k Keeper) deleteRoleProposal(ctx sdk.Context, id uint64) {
store := ctx.KVStore(k.storeKey)
if _, found := k.GetRoleProposal(ctx, id); !found {
panic(fmt.Sprintf("role proposal #%d not found", id))

Check warning on line 181 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L178-L181

Added lines #L178 - L181 were not covered by tests
}
store.Delete(types.ProposalKey(id))

Check warning on line 183 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L183

Added line #L183 was not covered by tests
}

// IterateProposals iterates over the all the role proposals and performs a callback function
func (k Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.RoleProposal) (stop bool)) {
store := ctx.KVStore(k.storeKey)

Check warning on line 188 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L187-L188

Added lines #L187 - L188 were not covered by tests

iterator := sdk.KVStorePrefixIterator(store, types.KeyProposalPrefix)
defer iterator.Close()

Check warning on line 191 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L190-L191

Added lines #L190 - L191 were not covered by tests

for ; iterator.Valid(); iterator.Next() {
var proposal types.RoleProposal
k.cdc.MustUnmarshal(iterator.Value(), &proposal)
if cb(proposal) {
break

Check warning on line 197 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L193-L197

Added lines #L193 - L197 were not covered by tests
}
}
}

// GetRoleProposals returns all the role proposals from store
func (k Keeper) GetRoleProposals(ctx sdk.Context) (proposals []types.RoleProposal) {
k.IterateProposals(ctx, func(proposal types.RoleProposal) bool {
proposals = append(proposals, proposal)
return false
})
return

Check warning on line 208 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L203-L208

Added lines #L203 - L208 were not covered by tests
}

func (k Keeper) setVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress, option types.VoteOption) {
Expand All @@ -225,36 +219,42 @@
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.VoterVoteKey(proposalID, voter))
if bz == nil {
return types.OptionEmpty, types.ErrUnknownVote

Check warning on line 222 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L222

Added line #L222 was not covered by tests
}

return types.VoteOption(binary.BigEndian.Uint32(bz)), nil
}

func (k Keeper) GetProposalVotes(ctx sdk.Context, proposalID uint64) []types.Vote {
store := ctx.KVStore(k.storeKey)

Check warning on line 229 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L228-L229

Added lines #L228 - L229 were not covered by tests

votes := make([]types.Vote, 0)
iterator := sdk.KVStorePrefixIterator(store, types.VotesKey(proposalID))
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
_, voter := types.SplitVoterVoteKey(iterator.Key())
v := types.Vote{
ProposalId: proposalID,
Voter: voter.String(),
Option: types.VoteOption(binary.BigEndian.Uint32(iterator.Value())),

Check warning on line 239 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L231-L239

Added lines #L231 - L239 were not covered by tests
}
votes = append(votes, v)

Check warning on line 241 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L241

Added line #L241 was not covered by tests
}

return votes

Check warning on line 244 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L244

Added line #L244 was not covered by tests
}

func (k Keeper) setRole(ctx sdk.Context, role types.Role, addr sdk.AccAddress) {
func (k Keeper) setRole(ctx sdk.Context, role types.Role, addr sdk.AccAddress) error {
if err := types.IsValidRole(role); err != nil {
return sdkerrors.ErrInvalidRequest.Wrap(err.Error())

Check warning on line 249 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L249

Added line #L249 was not covered by tests
}

store := ctx.KVStore(k.storeKey)
bz := make([]byte, 4)
binary.BigEndian.PutUint32(bz, uint32(role))
store.Set(types.RoleKey(addr), bz)

return nil
}

func (k Keeper) GetRole(ctx sdk.Context, addr sdk.AccAddress) types.Role {
Expand All @@ -273,19 +273,23 @@
iterator := sdk.KVStorePrefixIterator(store, types.KeyRolePrefix)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
assignee := types.SplitRoleKey(iterator.Key())
pairs = append(pairs, types.RolePair{Address: assignee.String(), Role: types.Role(binary.BigEndian.Uint32(iterator.Value()))})

Check warning on line 277 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L276-L277

Added lines #L276 - L277 were not covered by tests
}

return pairs
}

func (k Keeper) deleteRole(ctx sdk.Context, addr sdk.AccAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.RoleKey(addr))

Check warning on line 285 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L283-L285

Added lines #L283 - L285 were not covered by tests
}

func (k Keeper) setBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress, status types.BridgeStatus) error {
if err := types.IsValidBridgeStatus(status); err != nil {
return sdkerrors.ErrInvalidRequest.Wrap(err.Error())

Check warning on line 290 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L290

Added line #L290 was not covered by tests
}

store := ctx.KVStore(k.storeKey)
bz := make([]byte, 4)
binary.BigEndian.PutUint32(bz, uint32(status))
Expand All @@ -300,13 +304,13 @@

func (k Keeper) GetBridgeSwitch(ctx sdk.Context, guardian sdk.AccAddress) (types.BridgeSwitch, error) {
if k.GetRole(ctx, guardian) != types.RoleGuardian {
return types.BridgeSwitch{}, sdkerrors.ErrUnauthorized.Wrap("only guardian has bridge switch")

Check warning on line 307 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L307

Added line #L307 was not covered by tests
}

store := ctx.KVStore(k.storeKey)
bz := store.Get(types.BridgeSwitchKey(guardian))
if bz == nil {
panic("bridge switch must be set at genesis")

Check warning on line 313 in x/fbridge/keeper/auth.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/auth.go#L313

Added line #L313 was not covered by tests
}

return types.BridgeSwitch{Guardian: guardian.String(), Status: types.BridgeStatus(binary.BigEndian.Uint32(bz))}, nil
Expand Down
1 change: 0 additions & 1 deletion x/fbridge/keeper/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,4 @@ func TestBridgeHaltAndResume(t *testing.T) {
require.NoError(t, err)
require.Equal(t, types.StatusActive, k.GetBridgeStatus(ctx), "bridge status must be active (2/3)")
require.Equal(t, types.BridgeStatusMetadata{Active: 2, Inactive: 1}, k.GetBridgeStatusMetadata(ctx))

}
4 changes: 3 additions & 1 deletion x/fbridge/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,24 @@
}

for _, pair := range gs.Roles {
k.setRole(ctx, pair.Role, sdk.MustAccAddressFromBech32(pair.Address))
if err := k.setRole(ctx, pair.Role, sdk.MustAccAddressFromBech32(pair.Address)); err != nil {
panic(err)

Check warning on line 19 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L18-L19

Added lines #L18 - L19 were not covered by tests
}
}

for _, sw := range gs.BridgeSwitches {
if err := k.setBridgeSwitch(ctx, sdk.MustAccAddressFromBech32(sw.Guardian), sw.Status); err != nil {
panic(err)

Check warning on line 25 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L24-L25

Added lines #L24 - L25 were not covered by tests
}
}

k.setNextProposalID(ctx, gs.NextRoleProposalId)
for _, proposal := range gs.RoleProposals {
k.setRoleProposal(ctx, proposal)

Check warning on line 31 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L31

Added line #L31 was not covered by tests
}

for _, vote := range gs.Votes {
k.setVote(ctx, vote.ProposalId, sdk.MustAccAddressFromBech32(vote.Voter), vote.Option)

Check warning on line 35 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L35

Added line #L35 was not covered by tests
}

// TODO: we initialize the appropriate genesis parameters whenever the feature is added
Expand All @@ -42,17 +44,17 @@

func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
return &types.GenesisState{
Params: k.GetParams(ctx),

Check warning on line 47 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L47

Added line #L47 was not covered by tests
SendingState: types.SendingState{
NextSeq: k.GetNextSequence(ctx),
SeqToBlocknum: k.getAllSeqToBlocknums(ctx),
},
ReceivingState: types.ReceivingState{},
NextRoleProposalId: k.GetNextProposalID(ctx),
RoleProposals: k.GetRoleProposals(ctx),
Votes: k.GetAllVotes(ctx),
Roles: k.GetRolePairs(ctx),
BridgeSwitches: k.GetBridgeSwitches(ctx),

Check warning on line 57 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L52-L57

Added lines #L52 - L57 were not covered by tests
}
tkxkd0159 marked this conversation as resolved.
Show resolved Hide resolved
}

Expand All @@ -73,26 +75,26 @@
}

// IterateVotes iterates over the all the votes for role proposals and performs a callback function
func (k Keeper) IterateVotes(ctx sdk.Context, cb func(proposal types.Vote) (stop bool)) {
store := ctx.KVStore(k.storeKey)

Check warning on line 79 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L78-L79

Added lines #L78 - L79 were not covered by tests

iterator := sdk.KVStorePrefixIterator(store, types.KeyProposalVotePrefix)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
id, voter := types.SplitVoterVoteKey(iterator.Key())
opt := types.VoteOption(binary.BigEndian.Uint32(iterator.Value()))
v := types.Vote{ProposalId: id, Voter: voter.String(), Option: opt}
if cb(v) {
break

Check warning on line 88 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L81-L88

Added lines #L81 - L88 were not covered by tests
}
}
}

// GetAllVotes returns all the votes from the store
func (k Keeper) GetAllVotes(ctx sdk.Context) (votes []types.Vote) {
k.IterateVotes(ctx, func(vote types.Vote) bool {
votes = append(votes, vote)
return false
})
return

Check warning on line 99 in x/fbridge/keeper/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/genesis.go#L94-L99

Added lines #L94 - L99 were not covered by tests
}
56 changes: 29 additions & 27 deletions x/fbridge/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"encoding/binary"
"errors"
"fmt"

Expand Down Expand Up @@ -40,7 +41,7 @@
if authority == addr.String() {
break
}
panic("x/bridge authority must be the gov or foundation module account")

Check warning on line 44 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L44

Added line #L44 was not covered by tests
}

return Keeper{
Expand All @@ -62,7 +63,7 @@
memStore := ctx.KVStore(k.memKey)
memStoreType := memStore.GetStoreType()
if memStoreType != sdk.StoreTypeMemory {
panic(fmt.Sprintf("invalid memory store type; got %s, expected: %s", memStoreType, sdk.StoreTypeMemory))

Check warning on line 66 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L66

Added line #L66 was not covered by tests
}

// create context with no block gas meter to ensure we do not consume gas during local initialization logic.
Expand All @@ -71,29 +72,19 @@
roleMetadata := types.RoleMetadata{}
if !k.IsInitialized(noGasCtx) {
for _, pair := range k.GetRolePairs(noGasCtx) {
switch pair.Role {
case types.RoleGuardian:
roleMetadata.Guardian++
case types.RoleOperator:
roleMetadata.Operator++
case types.RoleJudge:
roleMetadata.Judge++

Check warning on line 81 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L75-L81

Added lines #L75 - L81 were not covered by tests
}
}
k.setRoleMetadata(noGasCtx, roleMetadata)

bsMeta := types.BridgeStatusMetadata{Inactive: 0, Active: 0}
for _, bs := range k.GetBridgeSwitches(noGasCtx) {
switch bs.Status {
case types.StatusInactive:
bsMeta.Inactive++
case types.StatusActive:
bsMeta.Active++
default:
panic("invalid bridge switch status")
}
}
k.setBridgeStatusMetadata(noGasCtx, types.BridgeStatusMetadata{})
nInactive := k.GetBridgeInactiveCounter(noGasCtx)
k.setBridgeInactiveCounter(noGasCtx, nInactive)

memStore := noGasCtx.KVStore(k.memKey)
memStore.Set(types.KeyMemInitialized, []byte{1})
Expand All @@ -110,8 +101,8 @@
return k.authority
}

func (k Keeper) IsBridgeHalted(ctx sdk.Context) bool {
return k.GetBridgeStatus(ctx) == types.StatusInactive

Check warning on line 105 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L104-L105

Added lines #L104 - L105 were not covered by tests
}

func (k Keeper) setRoleMetadata(ctx sdk.Context, data types.RoleMetadata) {
Expand All @@ -125,37 +116,48 @@
data := types.RoleMetadata{}
bz := memStore.Get(types.KeyMemRoleMetadata)
if bz == nil {
return types.RoleMetadata{}

Check warning on line 119 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L119

Added line #L119 was not covered by tests
}
k.cdc.MustUnmarshal(bz, &data)
return data
}

func (k Keeper) GetBridgeStatus(ctx sdk.Context) types.BridgeStatus {
memStore := ctx.KVStore(k.memKey)
bsMeta := types.BridgeStatusMetadata{}
bz := memStore.Get(types.KeyMemBridgeStatus)
k.cdc.MustUnmarshal(bz, &bsMeta)

if types.CheckTrustLevelThreshold(bsMeta.Active+bsMeta.Inactive, bsMeta.Active, k.GetParams(ctx).GuardianTrustLevel) {
return types.StatusActive
roleMeta := k.GetRoleMetadata(ctx)
bsMeta := k.GetBridgeStatusMetadata(ctx)
if types.CheckTrustLevelThreshold(roleMeta.Guardian, bsMeta.Inactive, k.GetParams(ctx).GuardianTrustLevel) {
return types.StatusInactive
}

return types.StatusInactive
return types.StatusActive
}

func (k Keeper) setBridgeStatusMetadata(ctx sdk.Context, status types.BridgeStatusMetadata) {
func (k Keeper) setBridgeInactiveCounter(ctx sdk.Context, nInactive uint64) {
memStore := ctx.KVStore(k.memKey)
memStore.Set(types.KeyMemBridgeStatus, k.cdc.MustMarshal(&status))
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, nInactive)
memStore.Set(types.KeyMemBridgeInactiveCounter, bz)
}

func (k Keeper) GetBridgeStatusMetadata(ctx sdk.Context) types.BridgeStatusMetadata {
func (k Keeper) GetBridgeInactiveCounter(ctx sdk.Context) uint64 {
memStore := ctx.KVStore(k.memKey)
bsMeta := types.BridgeStatusMetadata{}
bz := memStore.Get(types.KeyMemBridgeStatus)
bz := memStore.Get(types.KeyMemBridgeInactiveCounter)
if bz == nil {
return types.BridgeStatusMetadata{}
n := uint64(0)
0Tech marked this conversation as resolved.
Show resolved Hide resolved
for _, bs := range k.GetBridgeSwitches(ctx) {
if bs.Status == types.StatusInactive {
n++

Check warning on line 149 in x/fbridge/keeper/keeper.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/keeper.go#L148-L149

Added lines #L148 - L149 were not covered by tests
}
}
return n
}
k.cdc.MustUnmarshal(bz, &bsMeta)

return binary.BigEndian.Uint64(bz)
}

func (k Keeper) GetBridgeStatusMetadata(ctx sdk.Context) types.BridgeStatusMetadata {
bsMeta := types.BridgeStatusMetadata{}
bsMeta.Inactive = k.GetBridgeInactiveCounter(ctx)
bsMeta.Active = k.GetRoleMetadata(ctx).Guardian - bsMeta.Inactive
return bsMeta
}
4 changes: 0 additions & 4 deletions x/fbridge/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
func (m msgServer) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

if m.IsBridgeHalted(ctx) {
return nil, types.ErrInactiveBridge

Check warning on line 25 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L24-L25

Added lines #L24 - L25 were not covered by tests
}

from, err := sdk.AccAddressFromBech32(msg.Sender)
Expand Down Expand Up @@ -75,75 +75,71 @@
panic("implement me")
}

func (m msgServer) SuggestRole(goCtx context.Context, msg *types.MsgSuggestRole) (*types.MsgSuggestRoleResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Check warning on line 79 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L78-L79

Added lines #L78 - L79 were not covered by tests

proposer, err := sdk.AccAddressFromBech32(msg.From)
if err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid proposer address (%s)", err)

Check warning on line 83 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L81-L83

Added lines #L81 - L83 were not covered by tests
}

target, err := sdk.AccAddressFromBech32(msg.Target)
if err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid target address (%s)", err)

Check warning on line 88 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L86-L88

Added lines #L86 - L88 were not covered by tests
}

if err := types.IsValidRole(msg.Role); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())

Check warning on line 92 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L91-L92

Added lines #L91 - L92 were not covered by tests
}

proposal, err := m.RegisterRoleProposal(ctx, proposer, target, msg.Role)
if err != nil {
return nil, err

Check warning on line 97 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L95-L97

Added lines #L95 - L97 were not covered by tests
}

if err := ctx.EventManager().EmitTypedEvent(&types.EventSuggestRole{
Proposal: proposal,
}); err != nil {
panic(err)

Check warning on line 103 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L100-L103

Added lines #L100 - L103 were not covered by tests
}

return &types.MsgSuggestRoleResponse{}, nil

Check warning on line 106 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L106

Added line #L106 was not covered by tests
}

func (m msgServer) AddVoteForRole(goCtx context.Context, msg *types.MsgAddVoteForRole) (*types.MsgAddVoteForRoleResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Check warning on line 110 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L109-L110

Added lines #L109 - L110 were not covered by tests

voter, err := sdk.AccAddressFromBech32(msg.From)
if err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid proposer address (%s)", err)

Check warning on line 114 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L112-L114

Added lines #L112 - L114 were not covered by tests
}

if err := types.IsValidVoteOption(msg.Option); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
}

if err := m.addVote(ctx, msg.ProposalId, voter, msg.Option); err != nil {
return nil, err

Check warning on line 118 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L117-L118

Added lines #L117 - L118 were not covered by tests
}

if err := ctx.EventManager().EmitTypedEvent(&types.EventAddVoteForRole{
Voter: msg.From,
ProposalId: msg.ProposalId,
Option: msg.Option,
}); err != nil {
panic(err)

Check warning on line 126 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L121-L126

Added lines #L121 - L126 were not covered by tests
}

return &types.MsgAddVoteForRoleResponse{}, nil

Check warning on line 129 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L129

Added line #L129 was not covered by tests
}

func (m msgServer) SetBridgeStatus(goCtx context.Context, msg *types.MsgSetBridgeStatus) (*types.MsgSetBridgeStatusResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Check warning on line 133 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L132-L133

Added lines #L132 - L133 were not covered by tests

addr, err := sdk.AccAddressFromBech32(msg.Guardian)
if err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid guardian address (%s)", err)

Check warning on line 137 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L135-L137

Added lines #L135 - L137 were not covered by tests
}

if err := m.updateBridgeSwitch(ctx, addr, msg.Status); err != nil {
return nil, err

Check warning on line 141 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L140-L141

Added lines #L140 - L141 were not covered by tests
}

return &types.MsgSetBridgeStatusResponse{}, nil

Check warning on line 144 in x/fbridge/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/keeper/msg_server.go#L144

Added line #L144 was not covered by tests
}
6 changes: 3 additions & 3 deletions x/fbridge/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
KeyRolePrefix = []byte{0x13} // key prefix for the role of an address
KeyBridgeSwitchPrefix = []byte{0x14} // key for the switch to halt

KeyMemInitialized = []byte{0xF0}
KeyMemRoleMetadata = []byte{0xF1} // key for the role metadata
KeyMemBridgeStatus = []byte{0xF2} // key for the bridge status
KeyMemInitialized = []byte{0xF0}
KeyMemRoleMetadata = []byte{0xF1} // key for the role metadata
KeyMemBridgeInactiveCounter = []byte{0xF2} // key for the bridge inactive status
)

func SeqToBlocknumKey(seq uint64) []byte {
Expand All @@ -56,52 +56,52 @@
}

// GetProposalIDBytes returns the byte representation of the proposalID
func GetProposalIDBytes(proposalID uint64) []byte {
bz := make([]byte, 8)
binary.BigEndian.PutUint64(bz, proposalID)
return bz

Check warning on line 62 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L59-L62

Added lines #L59 - L62 were not covered by tests
}

// ProposalKey key of a specific role proposal
func ProposalKey(proposalID uint64) []byte {
return append(KeyProposalPrefix, GetProposalIDBytes(proposalID)...)

Check warning on line 67 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L66-L67

Added lines #L66 - L67 were not covered by tests
}

// VotesKey gets the first part of the votes key based on the proposalID
func VotesKey(proposalID uint64) []byte {
return append(KeyProposalVotePrefix, GetProposalIDBytes(proposalID)...)

Check warning on line 72 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L71-L72

Added lines #L71 - L72 were not covered by tests
}

// VoterVoteKey key of a specific vote from the store
func VoterVoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte {
return append(VotesKey(proposalID), address.MustLengthPrefix(voterAddr.Bytes())...)

Check warning on line 77 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L76-L77

Added lines #L76 - L77 were not covered by tests
}

// SplitVoterVoteKey split the voter key and returns the proposal id and voter address
func SplitVoterVoteKey(key []byte) (uint64, sdk.AccAddress) {
kv.AssertKeyAtLeastLength(key, 11)
proposalID := binary.BigEndian.Uint64(key[1:9])
voter := sdk.AccAddress(key[10:])
return proposalID, voter

Check warning on line 85 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L81-L85

Added lines #L81 - L85 were not covered by tests
}

// RoleKey key of a specific role of the address from the store
func RoleKey(target sdk.AccAddress) []byte {
return append(KeyRolePrefix, address.MustLengthPrefix(target.Bytes())...)

Check warning on line 90 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L89-L90

Added lines #L89 - L90 were not covered by tests
}

// SplitRoleKey split the role key and returns the address
func SplitRoleKey(key []byte) sdk.AccAddress {
kv.AssertKeyAtLeastLength(key, 3)
return key[2:]

Check warning on line 96 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L94-L96

Added lines #L94 - L96 were not covered by tests
}

func BridgeSwitchKey(guardian sdk.AccAddress) []byte {
return append(KeyBridgeSwitchPrefix, address.MustLengthPrefix(guardian.Bytes())...)

Check warning on line 100 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L99-L100

Added lines #L99 - L100 were not covered by tests
}

// SplitBridgeSwitchKey split the bridge switch key and returns the guardian address
func SplitBridgeSwitchKey(key []byte) sdk.AccAddress {
kv.AssertKeyAtLeastLength(key, 3)
return key[2:]

Check warning on line 106 in x/fbridge/types/keys.go

View check run for this annotation

Codecov / codecov/patch

x/fbridge/types/keys.go#L104-L106

Added lines #L104 - L106 were not covered by tests
}
4 changes: 2 additions & 2 deletions x/fbridge/types/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading