mirror of
https://github.com/planetmint/planetmint-go.git
synced 2025-07-04 19:52:30 +00:00
feat: add unresolved claim cleanup (#460)
Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
parent
764d1158dc
commit
0bd6964d3e
@ -10,9 +10,11 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
"github.com/planetmint/planetmint-go/lib"
|
"github.com/planetmint/planetmint-go/lib"
|
||||||
"github.com/planetmint/planetmint-go/monitor"
|
"github.com/planetmint/planetmint-go/monitor"
|
||||||
"github.com/planetmint/planetmint-go/testutil"
|
"github.com/planetmint/planetmint-go/testutil"
|
||||||
@ -85,6 +87,17 @@ func (s *SelectionE2ETestSuite) SetupSuite() {
|
|||||||
daoGenState.Params.ClaimAddress = valAddr.String()
|
daoGenState.Params.ClaimAddress = valAddr.String()
|
||||||
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
|
s.cfg.GenesisState[daotypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&daoGenState)
|
||||||
|
|
||||||
|
// setting up stagedClaims that are not part of PoP issuance (i.e.: past unresolved claims)
|
||||||
|
machineBalances := []banktypes.Balance{
|
||||||
|
{Address: machines[0].address, Coins: sdk.NewCoins(sdk.NewCoin(daoGenState.Params.StagedDenom, sdkmath.NewInt(10000)))},
|
||||||
|
{Address: machines[1].address, Coins: sdk.NewCoins(sdk.NewCoin(daoGenState.Params.StagedDenom, sdkmath.NewInt(10000)))},
|
||||||
|
}
|
||||||
|
|
||||||
|
var bankGenState banktypes.GenesisState
|
||||||
|
s.cfg.Codec.MustUnmarshalJSON(s.cfg.GenesisState[banktypes.ModuleName], &bankGenState)
|
||||||
|
bankGenState.Balances = append(bankGenState.Balances, machineBalances...)
|
||||||
|
s.cfg.GenesisState[banktypes.ModuleName] = s.cfg.Codec.MustMarshalJSON(&bankGenState)
|
||||||
|
|
||||||
s.network = network.Load(s.T(), s.cfg)
|
s.network = network.Load(s.T(), s.cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +211,7 @@ func (s *SelectionE2ETestSuite) VerifyTokens(token string) {
|
|||||||
})
|
})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
assert.Contains(s.T(), out.String(), token)
|
assert.Contains(s.T(), out.String(), token)
|
||||||
assert.Equal(s.T(), "amount: \"18279452050\"\ndenom: "+token+"\n", out.String()) // Total supply 2 * 7990867578 (total supply) + 1 * 1997716894 (challenger) + 3 * 100000000 (validator) = 17979452050
|
assert.Equal(s.T(), "amount: \"18279472050\"\ndenom: "+token+"\n", out.String()) // Total supply 2 * 7990867578 (total supply) + 1 * 1997716894 (challenger) + 3 * 100000000 (validator) + 2 * 10000 (past unresolved claims) = 17979472050
|
||||||
|
|
||||||
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
||||||
machines[0].address,
|
machines[0].address,
|
||||||
@ -206,7 +219,7 @@ func (s *SelectionE2ETestSuite) VerifyTokens(token string) {
|
|||||||
})
|
})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
assert.Contains(s.T(), out.String(), token)
|
assert.Contains(s.T(), out.String(), token)
|
||||||
assert.Equal(s.T(), "amount: \"5993150682\"\ndenom: "+token+"\n", out.String()) // 3 * 1997716894 = 5993150682
|
assert.Equal(s.T(), "amount: \"5993160682\"\ndenom: "+token+"\n", out.String()) // 3 * 1997716894 + 1 * 10000= 5993160682
|
||||||
|
|
||||||
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
||||||
machines[1].address,
|
machines[1].address,
|
||||||
@ -214,7 +227,7 @@ func (s *SelectionE2ETestSuite) VerifyTokens(token string) {
|
|||||||
})
|
})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
assert.Contains(s.T(), out.String(), token)
|
assert.Contains(s.T(), out.String(), token)
|
||||||
assert.Equal(s.T(), "amount: \"11986301368\"\ndenom: "+token+"\n", out.String()) // 2 * 5993150684 = 11986301368
|
assert.Equal(s.T(), "amount: \"11986311368\"\ndenom: "+token+"\n", out.String()) // 2 * 5993150684 + 1 * 10000 = 11986311368
|
||||||
|
|
||||||
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, bank.GetBalancesCmd(), []string{
|
||||||
val.Address.String(),
|
val.Address.String(),
|
||||||
@ -320,11 +333,11 @@ func (s *SelectionE2ETestSuite) TestTokenRedeemClaim() {
|
|||||||
// QueryRedeemClaim
|
// QueryRedeemClaim
|
||||||
qOut, err := clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdShowRedeemClaim(), []string{"liquidAddress", "0"})
|
qOut, err := clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdShowRedeemClaim(), []string{"liquidAddress", "0"})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993150682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
|
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993160682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
|
||||||
|
|
||||||
qOut, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdRedeemClaimByLiquidTxHash(), []string{"0000000000000000000000000000000000000000000000000000000000000000"})
|
qOut, err = clitestutil.ExecTestCLICmd(val.ClientCtx, daocli.CmdRedeemClaimByLiquidTxHash(), []string{"0000000000000000000000000000000000000000000000000000000000000000"})
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993150682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
|
assert.Equal(s.T(), "redeemClaim:\n amount: \"5993160682\"\n beneficiary: liquidAddress\n confirmed: true\n creator: plmnt1kp93kns6hs2066d8qw0uz84fw3vlthewt2ck6p\n id: \"0\"\n liquidTxHash: \"0000000000000000000000000000000000000000000000000000000000000000\"\n", qOut.String())
|
||||||
|
|
||||||
// Make sure "Publish" has been called with PoPInit cmnd
|
// Make sure "Publish" has been called with PoPInit cmnd
|
||||||
calls := mocks.GetCallLog()
|
calls := mocks.GetCallLog()
|
||||||
|
@ -2,6 +2,7 @@ package keeper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
errorsmod "cosmossdk.io/errors"
|
errorsmod "cosmossdk.io/errors"
|
||||||
@ -26,6 +27,10 @@ func (k msgServer) DistributionResult(goCtx context.Context, msg *types.MsgDistr
|
|||||||
distribution.EarlyInvAddr = msg.EarlyInvestorTxID
|
distribution.EarlyInvAddr = msg.EarlyInvestorTxID
|
||||||
distribution.StrategicTxID = msg.StrategicTxID
|
distribution.StrategicTxID = msg.StrategicTxID
|
||||||
|
|
||||||
|
if err := k.clearUnresolvedClaims(ctx, distribution.FirstPop); err != nil {
|
||||||
|
util.GetAppLogger().Error(ctx, "error while clearing unresolved claims for heights %d-%d: %v", distribution.FirstPop, distribution.LastPop, err)
|
||||||
|
}
|
||||||
|
|
||||||
err := k.resolveStagedClaims(ctx, distribution.FirstPop, distribution.LastPop)
|
err := k.resolveStagedClaims(ctx, distribution.FirstPop, distribution.LastPop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetAppLogger().Error(ctx, "%s for provided PoP heights: %d %d", types.ErrResolvingStagedClaims.Error(), distribution.FirstPop, distribution.LastPop)
|
util.GetAppLogger().Error(ctx, "%s for provided PoP heights: %d %d", types.ErrResolvingStagedClaims.Error(), distribution.FirstPop, distribution.LastPop)
|
||||||
@ -37,14 +42,48 @@ func (k msgServer) DistributionResult(goCtx context.Context, msg *types.MsgDistr
|
|||||||
return &types.MsgDistributionResultResponse{}, nil
|
return &types.MsgDistributionResultResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k msgServer) resolveStagedClaims(ctx sdk.Context, start int64, end int64) (err error) {
|
// clearUnresolvedClaims checks for all Challenge participants starting from a given height.
|
||||||
// lookup all challenges since the last distribution
|
// An accounts stagedDenom amount should always be 0 except for claims that have not yet been reissued.
|
||||||
challenges, err := k.GetChallengeRange(ctx, start, end)
|
// Calculate the difference for a set of participants and clear out all past unresolved staged claims.
|
||||||
|
func (k msgServer) clearUnresolvedClaims(ctx sdk.Context, start int64) (err error) {
|
||||||
|
// calculate total amounts for current and future claims
|
||||||
|
currentAmounts, err := k.getClaims(ctx, start, ctx.BlockHeight())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
popParticipants := make(map[string]uint64)
|
totalAmounts := make(map[string]uint64)
|
||||||
|
for participantAddress := range currentAmounts {
|
||||||
|
stagedBalance := k.bankKeeper.GetBalance(ctx, sdk.MustAccAddressFromBech32(participantAddress), k.GetParams(ctx).StagedDenom)
|
||||||
|
totalAmounts[participantAddress] = stagedBalance.Amount.Uint64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate difference to account balance
|
||||||
|
for participantAddress := range totalAmounts {
|
||||||
|
totalAmounts[participantAddress] -= currentAmounts[participantAddress]
|
||||||
|
}
|
||||||
|
|
||||||
|
return k.convertOrderedClaim(ctx, totalAmounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveStagedClaims converts staged claims to claims in an ordered fashion for a given range
|
||||||
|
func (k msgServer) resolveStagedClaims(ctx sdk.Context, start int64, end int64) (err error) {
|
||||||
|
popParticipantAmounts, err := k.getClaims(ctx, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k.convertOrderedClaim(ctx, popParticipantAmounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k msgServer) getClaims(ctx sdk.Context, start int64, end int64) (claims map[string]uint64, err error) {
|
||||||
|
// lookup all challenges for a given range
|
||||||
|
challenges, err := k.GetChallengeRange(ctx, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
claims = make(map[string]uint64)
|
||||||
|
|
||||||
for _, challenge := range challenges {
|
for _, challenge := range challenges {
|
||||||
// if challenge not finished nobody has claims
|
// if challenge not finished nobody has claims
|
||||||
@ -52,9 +91,9 @@ func (k msgServer) resolveStagedClaims(ctx sdk.Context, start int64, end int64)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, challengerAmt, challengeeAmt := util.GetPopReward(challenge.Height, k.GetParams(ctx).PopEpochs)
|
_, challengerAmt, challengeeAmt := util.GetPopReward(challenge.Height, k.GetParams(ctx).PopEpochs)
|
||||||
popParticipants[challenge.Challenger] += challengerAmt
|
claims[challenge.Challenger] += challengerAmt
|
||||||
if challenge.GetSuccess() {
|
if challenge.GetSuccess() {
|
||||||
popParticipants[challenge.Challengee] += challengeeAmt
|
claims[challenge.Challengee] += challengeeAmt
|
||||||
}
|
}
|
||||||
initiatorAddr, err := sdk.AccAddressFromBech32(challenge.Initiator)
|
initiatorAddr, err := sdk.AccAddressFromBech32(challenge.Initiator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -64,16 +103,22 @@ func (k msgServer) resolveStagedClaims(ctx sdk.Context, start int64, end int64)
|
|||||||
if !found {
|
if !found {
|
||||||
util.GetAppLogger().Error(ctx, "No PoP initiator reward found for height %v", challenge.GetHeight())
|
util.GetAppLogger().Error(ctx, "No PoP initiator reward found for height %v", challenge.GetHeight())
|
||||||
}
|
}
|
||||||
popParticipants[initiatorAddr.String()] += validatorPopReward
|
claims[initiatorAddr.String()] += validatorPopReward
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k msgServer) convertOrderedClaim(ctx sdk.Context, claims map[string]uint64) (err error) {
|
||||||
// second data structure because map iteration order is not guaranteed in GO
|
// second data structure because map iteration order is not guaranteed in GO
|
||||||
keys := make([]string, 0)
|
keys := make([]string, 0)
|
||||||
for p := range popParticipants {
|
for accountAddress := range claims {
|
||||||
keys = append(keys, p)
|
keys = append(keys, accountAddress)
|
||||||
}
|
}
|
||||||
for _, p := range keys {
|
|
||||||
err = k.convertAccountClaim(ctx, p, popParticipants[p])
|
sort.Strings(keys)
|
||||||
|
for _, accountAddress := range keys {
|
||||||
|
err = k.convertAccountClaim(ctx, accountAddress, claims[accountAddress])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user