diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index 76051250ea..2cf83e73e4 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -60,16 +60,17 @@ func (k Keeper) increaseDelegation(ctx sdk.Context, delegator, provider, chainID index = types.DelegatorKey(delegator) _ = k.delegatorFS.FindEntry(ctx, index, nextEpoch, &delegatorEntry) - delegatorEntry.AddProvider(provider) - - err = k.delegatorFS.AppendEntry(ctx, index, nextEpoch, &delegatorEntry) - if err != nil { - // append should never fail here - return utils.LavaFormatError("critical: append delegator entry", err, - utils.Attribute{Key: "delegator", Value: delegator}, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - ) + contains := delegatorEntry.AddProvider(provider) + if !contains { + err = k.delegatorFS.AppendEntry(ctx, index, nextEpoch, &delegatorEntry) + if err != nil { + // append should never fail here + return utils.LavaFormatError("critical: append delegator entry", err, + utils.Attribute{Key: "delegator", Value: delegator}, + utils.Attribute{Key: "provider", Value: provider}, + utils.Attribute{Key: "chainID", Value: chainID}, + ) + } } if provider != types.EMPTY_PROVIDER { @@ -140,27 +141,29 @@ func (k Keeper) decreaseDelegation(ctx sdk.Context, delegator, provider, chainID // entry; and if the delegator entry becomes entry then remove it altogether. // otherwise just append the new version (for next epoch). if delegationEntry.Amount.IsZero() { - delegatorEntry.DelProvider(provider) - } - if delegatorEntry.IsEmpty() { - err := k.delegatorFS.DelEntry(ctx, index, nextEpoch) - if err != nil { - // delete should never fail here - return utils.LavaFormatError("critical: delete delegator entry", err, - utils.Attribute{Key: "delegator", Value: delegator}, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - ) - } - } else { - err := k.delegatorFS.AppendEntry(ctx, index, nextEpoch, &delegatorEntry) - if err != nil { - // append should never fail here - return utils.LavaFormatError("failed to update delegator entry", err, - utils.Attribute{Key: "delegator", Value: delegator}, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - ) + if len(k.GetAllProviderDelegatorDelegations(ctx, delegator, provider, nextEpoch)) == 0 { + delegatorEntry.DelProvider(provider) + if delegatorEntry.IsEmpty() { + err := k.delegatorFS.DelEntry(ctx, index, nextEpoch) + if err != nil { + // delete should never fail here + return utils.LavaFormatError("critical: delete delegator entry", err, + utils.Attribute{Key: "delegator", Value: delegator}, + utils.Attribute{Key: "provider", Value: provider}, + utils.Attribute{Key: "chainID", Value: chainID}, + ) + } + } else { + err := k.delegatorFS.AppendEntry(ctx, index, nextEpoch, &delegatorEntry) + if err != nil { + // append should never fail here + return utils.LavaFormatError("failed to update delegator entry", err, + utils.Attribute{Key: "delegator", Value: delegator}, + utils.Attribute{Key: "provider", Value: provider}, + utils.Attribute{Key: "chainID", Value: chainID}, + ) + } + } } } @@ -468,14 +471,16 @@ func (k Keeper) GetAllProviderDelegatorDelegations(ctx sdk.Context, delegator, p var delegations []types.Delegation for _, ind := range indices { var delegation types.Delegation - found := k.delegationFS.FindEntry(ctx, ind, epoch, &delegation) + _, deleted, _, found := k.delegationFS.FindEntryDetailed(ctx, ind, epoch, &delegation) if !found { - provider, delegator, chainID := types.DelegationKeyDecode(ind) - utils.LavaFormatError("delegationFS entry index has no entry", fmt.Errorf("provider delegation not found"), - utils.Attribute{Key: "delegator", Value: delegator}, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - ) + if !deleted { + provider, delegator, chainID := types.DelegationKeyDecode(ind) + utils.LavaFormatError("delegationFS entry index has no entry", fmt.Errorf("provider delegation not found"), + utils.Attribute{Key: "delegator", Value: delegator}, + utils.Attribute{Key: "provider", Value: provider}, + utils.Attribute{Key: "chainID", Value: chainID}, + ) + } continue } delegations = append(delegations, delegation) diff --git a/x/dualstaking/keeper/delegate_test.go b/x/dualstaking/keeper/delegate_test.go index 5a1daa4402..1a432a0c66 100644 --- a/x/dualstaking/keeper/delegate_test.go +++ b/x/dualstaking/keeper/delegate_test.go @@ -377,15 +377,25 @@ func TestUnbond(t *testing.T) { // 1 delegator, 2 provider staked, 0 provider unstaked, 0 provider unstaking ts.setupForDelegation(1, 2, 0, 0) + provider1Acct, provider1Addr := ts.GetAccount(common.PROVIDER, 0) + + spec2 := ts.spec + spec2.Index = "mock2" + spec2.Name = spec2.Index + ts.AddSpec(spec2.Index, spec2) + err := ts.StakeProvider(provider1Addr, spec2, testStake) + require.NoError(t, err) _, client1Addr := ts.GetAccount(common.CONSUMER, 0) - provider1Acct, provider1Addr := ts.GetAccount(common.PROVIDER, 0) delegated := zeroCoin // delegate once amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) - _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) + _, err = ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) + require.NoError(t, err) + + _, err = ts.TxDualstakingDelegate(client1Addr, provider1Addr, spec2.Index, amount) require.NoError(t, err) // advance epoch to digest the delegate @@ -395,6 +405,10 @@ func TestUnbond(t *testing.T) { stakeEntry := ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) require.True(t, delegated.IsEqual(stakeEntry.DelegateTotal)) + res, err := ts.QueryDualstakingDelegatorProviders(client1Addr, true) + require.NoError(t, err) + require.Len(t, res.Delegations, 2) + // unbond once amount = sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(1000)) _, err = ts.TxDualstakingUnbond(client1Addr, provider1Addr, ts.spec.Name, amount) @@ -437,6 +451,12 @@ func TestUnbond(t *testing.T) { require.NoError(t, err) stakeEntry = ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) require.True(t, delegated.IsEqual(stakeEntry.DelegateTotal)) + delegated = delegated.Sub(amount) + + // unbond from unstaking provider everything + _, err = ts.TxDualstakingUnbond(client1Addr, provider1Addr, ts.spec.Name, delegated) + require.NoError(t, err) + stakeEntry = ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) // advance half the blocks for the unbond hold-period (for sure > epoch) ts.AdvanceBlocks(105) @@ -448,6 +468,11 @@ func TestUnbond(t *testing.T) { // not-blablacoins will have been returned to their delegator by now ts.verifyDelegatorsBalance() + + res, err = ts.QueryDualstakingDelegatorProviders(client1Addr, true) + require.NoError(t, err) + require.Len(t, res.Delegations, 1) + require.Equal(t, provider1Addr, res.Delegations[0].Provider) } func TestBondUnbondBond(t *testing.T) { diff --git a/x/dualstaking/types/delegate.go b/x/dualstaking/types/delegate.go index 96b4ce6572..4fa5dfca05 100644 --- a/x/dualstaking/types/delegate.go +++ b/x/dualstaking/types/delegate.go @@ -50,10 +50,12 @@ func NewDelegator(delegator, provider string) Delegator { } } -func (delegator *Delegator) AddProvider(provider string) { - if !lavaslices.Contains(delegator.Providers, provider) { +func (delegator *Delegator) AddProvider(provider string) bool { + contains := lavaslices.Contains(delegator.Providers, provider) + if !contains { delegator.Providers = append(delegator.Providers, provider) } + return contains } func (delegator *Delegator) DelProvider(provider string) { diff --git a/x/fixationstore/types/fixationstore.go b/x/fixationstore/types/fixationstore.go index 5c290964e1..a9510ef055 100644 --- a/x/fixationstore/types/fixationstore.go +++ b/x/fixationstore/types/fixationstore.go @@ -736,7 +736,7 @@ func (fs *FixationStore) FindEntryDetailed(ctx sdk.Context, index string, block // true in this case. if !found || entry.IsDeletedBy(block) { - return 0, false, false, false + return 0, entry.IsDeletedBy(block), false, false } fs.cdc.MustUnmarshal(entry.GetData(), entryData) diff --git a/x/pairing/keeper/unstaking.go b/x/pairing/keeper/unstaking.go index a9c0025a16..ee122b1509 100644 --- a/x/pairing/keeper/unstaking.go +++ b/x/pairing/keeper/unstaking.go @@ -51,18 +51,6 @@ func (k Keeper) UnstakeEntry(ctx sdk.Context, validator, chainID, creator, unsta ) } - // index might have changed in the unbond - existingEntry, found, indexInStakeStorage := k.epochStorageKeeper.GetStakeEntryByAddressCurrent(ctx, chainID, senderAddr) - if found { - err = k.epochStorageKeeper.RemoveStakeEntryCurrent(ctx, chainID, indexInStakeStorage) - if err != nil { - return utils.LavaFormatWarning("can't remove stake Entry, stake entry not found in index", err, - utils.Attribute{Key: "index", Value: indexInStakeStorage}, - utils.Attribute{Key: "spec", Value: chainID}, - ) - } - } - details := map[string]string{ "address": existingEntry.GetAddress(), "chainID": existingEntry.GetChain(),