Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

instant slashing of all balance in case of kycQuizResetAt passed #107

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ require (
github.com/alitto/pond v1.8.3
github.com/bsm/redislock v0.9.4
github.com/cenkalti/backoff/v4 v4.2.1
github.com/ethereum/go-ethereum v1.13.10
github.com/ethereum/go-ethereum v1.13.11
github.com/goccy/go-json v0.10.2
github.com/hashicorp/go-multierror v1.1.1
github.com/ice-blockchain/eskimo v1.273.0
github.com/ice-blockchain/eskimo v1.278.0
github.com/ice-blockchain/go-tarantool-client v0.0.0-20230327200757-4fc71fa3f7bb
github.com/ice-blockchain/wintr v1.133.0
github.com/imroc/req/v3 v3.42.3
Expand All @@ -34,7 +34,7 @@ require (
cloud.google.com/go/firestore v1.14.0 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/longrunning v0.5.4 // indirect
cloud.google.com/go/storage v1.36.0 // indirect
cloud.google.com/go/storage v1.37.0 // indirect
cosmossdk.io/math v1.2.0 // indirect
dario.cat/mergo v1.0.0 // indirect
firebase.google.com/go/v4 v4.13.0 // indirect
Expand Down Expand Up @@ -73,7 +73,7 @@ require (
github.com/distribution/reference v0.5.0 // indirect
github.com/dmarkham/enumer v1.5.9 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v25.0.0+incompatible // indirect
github.com/docker/docker v25.0.1+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
Expand Down Expand Up @@ -106,7 +106,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 // indirect
github.com/google/pprof v0.0.0-20240125082051-42cd04596328 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8=
cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cloud.google.com/go/storage v1.37.0 h1:WI8CsaFO8Q9KjPVtsZ5Cmi0dXV25zMoX0FklT7c3Jm4=
cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k=
cosmossdk.io/math v1.2.0 h1:8gudhTkkD3NxOP2YyyJIYYmt6dQ55ZfJkDOaxXpy7Ig=
cosmossdk.io/math v1.2.0/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
Expand Down Expand Up @@ -149,8 +149,8 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBF
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY=
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoIVSdqZek=
github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA=
github.com/ethereum/go-ethereum v1.13.11 h1:b51Dsm+rEg7anFRUMGB8hODXHvNfcRKzz9vcj8wSdUs=
github.com/ethereum/go-ethereum v1.13.11/go.mod h1:gFtlVORuUcT+UUIcJ/veCNjkuOSujCi338uSHJrYAew=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
Expand Down Expand Up @@ -266,8 +266,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw=
github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8=
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240125082051-42cd04596328 h1:oI+lCI2DY1BsRrdzMJBhIMxBBdlZJl31YNQC11EiyvA=
github.com/google/pprof v0.0.0-20240125082051-42cd04596328/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
Expand Down Expand Up @@ -303,8 +303,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ice-blockchain/eskimo v1.273.0 h1:MiAtuwy/rCoxO3KckScrBYLz+PE4722rsYVrab+3FmA=
github.com/ice-blockchain/eskimo v1.273.0/go.mod h1:9+GGoDYKZ2uoK83vEQP6iepy6NvK67IXtRQA5jiu6lM=
github.com/ice-blockchain/eskimo v1.278.0 h1:yhLfMPNHaKUSobhmNdvr8YZrms51DmUkD60xdxdAF1M=
github.com/ice-blockchain/eskimo v1.278.0/go.mod h1:N+V5nMoa61c25ZhvGC849mpS+pW0ptBrGzi5yqxa3YY=
github.com/ice-blockchain/go-tarantool-client v0.0.0-20230327200757-4fc71fa3f7bb h1:8TnFP3mc7O+tc44kv2e0/TpZKnEVUaKH+UstwfBwRkk=
github.com/ice-blockchain/go-tarantool-client v0.0.0-20230327200757-4fc71fa3f7bb/go.mod h1:ZsQU7i3mxhgBBu43Oev7WPFbIjP4TniN/b1UPNGbrq8=
github.com/ice-blockchain/wintr v1.133.0 h1:lmRQQlowBWBKZfAW6vVAtDwYRc4mKvx9MkgPArQgkwU=
Expand Down
28 changes: 25 additions & 3 deletions miner/mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func mine(baseMiningRate float64, now *time.Time, usr *user, t0Ref, tMinus1Ref *
clonedUser1 := *usr
updatedUser = &clonedUser1
pendingResurrectionForTMinus1, pendingResurrectionForT0 := resurrect(now, updatedUser, t0Ref, tMinus1Ref)

IDT0Changed, _ = changeT0AndTMinus1Referrals(updatedUser)
if updatedUser.MiningSessionSoloEndedAt.Before(*now.Time) && updatedUser.isAbsoluteZero() {
if updatedUser.BalanceT1Pending-updatedUser.BalanceT1PendingApplied != 0 ||
Expand Down Expand Up @@ -78,7 +79,21 @@ func mine(baseMiningRate float64, now *time.Time, usr *user, t0Ref, tMinus1Ref *
updatedUser.BalanceT2Pending = 0
updatedUser.BalanceT2PendingApplied = 0
}

needInstantSlashing := usr.WasQuizReset(updatedUser.BalanceLastUpdatedAt)
if needInstantSlashing {
pendingResurrectionForTMinus1 = 0
pendingResurrectionForT0 = 0
updatedUser.BalanceSolo = 0
updatedUser.BalanceT1 = 0
updatedUser.BalanceT2 = 0
if tMinus1Ref != nil {
updatedUser.BalanceForTMinus1 = 0
}
if t0Ref != nil {
updatedUser.BalanceForT0 = 0
updatedUser.BalanceT0 = 0
}
}
if updatedUser.MiningSessionSoloEndedAt.After(*now.Time) {
if !updatedUser.ExtraBonusStartedAt.IsNil() && now.Before(updatedUser.ExtraBonusStartedAt.Add(cfg.ExtraBonuses.Duration)) {
rate := (100 + float64(updatedUser.ExtraBonus)) * baseMiningRate * elapsedTimeFraction / 100.
Expand All @@ -95,14 +110,14 @@ func mine(baseMiningRate float64, now *time.Time, usr *user, t0Ref, tMinus1Ref *
updatedUser.BalanceT0 += rate
mintedAmount += rate

if updatedUser.SlashingRateForT0 != 0 {
if updatedUser.SlashingRateForT0 != 0 && (!needInstantSlashing) {
updatedUser.SlashingRateForT0 = 0
}
}
if tMinus1Ref != nil && !tMinus1Ref.MiningSessionSoloEndedAt.IsNil() && tMinus1Ref.MiningSessionSoloEndedAt.After(*now.Time) {
updatedUser.BalanceForTMinus1 += 5 * baseMiningRate * elapsedTimeFraction / 100

if updatedUser.SlashingRateForTMinus1 != 0 {
if updatedUser.SlashingRateForTMinus1 != 0 && (!needInstantSlashing) {
updatedUser.SlashingRateForTMinus1 = 0
}
}
Expand Down Expand Up @@ -208,6 +223,13 @@ func mine(baseMiningRate float64, now *time.Time, usr *user, t0Ref, tMinus1Ref *
updatedUser.BalanceTotalSlashed += slashedStandard + slashedPreStaking
updatedUser.BalanceLastUpdatedAt = now

if needInstantSlashing {
updatedUser.SlashingRateSolo = 0
updatedUser.SlashingRateT0 = 0
updatedUser.SlashingRateForT0 = 0
updatedUser.SlashingRateForTMinus1 = 0
}

return updatedUser, shouldGenerateHistory, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0
}

Expand Down
105 changes: 105 additions & 0 deletions miner/mining_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package miner

import (
"github.com/ice-blockchain/freezer/model"
"testing"
stdlibtime "time"

Expand Down Expand Up @@ -162,6 +163,110 @@ func testSoloMiningNoExtraBonus(t *testing.T) {
require.EqualValues(t, 4, m.BalanceForT0)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)
})
t.Run("no KYCQuizResetAt => balance is accumulated between mine calls", func(t *testing.T) {
t.Parallel()
m := newUser()
m.ActiveT1Referrals = 4
m.ActiveT2Referrals = 20
m.IDT0, m.IDTMinus1 = 1, 2
ref := newRef()
tMinus1Ref := newRef()
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 := mine(testMiningBase, testTime, m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 16, m.BalanceSolo)
require.EqualValues(t, 4, m.BalanceT0)
require.EqualValues(t, 4, m.BalanceForT0)
require.EqualValues(t, 16, m.BalanceT1)
require.EqualValues(t, 16, m.BalanceT2)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)

m.IDT0, m.IDTMinus1 = 1, 2
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 = mine(testMiningBase, timeDelta(1*stdlibtime.Hour), m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 32, m.BalanceSolo)
require.EqualValues(t, 8, m.BalanceT0)
require.EqualValues(t, 8, m.BalanceForT0)
require.EqualValues(t, 32, m.BalanceT1)
require.EqualValues(t, 32, m.BalanceT2)
require.EqualValues(t, 1.6, m.BalanceForTMinus1)
require.False(t, IDT0Changed)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
})
t.Run("with KYCQuizResetAt after now => balance is reset on next iteration to mined value for the past time", func(t *testing.T) {
t.Parallel()
m := newUser()
m.ActiveT1Referrals = 4
m.ActiveT2Referrals = 20
m.IDT0, m.IDTMinus1 = 1, 2
ref := newRef()
tMinus1Ref := newRef()
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 := mine(testMiningBase, testTime, m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 16, m.BalanceSolo)
require.EqualValues(t, 4, m.BalanceT0)
require.EqualValues(t, 4, m.BalanceForT0)
require.EqualValues(t, 16, m.BalanceT1)
require.EqualValues(t, 16, m.BalanceT2)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)

kycResetAt := model.TimeSlice([]*time.Time{timeDelta(61 * stdlibtime.Minute)})
m.KYCQuizResetAt = &kycResetAt
m.IDT0, m.IDTMinus1 = 1, 2
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 = mine(testMiningBase, timeDelta(1*stdlibtime.Hour), m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 16, m.BalanceSolo)
require.EqualValues(t, 4, m.BalanceT0)
require.EqualValues(t, 4, m.BalanceForT0)
require.EqualValues(t, 16, m.BalanceT1)
require.EqualValues(t, 16, m.BalanceT2)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)
require.False(t, IDT0Changed)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
})
t.Run("with KYCQuizResetAt before balanceUpdatedAt => it is passed and no balance reset", func(t *testing.T) {
t.Parallel()
m := newUser()
m.ActiveT1Referrals = 4
m.ActiveT2Referrals = 20
m.IDT0, m.IDTMinus1 = 1, 2
ref := newRef()
tMinus1Ref := newRef()
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 := mine(testMiningBase, testTime, m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 16, m.BalanceSolo)
require.EqualValues(t, 4, m.BalanceT0)
require.EqualValues(t, 4, m.BalanceForT0)
require.EqualValues(t, 16, m.BalanceT1)
require.EqualValues(t, 16, m.BalanceT2)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
require.EqualValues(t, 0.8, m.BalanceForTMinus1)

kycResetAt := model.TimeSlice([]*time.Time{timeDelta(59 * stdlibtime.Minute)})
m.KYCQuizResetAt = &kycResetAt
m.IDT0, m.IDTMinus1 = 1, 2
m.BalanceLastUpdatedAt = timeDelta(1 * stdlibtime.Hour)
m, _, IDT0Changed, pendingAmountForTMinus1, pendingAmountForT0 = mine(testMiningBase, timeDelta(1*stdlibtime.Hour), m, ref, tMinus1Ref)
require.NotNil(t, m)
require.EqualValues(t, 32, m.BalanceSolo)
require.EqualValues(t, 8, m.BalanceT0)
require.EqualValues(t, 8, m.BalanceForT0)
require.EqualValues(t, 32, m.BalanceT1)
require.EqualValues(t, 32, m.BalanceT2)
require.EqualValues(t, 1.6, m.BalanceForTMinus1)
require.False(t, IDT0Changed)
require.EqualValues(t, 0, pendingAmountForTMinus1)
require.EqualValues(t, 0, pendingAmountForT0)
})
}

func testSoloMiningWithExtraBonus(t *testing.T) {
Expand Down
19 changes: 19 additions & 0 deletions model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type (
KYCStepsLastUpdatedAtField
KYCStepPassedField
KYCStepBlockedField
KYCQuizResetAtField
}
SoloLastEthereumCoinDistributionProcessedAtField struct {
SoloLastEthereumCoinDistributionProcessedAt *time.Time `redis:"solo_last_ethereum_coin_distribution_processed_at,omitempty"`
Expand Down Expand Up @@ -311,6 +312,10 @@ type (
KYCStepBlockedField struct {
KYCStepBlocked users.KYCStep `json:"kycStepBlocked" redis:"kyc_step_blocked"`
}

KYCQuizResetAtField struct {
KYCQuizResetAt *TimeSlice `json:"kycQuizResetAt" redis:"kyc_quiz_reset_at"`
}
)

type (
Expand Down Expand Up @@ -408,6 +413,20 @@ func (kyc *KYCState) DelayPassedSinceLastKYCStepAttempt(kycStep users.KYCStep, d
return kyc.KYCStepAttempted(kycStep) && time.Now().Sub(*(*kyc.KYCStepsLastUpdatedAt)[kycStep-1].Time) >= duration
}

func (kyc *KYCState) WasQuizReset(past *time.Time) bool {
res := false
if kyc.KYCQuizResetAt != nil {
for _, quizResettedDate := range *kyc.KYCQuizResetAt {
if quizResettedDate.After(*past.Time) {
res = true

break
}
}
}
return res
}

type (
TimeSlice []*time.Time
)
Expand Down
Loading