Skip to content

Commit

Permalink
Merge pull request #1837 from lavanet/fix-unfreeze-after-new-stake
Browse files Browse the repository at this point in the history
fix: unfreeze after new stake bug
  • Loading branch information
Yaroms authored Dec 16, 2024
2 parents 61959cf + 7903158 commit 0c91449
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 10 deletions.
3 changes: 1 addition & 2 deletions x/dualstaking/keeper/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,8 @@ func (k Keeper) AfterDelegationModified(ctx sdk.Context, delegator, provider str
details["stake"] = entry.TotalStake().String()
utils.LogLavaEvent(ctx, k.Logger(ctx), types.FreezeFromUnbond, details, "freezing provider due to stake below min spec stake")
entry.Freeze()
} else if delegator == entry.Vault && entry.IsFrozen() && !entry.IsJailed(ctx.BlockTime().UTC().Unix()) {
entry.UnFreeze(k.epochstorageKeeper.GetCurrentNextEpoch(ctx) + 1)
}

k.epochstorageKeeper.SetStakeEntryCurrent(ctx, *entry)
}

Expand Down
18 changes: 18 additions & 0 deletions x/pairing/keeper/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,21 @@ func (ts *tester) newRelaySession(
}
return relaySession
}

func (ts *tester) isProviderFrozen(provider string, chain string) bool {
res, err := ts.QueryPairingProvider(provider, chain)
require.NoError(ts.T, err)
foundChain := false
var isFrozen bool
for _, stakeEntry := range res.StakeEntries {
if stakeEntry.Address == provider && stakeEntry.Chain == chain {
foundChain = true
isFrozen = stakeEntry.IsFrozen()
break
}
}
if !foundChain {
require.Fail(ts.T, "provider not staked in chain", "provider: %s, chain: %s", provider, chain)
}
return isFrozen
}
44 changes: 44 additions & 0 deletions x/pairing/keeper/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2509,3 +2509,47 @@ func TestMaxEndpointPerGeolocationLimit(t *testing.T) {
)
require.Error(t, err)
}

// TestStakeNotAffectingFreeze checks the following scenario:
// 1. a provider is staked and frozen
// 2. the provider stakes to a new chain
// 3. the provider's freeze status in the original chain is not affected
func TestStakeNotAffectingFreeze(t *testing.T) {
ts := newTester(t)
ts.SetupAccounts(0, 0, 1) // 0 sub, 0 adm, 1 dev

var balance int64 = 10000
stake := balance / 10

// Create provider account and stake them to first spec
acc, addr := ts.AddAccount(common.PROVIDER, 1, balance)
err := ts.StakeProvider(acc.GetVaultAddr(), addr, ts.spec, stake)
require.NoError(t, err)

ts.AdvanceEpoch()

// Freeze the provider
_, err = ts.TxPairingFreezeProvider(addr, ts.spec.Index)
require.NoError(t, err)

// Verify provider is frozen
frozen := ts.isProviderFrozen(addr, ts.spec.Index)
require.True(t, frozen)

// Create a second spec and stake provider to it
spec1 := ts.spec
spec1Name := "spec1"
spec1.Index, spec1.Name = spec1Name, spec1Name
ts.AddSpec(spec1Name, spec1)
err = ts.StakeProvider(acc.GetVaultAddr(), addr, spec1, stake)
require.NoError(t, err)
ts.AdvanceEpoch()

// Verify provider is still frozen in original spec
frozen = ts.isProviderFrozen(addr, ts.spec.Index)
require.True(t, frozen)

// Verify provider is not frozen in new spec
frozen = ts.isProviderFrozen(addr, spec1.Index)
require.False(t, frozen)
}
24 changes: 16 additions & 8 deletions x/pairing/keeper/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin
// new staking takes effect from the next block
stakeAppliedBlock := uint64(ctx.BlockHeight()) + 1

nextEpoch, err := k.epochStorageKeeper.GetNextEpoch(ctx, uint64(ctx.BlockHeight()))
if err != nil {
return utils.LavaFormatWarning("cannot get next epoch to count past delegations", err,
utils.LogAttr("provider", senderAddr.String()),
utils.LogAttr("block", nextEpoch),
)
}

existingEntry, entryExists := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, chainID, creator)
if entryExists {
// modify the entry (check who's modifying - vault/provider)
Expand Down Expand Up @@ -175,6 +183,13 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin
details...,
)
}

// automatically unfreeze the provider if it was frozen due to stake below min spec stake
minSpecStake := k.specKeeper.GetMinStake(ctx, chainID)
if beforeAmount.IsLT(minSpecStake) && existingEntry.IsFrozen() && !existingEntry.IsJailed(ctx.BlockTime().UTC().Unix()) && amount.IsGTE(minSpecStake) {
existingEntry.UnFreeze(nextEpoch)
k.epochStorageKeeper.SetStakeEntryCurrent(ctx, existingEntry)
}
} else if decrease {
// unbond the difference
diffAmount := beforeAmount.Sub(amount)
Expand Down Expand Up @@ -228,15 +243,8 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin

// if there are registered delegations to the provider, count them in the delegateTotal
delegateTotal := sdk.ZeroInt()
nextEpoch, err := k.epochStorageKeeper.GetNextEpoch(ctx, uint64(ctx.BlockHeight()))
if err != nil {
return utils.LavaFormatWarning("cannot get next epoch to count past delegations", err,
utils.LogAttr("provider", senderAddr.String()),
utils.LogAttr("block", nextEpoch),
)
}

stakeAmount := amount

// creating a new provider, fetch old delegation
if len(metadata.Chains) == 1 {
delegations, err := k.dualstakingKeeper.GetProviderDelegators(ctx, provider)
Expand Down

0 comments on commit 0c91449

Please sign in to comment.