code.vegaprotocol.io/vega@v0.79.0/core/activitystreak/activitiystreak_snapshot_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package activitystreak_test 17 18 import ( 19 "context" 20 "fmt" 21 "testing" 22 23 "code.vegaprotocol.io/vega/core/activitystreak" 24 "code.vegaprotocol.io/vega/core/activitystreak/mocks" 25 "code.vegaprotocol.io/vega/core/events" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/libs/proto" 29 "code.vegaprotocol.io/vega/logging" 30 vegapb "code.vegaprotocol.io/vega/protos/vega" 31 snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 32 33 "github.com/golang/mock/gomock" 34 "github.com/stretchr/testify/assert" 35 ) 36 37 type testSnapshotEngine struct { 38 *activitystreak.SnapshotEngine 39 40 ctrl *gomock.Controller 41 broker *mocks.MockBroker 42 marketsStats *mocks.MockMarketsStatsAggregator 43 } 44 45 func getTestSnapshotEngine(t *testing.T) *testSnapshotEngine { 46 t.Helper() 47 ctrl := gomock.NewController(t) 48 marketsStats := mocks.NewMockMarketsStatsAggregator(ctrl) 49 broker := mocks.NewMockBroker(ctrl) 50 51 e := &testSnapshotEngine{ 52 SnapshotEngine: activitystreak.NewSnapshotEngine( 53 logging.NewTestLogger(), marketsStats, broker, 54 ), 55 ctrl: ctrl, 56 broker: broker, 57 marketsStats: marketsStats, 58 } 59 60 e.OnMinQuantumOpenNationalVolumeUpdate(context.Background(), num.NewUint(100)) 61 e.OnMinQuantumTradeVolumeUpdate(context.Background(), num.NewUint(200)) 62 e.OnRewardsActivityStreakInactivityLimit(context.Background(), num.NewUint(10)) 63 assert.NoError(t, e.OnBenefitTiersUpdate(context.Background(), &vegapb.ActivityStreakBenefitTiers{ 64 Tiers: []*vegapb.ActivityStreakBenefitTier{ 65 { 66 MinimumActivityStreak: 1, 67 RewardMultiplier: "2", 68 VestingMultiplier: "1.5", 69 }, 70 { 71 MinimumActivityStreak: 7, 72 RewardMultiplier: "3", 73 VestingMultiplier: "2.5", 74 }, 75 { 76 MinimumActivityStreak: 14, 77 RewardMultiplier: "4", 78 VestingMultiplier: "3.5", 79 }, 80 }, 81 })) 82 83 return e 84 } 85 86 func TestSnapshot(t *testing.T) { 87 e1 := getTestSnapshotEngine(t) 88 89 t.Run("setting up engine 1", func(t *testing.T) { 90 e1.marketsStats.EXPECT().GetMarketStats().Times(2).Return( 91 map[string]*types.MarketStats{ 92 "market1": { 93 PartiesOpenNotionalVolume: map[string]*num.Uint{ 94 "party1": num.NewUint(100), 95 "party2": num.NewUint(100), 96 "party3": num.NewUint(0), 97 }, 98 PartiesTotalTradeVolume: map[string]*num.Uint{ 99 "party1": num.NewUint(20), 100 "party2": num.NewUint(50), 101 "party3": num.NewUint(150), 102 }, 103 }, 104 "market2": { 105 PartiesOpenNotionalVolume: map[string]*num.Uint{ 106 "party1": num.NewUint(20), 107 "party2": num.NewUint(20), 108 "party3": num.NewUint(20), 109 }, 110 PartiesTotalTradeVolume: map[string]*num.Uint{ 111 "party1": num.NewUint(20), 112 "party2": num.NewUint(50), 113 "party3": num.NewUint(100), 114 }, 115 }, 116 }, 117 ) 118 119 e1.broker.EXPECT().SendBatch(gomock.Any()).Times(1) 120 e1.broker.EXPECT().SendBatch(gomock.Any()).Times(1).Do( 121 func(evts []events.Event) { 122 assert.Len(t, evts, 3) 123 124 pas := evts[0].(*events.PartyActivityStreak) 125 assert.Equal(t, pas.Proto().Party, "party1") 126 assert.True(t, pas.Proto().IsActive) 127 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 128 assert.Equal(t, int(pas.Proto().InactiveFor), 0) 129 assert.Equal(t, int(pas.Proto().Epoch), 2) 130 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 131 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 132 pas = evts[1].(*events.PartyActivityStreak) 133 assert.Equal(t, pas.Proto().Party, "party2") 134 assert.True(t, pas.Proto().IsActive) 135 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 136 assert.Equal(t, int(pas.Proto().InactiveFor), 0) 137 assert.Equal(t, int(pas.Proto().Epoch), 2) 138 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 139 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 140 pas = evts[2].(*events.PartyActivityStreak) 141 assert.Equal(t, pas.Proto().Party, "party3") 142 assert.True(t, pas.Proto().IsActive) 143 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 144 assert.Equal(t, int(pas.Proto().InactiveFor), 0) 145 assert.Equal(t, int(pas.Proto().Epoch), 2) 146 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 147 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 148 }, 149 ) 150 151 e1.OnEpochEvent(context.Background(), types.Epoch{ 152 Seq: 1, 153 Action: vegapb.EpochAction_EPOCH_ACTION_END, 154 }) 155 e1.OnEpochEvent(context.Background(), types.Epoch{ 156 Seq: 2, 157 Action: vegapb.EpochAction_EPOCH_ACTION_END, 158 }) 159 }) 160 161 state1, _, err := e1.GetState(activitystreak.ActivityStreakKey) 162 assert.NoError(t, err) 163 assert.NotNil(t, state1) 164 165 ppayload := &snapshotpb.Payload{} 166 err = proto.Unmarshal(state1, ppayload) 167 assert.NoError(t, err) 168 169 e2 := getTestSnapshotEngine(t) 170 _, err = e2.LoadState(context.Background(), types.PayloadFromProto(ppayload)) 171 assert.NoError(t, err) 172 173 // now assert the v2 produce the same state 174 state2, _, err := e2.GetState(activitystreak.ActivityStreakKey) 175 assert.NoError(t, err) 176 assert.NotNil(t, state2) 177 178 assert.Equal(t, state1, state2) 179 180 epochForward(t, e1, "engine 1") 181 epochForward(t, e2, "engine 2") 182 183 t.Run("finally comparing final state from both engines", func(t *testing.T) { 184 state1, _, err := e1.GetState(activitystreak.ActivityStreakKey) 185 assert.NoError(t, err) 186 assert.NotNil(t, state1) 187 188 ppayload := &snapshotpb.Payload{} 189 err = proto.Unmarshal(state1, ppayload) 190 assert.NoError(t, err) 191 192 _, err = e2.LoadState(context.Background(), types.PayloadFromProto(ppayload)) 193 assert.NoError(t, err) 194 195 // now assert the v2 produce the same state 196 state2, _, err := e2.GetState(activitystreak.ActivityStreakKey) 197 assert.NoError(t, err) 198 assert.NotNil(t, state2) 199 200 assert.Equal(t, state1, state2) 201 }) 202 } 203 204 func epochForward(t *testing.T, e *testSnapshotEngine, name string) { 205 t.Helper() 206 t.Run(fmt.Sprintf("moving time for %v", name), func(t *testing.T) { 207 e.marketsStats.EXPECT().GetMarketStats().Times(1).Return( 208 map[string]*types.MarketStats{}, 209 ) 210 211 e.broker.EXPECT().SendBatch(gomock.Any()).Times(1).Do( 212 func(evts []events.Event) { 213 assert.Len(t, evts, 3) 214 215 pas := evts[0].(*events.PartyActivityStreak) 216 assert.Equal(t, pas.Proto().Party, "party1") 217 assert.False(t, pas.Proto().IsActive) 218 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 219 assert.Equal(t, int(pas.Proto().InactiveFor), 1) 220 assert.Equal(t, int(pas.Proto().Epoch), 3) 221 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 222 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 223 pas = evts[1].(*events.PartyActivityStreak) 224 assert.Equal(t, pas.Proto().Party, "party2") 225 assert.False(t, pas.Proto().IsActive) 226 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 227 assert.Equal(t, int(pas.Proto().InactiveFor), 1) 228 assert.Equal(t, int(pas.Proto().Epoch), 3) 229 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 230 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 231 pas = evts[2].(*events.PartyActivityStreak) 232 assert.Equal(t, pas.Proto().Party, "party3") 233 assert.False(t, pas.Proto().IsActive) 234 assert.Equal(t, int(pas.Proto().ActiveFor), 2) 235 assert.Equal(t, int(pas.Proto().InactiveFor), 1) 236 assert.Equal(t, int(pas.Proto().Epoch), 3) 237 assert.Equal(t, pas.Proto().RewardDistributionActivityMultiplier, "2") 238 assert.Equal(t, pas.Proto().RewardVestingActivityMultiplier, "1.5") 239 }, 240 ) 241 242 e.OnEpochEvent(context.Background(), types.Epoch{ 243 Seq: 3, 244 Action: vegapb.EpochAction_EPOCH_ACTION_END, 245 }) 246 }) 247 }