From 0833b565b53f421bd857a17aaf087145ec443f09 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:48:31 -0600 Subject: [PATCH] add test to check bug (#481) (#483) * add test to check bug * mv conditional to top * fix right pool to send to (#482) * send to right pool * remove todo comment * remove comment (cherry picked from commit e875ac47d15afb13a725a615ea74fe87c8b314fe) Co-authored-by: akrem <71235284+akremstudy@users.noreply.github.com> --- app/app.go | 28 ++- tests/integration/dispute_keeper_test.go | 246 +++++++++++++++++++++++ tests/integration/keeper_test.go | 41 ++++ tests/setup.go | 4 +- x/dispute/keeper/dispute_fee.go | 4 +- x/dispute/keeper/dispute_fee_test.go | 5 +- x/dispute/mocks/ReporterKeeper.go | 20 +- x/dispute/types/expected_keepers.go | 2 +- x/reporter/keeper/distribution.go | 18 +- x/reporter/keeper/distribution_test.go | 4 +- 10 files changed, 349 insertions(+), 23 deletions(-) diff --git a/app/app.go b/app/app.go index ec8f84cad..e3d96b4c7 100644 --- a/app/app.go +++ b/app/app.go @@ -80,6 +80,7 @@ import ( "cosmossdk.io/client/v2/autocli" "cosmossdk.io/core/appmodule" "cosmossdk.io/log" + "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/evidence" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -1001,12 +1002,37 @@ func (app *App) setAnteHandler(txConfig client.TxConfig) { app.SetAnteHandler(anteHandler) } -func (app *App) preBlocker(ph *ProposalHandler) func(sdk.Context, *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { +func (app *App) preBlocker(ph *ProposalHandler) func(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { return func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { res, err := app.ModuleManager().PreBlock(ctx) if err != nil { return nil, err } + if ctx.BlockHeight() == 1062219+1 { + bondedPoolBal := app.BankKeeper.GetBalance(ctx, authtypes.NewModuleAddress(stakingtypes.BondedPoolName), "loya") + vals, err := app.StakingKeeper.GetValidators(ctx, 7) // only 6 validators exist + if err != nil { + return nil, err + } + bondedtotal := math.ZeroInt() + notbondedtotal := math.ZeroInt() + for _, v := range vals { + if v.IsBonded() { + bondedtotal = bondedtotal.Add(v.Tokens) + } else { + notbondedtotal = notbondedtotal.Add(v.Tokens) + } + } + // transfer amount should be 1950000000 + // "spendable balance 97171770000loya is smaller than 99121770000loya + transferAmt := bondedPoolBal.Amount.Sub(bondedtotal) + if transferAmt.Equal(math.NewInt(1950000000)) { // manually checked amount + err = app.BankKeeper.SendCoinsFromModuleToModule(ctx, stakingtypes.BondedPoolName, stakingtypes.NotBondedPoolName, sdk.NewCoins(sdk.NewCoin("loya", transferAmt))) + if err != nil { + return nil, err + } + } + } changed := res.ConsensusParamsChanged diff --git a/tests/integration/dispute_keeper_test.go b/tests/integration/dispute_keeper_test.go index 4d93f4b00..50138e121 100644 --- a/tests/integration/dispute_keeper_test.go +++ b/tests/integration/dispute_keeper_test.go @@ -6,7 +6,9 @@ import ( "fmt" "time" + abci "github.com/cometbft/cometbft/abci/types" "github.com/tellor-io/layer/testutil" + "github.com/tellor-io/layer/utils" "github.com/tellor-io/layer/x/dispute" "github.com/tellor-io/layer/x/dispute/keeper" "github.com/tellor-io/layer/x/dispute/types" @@ -18,7 +20,12 @@ import ( "cosmossdk.io/collections" "cosmossdk.io/math" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) func (s *IntegrationTestSuite) TestVotingOnDispute() { @@ -1152,3 +1159,242 @@ func (s *IntegrationTestSuite) TestAddFeeToDisputeBond() { s.NoError(err) s.Equal(feePayerStakeBefore.Sub(disputeFee.QuoRaw(2)), feePayerStakeAfter) } + +func (s *IntegrationTestSuite) TestCurrentBug() { + ctx := s.Setup.Ctx + ctx = ctx.WithBlockHeight(1) + sk := s.Setup.Stakingkeeper + startingBondedPoolbal := math.NewInt(1000000) + params := slashingtypes.DefaultParams() + params.SignedBlocksWindow = 1 + notbondedpool := authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName) + bondedpool := authtypes.NewModuleAddress(stakingtypes.BondedPoolName) + + s.NoError(s.Setup.SlashingKeeper.SetParams(ctx, params)) + msgServer := keeper.NewMsgServerImpl(s.Setup.Disputekeeper) + oServer := oraclekeeper.NewMsgServerImpl(s.Setup.Oraclekeeper) + + // chain has three validators + repAccs, valAccs, _ := s.createValidatorsbypowers([]uint64{150, 500, 100000}) + // staking pool balances + // not bonded pool + bal, err := s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(notbondedpool, "loya")) + s.Error(err, "balance should be zero") + s.True(bal.IsNil()) + // bonded poool + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(bondedpool, "loya")) + s.NoError(err, "balance should be gt zero") + s.Equal(sk.PowerReduction(ctx).MulRaw(int64(150+500+100000)).Add(startingBondedPoolbal), bal) + + // give disputer tokens + s.Setup.MintTokens(repAccs[1], math.NewInt(100000000000)) + // bridge endBlock stuff + for _, val := range valAccs { + err := s.Setup.Bridgekeeper.SetEVMAddressByOperator(s.Setup.Ctx, val.String(), []byte("not real")) + s.NoError(err) + } + + // create reporter and submit reports + reportBlock := ctx.BlockHeight() + for _, r := range repAccs { + s.NoError(s.Setup.Reporterkeeper.Reporters.Set(ctx, r, reportertypes.NewReporter(reportertypes.DefaultMinCommissionRate, math.OneInt()))) + s.NoError(s.Setup.Reporterkeeper.Selectors.Set(ctx, r, reportertypes.NewSelection(r, 1))) + rep := report(r.String(), testutil.EncodeValue(29266), ethQueryData) + _, err := oServer.SubmitValue(ctx, &rep) + s.NoError(err) + } + + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + // propose dispute id 1 slash amount 10_000_000 + _, err = msgServer.ProposeDispute(ctx, &types.MsgProposeDispute{ + Creator: repAccs[1].String(), + Report: &oracletypes.MicroReport{ + Reporter: repAccs[2].String(), + Power: 100000, + QueryType: "SpotPrice", + QueryId: utils.QueryIDFromData(ethQueryData), + AggregateMethod: "weighted-median", + Value: testutil.EncodeValue(29266), + Cyclelist: false, + BlockNumber: uint64(reportBlock), + }, + DisputeCategory: types.Warning, + Fee: sdk.NewCoin(s.Setup.Denom, math.NewInt(1000_000_000)), // one percent dispute fee + PayFromBond: false, + }) + s.NoError(err) + // check dispute status + dispute, err := s.Setup.Disputekeeper.Disputes.Get(ctx, 1) + s.NoError(err) + s.Equal(types.Voting, dispute.DisputeStatus) + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + // check pool bals after first dispute + notbondedpool = authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName) + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(notbondedpool, "loya")) + s.Error(err, "balance should be zero") + s.True(bal.IsNil()) + + // bonded pool + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(bondedpool, "loya")) + s.NoError(err, "balance should be gt zero") + s.Equal(sk.PowerReduction(ctx).MulRaw(int64(150+500+99000)).Add(startingBondedPoolbal), bal) + + // propose dispute id 2 slash amount 2_000_000 + _, err = msgServer.ProposeDispute(ctx, &types.MsgProposeDispute{ + Creator: repAccs[1].String(), + Report: &oracletypes.MicroReport{ + Reporter: repAccs[0].String(), + Power: 150, + QueryType: "SpotPrice", + QueryId: utils.QueryIDFromData(ethQueryData), + AggregateMethod: "weighted-median", + Value: testutil.EncodeValue(29266), + Cyclelist: false, + BlockNumber: uint64(reportBlock), + }, + DisputeCategory: types.Warning, + Fee: sdk.NewCoin(s.Setup.Denom, math.NewInt(2_000_000)), // one percent dispute fee + PayFromBond: false, + }) + s.NoError(err) + + // check dispute status 2 + dispute, err = s.Setup.Disputekeeper.Disputes.Get(ctx, 2) + s.NoError(err) + s.Equal(types.Voting, dispute.DisputeStatus) + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + notbondedpool = authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName) + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(notbondedpool, "loya")) + s.Error(err, "balance should be zero") + s.True(bal.IsNil()) + + voteinfos := []abci.VoteInfo{ + { + Validator: abci.Validator{ + Address: valAccs[0], + Power: 149, + }, + }, + { + Validator: abci.Validator{ + Address: valAccs[1], + Power: 4000, + }, + }, + { + Validator: abci.Validator{ + Address: valAccs[2], + Power: 99000, + }, + }, + } + + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + // during a dispute two validators are jailed (validator slashing) + val1, err := s.Setup.Stakingkeeper.GetValidator(ctx, valAccs[0]) // reporter + s.NoError(err) + consAddr1, err := val1.GetConsAddr() + s.NoError(err) + signinginfor1, err := s.Setup.SlashingKeeper.GetValidatorSigningInfo(ctx, consAddr1) + s.NoError(err) + signinginfor1.MissedBlocksCounter = 2 + signinginfor1.StartHeight = 1 + s.NoError(s.Setup.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr1, signinginfor1)) + + val2, err := s.Setup.Stakingkeeper.GetValidator(ctx, valAccs[2]) // reporter + s.NoError(err) + + consAddr2, err := val2.GetConsAddr() + s.NoError(err) + signinginfor2, err := s.Setup.SlashingKeeper.GetValidatorSigningInfo(ctx, consAddr2) + s.NoError(err) + signinginfor2.MissedBlocksCounter = 2 + signinginfor1.StartHeight = 1 + s.NoError(s.Setup.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr2, signinginfor2)) + + // move blocks ahead so that they are jailed/slashed + ctx = ctx.WithVoteInfos(voteinfos) + _, err = s.Setup.App.BeginBlocker(ctx) + s.NoError(err) + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + // both validators jailed + val1, err = s.Setup.Stakingkeeper.GetValidator(ctx, valAccs[0]) // reporter + s.NoError(err) + s.True(val1.Jailed) + val2, err = s.Setup.Stakingkeeper.GetValidator(ctx, valAccs[2]) // reporter + s.NoError(err) + s.True(val2.Jailed) + + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(notbondedpool, "loya")) + s.NoError(err, "balance should be gt zero since validators were jailed") + s.True(bal.GT(math.ZeroInt()), "amount should be tokens minus the slashed amount, val 0 and val 2 got slashed 1 percen") + s.Equal(math.NewInt(int64(147010000+98010000000)), bal) // 147010000 precision ?? should be 147015000 + votes := []types.MsgVote{ + { + Voter: repAccs[1].String(), + Id: 1, + Vote: types.VoteEnum_VOTE_AGAINST, + }, + } + for i := range votes { + _, err = msgServer.Vote(ctx, &votes[i]) + s.NoError(err) + } + + votes = []types.MsgVote{ + { + Voter: repAccs[1].String(), + Id: 2, + Vote: types.VoteEnum_VOTE_AGAINST, + }, + } + for i := range votes { + _, err = msgServer.Vote(ctx, &votes[i]) + s.NoError(err) + } + + ctx = ctx.WithBlockTime(ctx.BlockTime().Add(time.Hour * 72)) + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + dispute, err = s.Setup.Disputekeeper.Disputes.Get(ctx, 1) + s.NoError(err) + s.Equal(dispute.DisputeStatus, types.Resolved) + vote, err := s.Setup.Disputekeeper.Votes.Get(ctx, 1) + s.NoError(err) + s.Equal(vote.VoteResult, types.VoteResult_NO_QUORUM_MAJORITY_AGAINST) + dispute, err = s.Setup.Disputekeeper.Disputes.Get(ctx, 2) + s.NoError(err) + s.Equal(dispute.DisputeStatus, types.Resolved) + vote, err = s.Setup.Disputekeeper.Votes.Get(ctx, 2) + s.NoError(err) + s.Equal(vote.VoteResult, types.VoteResult_NO_QUORUM_MAJORITY_AGAINST) + // unjail validator 1 + slashingServer := slashingkeeper.NewMsgServerImpl(s.Setup.SlashingKeeper) + _, err = slashingServer.Unjail(ctx, slashingtypes.NewMsgUnjail(valAccs[2].String())) + s.NoError(err) + + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + + _, err = slashingServer.Unjail(ctx, slashingtypes.NewMsgUnjail(valAccs[0].String())) + s.NoError(err) + + ctx, err = simtestutil.NextBlock(s.Setup.App, ctx, time.Minute) + s.NoError(err) + // should be back to zero/nil + bal, err = s.Setup.Bankkeeper.Balances.Get(ctx, collections.Join(notbondedpool, "loya")) + s.Error(err, "balance should be zero") + s.True(bal.IsNil()) +} diff --git a/tests/integration/keeper_test.go b/tests/integration/keeper_test.go index e29178e26..bd5fcd689 100644 --- a/tests/integration/keeper_test.go +++ b/tests/integration/keeper_test.go @@ -64,6 +64,7 @@ func CreateRandomPrivateKeys(accNum int) []ed25519.PrivKey { return testAddrs } +// todo: remove this func (s *IntegrationTestSuite) createValidatorAccs(powers []uint64) ([]sdk.AccAddress, []sdk.ValAddress, []ed25519.PrivKey) { ctx := s.Setup.Ctx acctNum := len(powers) @@ -123,6 +124,46 @@ func (s *IntegrationTestSuite) CreateAccountsWithTokens(numofAccs int, amountOfT return accs } +func (s *IntegrationTestSuite) createValidatorsbypowers(powers []uint64) ([]sdk.AccAddress, []sdk.ValAddress, []ed25519.PrivKey) { + ctx := s.Setup.Ctx + acctNum := len(powers) + privKeys := CreateRandomPrivateKeys(acctNum) + testAddrs := s.Setup.ConvertToAccAddress(privKeys) + for i, addr := range testAddrs { + s.Setup.MintTokens(addr, math.NewInt(int64(powers[i]*1000000))) + } + valAddrs := simtestutil.ConvertAddrsToValAddrs(testAddrs) + stakingServer := stakingkeeper.NewMsgServerImpl(s.Setup.Stakingkeeper) + for i, pk := range privKeys { + account := authtypes.BaseAccount{ + Address: testAddrs[i].String(), + PubKey: codectypes.UnsafePackAny(pk.PubKey()), + AccountNumber: uint64(i + 100), + } + s.Setup.Accountkeeper.SetAccount(s.Setup.Ctx, &account) + valMsg, err := stakingtypes.NewMsgCreateValidator( + valAddrs[i].String(), + pk.PubKey(), + sdk.NewInt64Coin(s.Setup.Denom, s.Setup.Stakingkeeper.TokensFromConsensusPower(ctx, int64(powers[i])).Int64()), + stakingtypes.Description{Moniker: strconv.Itoa(i)}, + stakingtypes.CommissionRates{ + Rate: math.LegacyNewDecWithPrec(5, 1), + MaxRate: math.LegacyNewDecWithPrec(5, 1), + MaxChangeRate: math.LegacyNewDec(0), + }, + math.OneInt()) + s.NoError(err) + + _, err = stakingServer.CreateValidator(s.Setup.Ctx, valMsg) + s.NoError(err) + } + + _, err := s.Setup.Stakingkeeper.EndBlocker(ctx) + s.NoError(err) + + return testAddrs, valAddrs, privKeys +} + func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } diff --git a/tests/setup.go b/tests/setup.go index 3d22f0cfe..c7e40fcaf 100644 --- a/tests/setup.go +++ b/tests/setup.go @@ -205,7 +205,7 @@ type SharedSetup struct { Accountkeeper authkeeper.AccountKeeper Bankkeeper bankkeeper.BaseKeeper distrKeeper distrkeeper.Keeper - slashingKeeper slashingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper Stakingkeeper *stakingkeeper.Keeper Govkeeper *govkeeper.Keeper Ctx sdk.Context @@ -249,7 +249,7 @@ func (s *SharedSetup) SetupTest(t *testing.T) { depinject.Supply(log.NewNopLogger()), ), DefaultStartUpConfig(), - &s.Accountkeeper, &s.Bankkeeper, &s.Stakingkeeper, &s.slashingKeeper, &s.interfaceRegistry, + &s.Accountkeeper, &s.Bankkeeper, &s.Stakingkeeper, &s.SlashingKeeper, &s.interfaceRegistry, &s.appCodec, &s.authConfig, &s.Oraclekeeper, &s.Mintkeeper, &s.Bridgekeeper, &s.GlobalFeekeeper, &s.Disputekeeper, &s.Registrykeeper, &s.Govkeeper, &s.distrKeeper, &s.Reporterkeeper) require.NoError(t, err) diff --git a/x/dispute/keeper/dispute_fee.go b/x/dispute/keeper/dispute_fee.go index a679ff709..93ef6b791 100644 --- a/x/dispute/keeper/dispute_fee.go +++ b/x/dispute/keeper/dispute_fee.go @@ -48,13 +48,13 @@ func (k Keeper) PayDisputeFee(ctx sdk.Context, proposer sdk.AccAddress, fee sdk. // return slashed tokens when reporter either wins dispute or dispute is invalid func (k Keeper) ReturnSlashedTokens(ctx context.Context, dispute types.Dispute) error { - err := k.reporterKeeper.ReturnSlashedTokens(ctx, dispute.SlashAmount, dispute.HashId) + pool, err := k.reporterKeeper.ReturnSlashedTokens(ctx, dispute.SlashAmount, dispute.HashId) if err != nil { return err } coins := sdk.NewCoins(sdk.NewCoin(layertypes.BondDenom, dispute.SlashAmount)) - return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, stakingtypes.BondedPoolName, coins) + return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, pool, coins) } func (k Keeper) ReturnFeetoStake(ctx context.Context, hashId []byte, remainingAmt math.Int) error { diff --git a/x/dispute/keeper/dispute_fee_test.go b/x/dispute/keeper/dispute_fee_test.go index ebdde9f8d..6dbcd616d 100644 --- a/x/dispute/keeper/dispute_fee_test.go +++ b/x/dispute/keeper/dispute_fee_test.go @@ -44,8 +44,9 @@ func (s *KeeperTestSuite) TestPayDisputeFee() { func (k *KeeperTestSuite) TestReturnSlashedTokens() { dispute := k.dispute() - k.reporterKeeper.On("ReturnSlashedTokens", k.ctx, dispute.SlashAmount, dispute.HashId).Return(nil) - k.bankKeeper.On("SendCoinsFromModuleToModule", k.ctx, types.ModuleName, stakingtypes.BondedPoolName, sdk.NewCoins(sdk.NewCoin(layer.BondDenom, dispute.SlashAmount))).Return(nil) + pool := stakingtypes.BondedPoolName + k.reporterKeeper.On("ReturnSlashedTokens", k.ctx, dispute.SlashAmount, dispute.HashId).Return(pool, nil) + k.bankKeeper.On("SendCoinsFromModuleToModule", k.ctx, types.ModuleName, pool, sdk.NewCoins(sdk.NewCoin(layer.BondDenom, dispute.SlashAmount))).Return(nil) k.NoError(k.disputeKeeper.ReturnSlashedTokens(k.ctx, dispute)) } diff --git a/x/dispute/mocks/ReporterKeeper.go b/x/dispute/mocks/ReporterKeeper.go index b2cb5e1b0..86552b83f 100644 --- a/x/dispute/mocks/ReporterKeeper.go +++ b/x/dispute/mocks/ReporterKeeper.go @@ -162,17 +162,27 @@ func (_m *ReporterKeeper) JailReporter(ctx context.Context, reporterAddr types.A } // ReturnSlashedTokens provides a mock function with given fields: ctx, amt, hashId -func (_m *ReporterKeeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) error { +func (_m *ReporterKeeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) (string, error) { ret := _m.Called(ctx, amt, hashId) - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, math.Int, []byte) error); ok { + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, math.Int, []byte) (string, error)); ok { + return rf(ctx, amt, hashId) + } + if rf, ok := ret.Get(0).(func(context.Context, math.Int, []byte) string); ok { r0 = rf(ctx, amt, hashId) } else { - r0 = ret.Error(0) + r0 = ret.Get(0).(string) } - return r0 + if rf, ok := ret.Get(1).(func(context.Context, math.Int, []byte) error); ok { + r1 = rf(ctx, amt, hashId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } // TotalReporterPower provides a mock function with given fields: ctx diff --git a/x/dispute/types/expected_keepers.go b/x/dispute/types/expected_keepers.go index bfaa800a6..6bacfc77f 100644 --- a/x/dispute/types/expected_keepers.go +++ b/x/dispute/types/expected_keepers.go @@ -46,7 +46,7 @@ type ReporterKeeper interface { JailReporter(ctx context.Context, reporterAddr sdk.AccAddress, jailDuration uint64) error TotalReporterPower(ctx context.Context) (math.Int, error) FeefromReporterStake(ctx context.Context, reporterAddr sdk.AccAddress, amt math.Int, hashId []byte) error - ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) error + ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) (string, error) AddAmountToStake(ctx context.Context, acc sdk.AccAddress, amt math.Int) error Delegation(ctx context.Context, delegator sdk.AccAddress) (reportertypes.Selection, error) GetReporterTokensAtBlock(ctx context.Context, reporter []byte, blockNumber uint64) (math.Int, error) diff --git a/x/reporter/keeper/distribution.go b/x/reporter/keeper/distribution.go index 7587c10a4..5aff3ffa1 100644 --- a/x/reporter/keeper/distribution.go +++ b/x/reporter/keeper/distribution.go @@ -13,11 +13,12 @@ import ( // ReturnSlashedTokens returns the slashed tokens to the delegators, // called in dispute module after dispute is resolved with result invalid or reporter wins -func (k Keeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) error { +func (k Keeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId []byte) (string, error) { + var pool string // get the snapshot of the metadata of the tokens that were slashed ie selectors' shares amounts and validator they were delegated to snapshot, err := k.DisputedDelegationAmounts.Get(ctx, hashId) if err != nil { - return err + return "", err } // winningpurse represents the amount of tokens that a disputed reporter possibly receives for winning a dispute @@ -31,15 +32,15 @@ func (k Keeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId [] val, err = k.stakingKeeper.GetValidator(ctx, valAddr) if err != nil { if !errors.Is(err, stakingtypes.ErrNoValidatorFound) { - return err + return "", err } vals, err := k.GetBondedValidators(ctx, 1) if err != nil { - return err + return "", err } // this should never happen since there should always be a bonded validator if len(vals) == 0 { - return errors.New("no validators found in staking module to return tokens to") + return "", errors.New("no validators found in staking module to return tokens to") } val = vals[0] } @@ -59,16 +60,17 @@ func (k Keeper) ReturnSlashedTokens(ctx context.Context, amt math.Int, hashId [] var tokenSrc stakingtypes.BondStatus if val.IsBonded() { tokenSrc = stakingtypes.Bonded + pool = stakingtypes.BondedPoolName } else { tokenSrc = stakingtypes.Unbonded + pool = stakingtypes.NotBondedPoolName } _, err = k.stakingKeeper.Delegate(ctx, delAddr, shareAmt.TruncateInt(), tokenSrc, val, false) // false means to not subtract tokens from an account if err != nil { - return err + return "", err } } - - return k.DisputedDelegationAmounts.Remove(ctx, hashId) + return pool, k.DisputedDelegationAmounts.Remove(ctx, hashId) } // called in dispute module after dispute is resolved diff --git a/x/reporter/keeper/distribution_test.go b/x/reporter/keeper/distribution_test.go index ab88518ed..33fc83ad6 100644 --- a/x/reporter/keeper/distribution_test.go +++ b/x/reporter/keeper/distribution_test.go @@ -76,8 +76,8 @@ func TestReturnSlashedTokens(t *testing.T) { sk.On("GetValidator", ctx, val2Address).Return(validator2, nil) sk.On("Delegate", ctx, delAddr1, tokenOrigin1.Amount, stakingtypes.Bonded, validator1, false).Return(math.LegacyZeroDec(), nil) sk.On("Delegate", ctx, delAddr2, tokenOrigin2.Amount, stakingtypes.Bonded, validator2, false).Return(math.LegacyZeroDec(), nil) - - require.NoError(t, k.ReturnSlashedTokens(ctx, math.NewIntWithDecimal(2000, 6), []byte("hashId"))) + _, err = k.ReturnSlashedTokens(ctx, math.NewIntWithDecimal(2000, 6), []byte("hashId")) + require.NoError(t, err) } func TestFeeRefund(t *testing.T) {