diff --git a/x/dispute/keeper/claim_reward.go b/x/dispute/keeper/claim_reward.go index 6daf09acc..56dc25af7 100644 --- a/x/dispute/keeper/claim_reward.go +++ b/x/dispute/keeper/claim_reward.go @@ -58,6 +58,7 @@ func (k Keeper) ClaimReward(ctx sdk.Context, addr sdk.AccAddress, id uint64) err return nil } +// CalculateReward calculates the dispute reward for a given voter and disputeId func (k Keeper) CalculateReward(ctx sdk.Context, addr sdk.AccAddress, id uint64) (math.Int, error) { dispute, err := k.Disputes.Get(ctx, id) if err != nil { @@ -97,6 +98,7 @@ func (k Keeper) CalculateReward(ctx sdk.Context, addr sdk.AccAddress, id uint64) if err != nil { return math.Int{}, err } + // Add up the global power for each group globalReporterPower = globalReporterPower.Add(math.NewIntFromUint64(pastVoteCounts.Reporters.Support)). Add(math.NewIntFromUint64(pastVoteCounts.Reporters.Against)).Add(math.NewIntFromUint64(pastVoteCounts.Reporters.Invalid)) globalUserPower = globalUserPower.Add(math.NewIntFromUint64(pastVoteCounts.Users.Support)). @@ -104,7 +106,7 @@ func (k Keeper) CalculateReward(ctx sdk.Context, addr sdk.AccAddress, id uint64) globalTokenholderPower = globalTokenholderPower.Add(math.NewIntFromUint64(pastVoteCounts.Tokenholders.Support)). Add(math.NewIntFromUint64(pastVoteCounts.Tokenholders.Against)).Add(math.NewIntFromUint64(pastVoteCounts.Tokenholders.Invalid)) } - + // nice way to handle zero division and zero votes totalGroups := int64(3) if globalReporterPower.IsZero() { globalReporterPower = math.NewInt(1) diff --git a/x/dispute/keeper/dispute.go b/x/dispute/keeper/dispute.go index 62a4309f2..b2811f781 100644 --- a/x/dispute/keeper/dispute.go +++ b/x/dispute/keeper/dispute.go @@ -19,38 +19,45 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Get dispute by reporter key +// GetDisputeByReporter assembles dispute key for reporter given the params and fetches the current dispute (the last generated one for this specific dispute) +// and returns the dispute object func (k Keeper) GetDisputeByReporter(ctx sdk.Context, r oracletypes.MicroReport, c types.DisputeCategory) (types.Dispute, error) { key := []byte(k.ReporterKey(ctx, r, c)) - - iter, err := k.Disputes.Indexes.DisputeByReporter.MatchExact(ctx, key) + rng := collections.NewPrefixedPairRange[[]byte, uint64](key).Descending() + // returns iterator for all the dispute ids sorted in descending order + iter, err := k.Disputes.Indexes.DisputeByReporter.Iterate(ctx, rng) if err != nil { return types.Dispute{}, err } - var id uint64 defer iter.Close() - for ; iter.Valid(); iter.Next() { - id, err = iter.PrimaryKey() - if err != nil { - return types.Dispute{}, err - } + if !iter.Valid() { + return types.Dispute{}, collections.ErrNotFound + } + // get the first dispute id + id, err := iter.PrimaryKey() + if err != nil { + return types.Dispute{}, err } return k.Disputes.Get(ctx, id) } -// Get next dispute id +// NextDisputeId fetches an iterator for all disputes in descending order and increments the first returned dispute id by 1 func (k Keeper) NextDisputeId(ctx sdk.Context) uint64 { - rng := new(collections.Range[uint64]).EndExclusive(gomath.MaxUint64).Descending() - // start dispute count at 1 - id := uint64(1) - err := k.Disputes.Walk(ctx, rng, func(k uint64, _ types.Dispute) (stop bool, err error) { - id = k + 1 - return true, nil - }) + rng := new(collections.Range[uint64]).Descending() + iter, err := k.Disputes.Iterate(ctx, rng) + if err != nil { + return 0 + } + defer iter.Close() + // for the first dispute id, return 1 + if !iter.Valid() { + return 1 + } + currentId, err := iter.Key() if err != nil { return 0 } - return id + return currentId + 1 } // Generate hash id diff --git a/x/dispute/keeper/keeper.go b/x/dispute/keeper/keeper.go index 86ea4f5c5..e30a5f457 100644 --- a/x/dispute/keeper/keeper.go +++ b/x/dispute/keeper/keeper.go @@ -32,18 +32,15 @@ type ( bankKeeper types.BankKeeper oracleKeeper types.OracleKeeper reporterKeeper types.ReporterKeeper - Disputes *collections.IndexedMap[uint64, types.Dispute, DisputesIndex] // dispute id -> dispute - Votes collections.Map[uint64, types.Vote] - Voter *collections.IndexedMap[collections.Pair[uint64, []byte], types.Voter, VotersVoteIndex] - TeamVoter collections.Map[uint64, bool] - UsersGroup collections.Map[collections.Pair[uint64, []byte], math.Int] - ReportersGroup collections.Map[collections.Pair[uint64, []byte], math.Int] - ReportersWithDelegatorsVotedBefore collections.Map[collections.Pair[[]byte, uint64], math.Int] - BlockInfo collections.Map[[]byte, types.BlockInfo] - DisputeFeePayer collections.Map[collections.Pair[uint64, []byte], types.PayerInfo] + Disputes *collections.IndexedMap[uint64, types.Dispute, DisputesIndex] // key: dispute id + Votes collections.Map[uint64, types.Vote] // key: dispute id + Voter *collections.IndexedMap[collections.Pair[uint64, []byte], types.Voter, VotersVoteIndex] // key: dispute id + voter address + ReportersWithDelegatorsVotedBefore collections.Map[collections.Pair[[]byte, uint64], math.Int] // key: reporter address + dispute id + BlockInfo collections.Map[[]byte, types.BlockInfo] // key: dispute.HashId + DisputeFeePayer collections.Map[collections.Pair[uint64, []byte], types.PayerInfo] // key: dispute id + payer address // dust is extra tokens leftover after truncating decimals, stored as fixed256x12 Dust collections.Item[math.Int] - VoteCountsByGroup collections.Map[uint64, types.StakeholderVoteCounts] + VoteCountsByGroup collections.Map[uint64, types.StakeholderVoteCounts] // key: dispute id } ) @@ -57,24 +54,40 @@ func NewKeeper( ) Keeper { sb := collections.NewSchemaBuilder(storeService) return Keeper{ - cdc: cdc, - Params: collections.NewItem(sb, types.ParamsKeyPrefix(), "params", codec.CollValue[types.Params](cdc)), - storeService: storeService, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, - oracleKeeper: oracleKeeper, - reporterKeeper: reporterKeeper, - Disputes: collections.NewIndexedMap(sb, types.DisputesPrefix, "disputes", collections.Uint64Key, codec.CollValue[types.Dispute](cdc), NewDisputesIndex(sb)), - Votes: collections.NewMap(sb, types.VotesPrefix, "votes", collections.Uint64Key, codec.CollValue[types.Vote](cdc)), - Voter: collections.NewIndexedMap(sb, types.VoterVotePrefix, "voter_vote", collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), codec.CollValue[types.Voter](cdc), NewVotersIndex(sb)), - ReportersWithDelegatorsVotedBefore: collections.NewMap(sb, types.ReportersWithDelegatorsVotedBeforePrefix, "reporters_with_delegators_voted_before", collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key), sdk.IntValue), - ReportersGroup: collections.NewMap(sb, types.ReporterPowerIndexPrefix, "reporters_group", collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), sdk.IntValue), - TeamVoter: collections.NewMap(sb, types.TeamVoterPrefix, "team_voter", collections.Uint64Key, collections.BoolValue), - UsersGroup: collections.NewMap(sb, types.UsersGroupPrefix, "users_group", collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), sdk.IntValue), - BlockInfo: collections.NewMap(sb, types.BlockInfoPrefix, "block_info", collections.BytesKey, codec.CollValue[types.BlockInfo](cdc)), - DisputeFeePayer: collections.NewMap(sb, types.DisputeFeePayerPrefix, "dispute_fee_payer", collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), codec.CollValue[types.PayerInfo](cdc)), - Dust: collections.NewItem(sb, types.DustKeyPrefix, "dust", sdk.IntValue), - VoteCountsByGroup: collections.NewMap(sb, types.VoteCountsByGroupPrefix, "vote_counts_by_group", collections.Uint64Key, codec.CollValue[types.StakeholderVoteCounts](cdc)), + cdc: cdc, + Params: collections.NewItem(sb, types.ParamsKeyPrefix(), "params", codec.CollValue[types.Params](cdc)), + storeService: storeService, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + oracleKeeper: oracleKeeper, + reporterKeeper: reporterKeeper, + // maps dispute id to dispute, and indexes disputes by reporter, open status, and pending execution + Disputes: collections.NewIndexedMap(sb, types.DisputesPrefix, "disputes", collections.Uint64Key, codec.CollValue[types.Dispute](cdc), NewDisputesIndex(sb)), + // maps dispute id to vote + Votes: collections.NewMap(sb, types.VotesPrefix, "votes", collections.Uint64Key, codec.CollValue[types.Vote](cdc)), + // maps dispute id + voter address to voter's vote info and indexes voters by id, used for tallying votes + Voter: collections.NewIndexedMap(sb, + types.VoterVotePrefix, + "voter_vote", + collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), + codec.CollValue[types.Voter](cdc), + NewVotersIndex(sb), + ), + // maps reporter address + dispute id to reporter's stake - selectors' belonging to the reporter share that individually voted + ReportersWithDelegatorsVotedBefore: collections.NewMap(sb, + types.ReportersWithDelegatorsVotedBeforePrefix, + "reporters_with_delegators_voted_before", + collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key), + sdk.IntValue, + ), + // maps dispute hash to block info, stores total reporting stake and total user tips at the time of dispute start + BlockInfo: collections.NewMap(sb, types.BlockInfoPrefix, "block_info", collections.BytesKey, codec.CollValue[types.BlockInfo](cdc)), + // maps dispute id + payer address to payer info, used to track who paid the dispute fee, how much and how (ie from stake or not) + DisputeFeePayer: collections.NewMap(sb, types.DisputeFeePayerPrefix, "dispute_fee_payer", collections.PairKeyCodec(collections.Uint64Key, collections.BytesKey), codec.CollValue[types.PayerInfo](cdc)), + // a place to store dust fractions of tokens that remains during fee refunds, burned when they become whole amounts + Dust: collections.NewItem(sb, types.DustKeyPrefix, "dust", sdk.IntValue), + // maps dispute id to voter groups' vote counts, used to tally votes + VoteCountsByGroup: collections.NewMap(sb, types.VoteCountsByGroupPrefix, "vote_counts_by_group", collections.Uint64Key, codec.CollValue[types.StakeholderVoteCounts](cdc)), } } diff --git a/x/dispute/keeper/vote.go b/x/dispute/keeper/vote.go index 3445911ce..f36e8368b 100644 --- a/x/dispute/keeper/vote.go +++ b/x/dispute/keeper/vote.go @@ -32,19 +32,6 @@ func (k Keeper) SetStartVote(ctx sdk.Context, id uint64) error { return k.Votes.Set(ctx, id, vote) } -func (k Keeper) TeamVote(ctx context.Context, id uint64) (math.Int, error) { - teamTally := math.ZeroInt() - voted, err := k.TeamVoter.Has(ctx, id) - if err != nil { - return math.Int{}, err - } - if voted { - teamTally = math.OneInt() - } - - return teamTally, nil -} - func (k Keeper) GetTeamAddress(ctx context.Context) (sdk.AccAddress, error) { params, err := k.Params.Get(ctx) if err != nil { @@ -79,7 +66,7 @@ func (k Keeper) SetTeamVote(ctx context.Context, id uint64, voter sdk.AccAddress if err != nil { return math.Int{}, err } - return math.NewInt(25000000), k.TeamVoter.Set(ctx, id, true) + return math.NewInt(25000000), nil } return math.ZeroInt(), nil } @@ -119,7 +106,7 @@ func (k Keeper) SetVoterTips(ctx context.Context, id uint64, voter sdk.AccAddres if err != nil { return math.Int{}, err } - return tips, k.UsersGroup.Set(ctx, collections.Join(id, voter.Bytes()), tips) + return tips, nil } return math.ZeroInt(), nil } diff --git a/x/dispute/keeper/vote_test.go b/x/dispute/keeper/vote_test.go index 4c89f7703..0eaa5d1c3 100644 --- a/x/dispute/keeper/vote_test.go +++ b/x/dispute/keeper/vote_test.go @@ -64,10 +64,6 @@ func (s *KeeperTestSuite) TestTeamVote_SetTeamVote() { ctx := s.ctx disputeId := uint64(1) - // team has not voted, expect 0 - teamTally, err := k.TeamVote(ctx, disputeId) - require.NoError(err) - require.Equal(teamTally, math.NewInt(0)) // team votes SUPPORT, expect return 25000000 teamAddr, err := k.GetTeamAddress(ctx) @@ -76,9 +72,6 @@ func (s *KeeperTestSuite) TestTeamVote_SetTeamVote() { require.NoError(err) require.Equal(teamVote, math.NewInt(25000000)) // check on vote - voted, err := k.TeamVoter.Get(ctx, disputeId) - require.True(voted) - require.NoError(err) votesByGroup, err := k.VoteCountsByGroup.Get(ctx, disputeId) require.Equal(votesByGroup.Team.Against, uint64(0)) require.Equal(votesByGroup.Team.Support, uint64(1)) @@ -299,7 +292,6 @@ func (s *KeeperTestSuite) TestSetVoterReportStake() { rk.On("Delegation", ctx, selector).Return(reportertypes.Selection{ Reporter: reporter, }, nil).Once() - require.NoError(k.ReportersGroup.Set(ctx, collections.Join(disputeId, reporter.Bytes()), math.NewInt(50))) // selector has 100 selected to reporter rk.On("GetDelegatorTokensAtBlock", ctx, selector.Bytes(), blockNum).Return(math.NewInt(100), nil).Once() // reporter has voted against with 150