code.vegaprotocol.io/vega@v0.79.0/core/rewards/engine_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 rewards 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 bmocks "code.vegaprotocol.io/vega/core/broker/mocks" 24 "code.vegaprotocol.io/vega/core/collateral" 25 "code.vegaprotocol.io/vega/core/rewards/mocks" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/num" 28 "code.vegaprotocol.io/vega/logging" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func Test(t *testing.T) { 35 t.Run("Update max payout per participant for staking and delegation reward scheme succeeds", testUpdateMaxPayoutPerParticipantForStakingRewardScheme) 36 t.Run("Calculation of reward payout succeeds", testCalculateRewards) 37 t.Run("Calculation of reward payout succeeds with map per participant", testCalculateRewardsWithMaxPerParticipant) 38 t.Run("Payout distribution succeeds", testDistributePayout) 39 t.Run("Process epoch end to calculate payout with no delay - rewards are distributed successfully", testOnEpochEventNoPayoutDelay) 40 } 41 42 func TestRewardFactors(t *testing.T) { 43 testEngine := getEngine(t) 44 engine := testEngine.engine 45 46 p, e := engine.calculateRewardFactors(num.DecimalFromInt64(10), num.DecimalFromInt64(10)) 47 require.Equal(t, "0.5", p.String()) 48 require.Equal(t, "0.5", e.String()) 49 50 p, e = engine.calculateRewardFactors(num.DecimalFromInt64(100), num.DecimalFromInt64(0)) 51 require.Equal(t, "1", p.String()) 52 require.Equal(t, "0", e.String()) 53 54 p, e = engine.calculateRewardFactors(num.DecimalFromInt64(0), num.DecimalFromInt64(1)) 55 require.Equal(t, "0", p.String()) 56 require.Equal(t, "1", e.String()) 57 58 p, e = engine.calculateRewardFactors(num.DecimalFromInt64(99999999), num.DecimalFromInt64(1)) 59 require.Equal(t, "0.99999999", p.String()) 60 require.Equal(t, "0.00000001", e.String()) 61 62 p, e = engine.calculateRewardFactors(num.DecimalFromInt64(1), num.DecimalFromInt64(99999999)) 63 require.Equal(t, "0.00000001", p.String()) 64 require.Equal(t, "0.99999999", e.String()) 65 } 66 67 // test updating of max payout per participant for staking and delegation reward scheme. 68 func testUpdateMaxPayoutPerParticipantForStakingRewardScheme(t *testing.T) { 69 testEngine := getEngine(t) 70 engine := testEngine.engine 71 require.NoError(t, engine.UpdateMaxPayoutPerParticipantForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(10000))) 72 require.Equal(t, num.NewUint(10000), engine.global.maxPayoutPerParticipant) 73 } 74 75 // test calculation of reward payout. 76 func testCalculateRewards(t *testing.T) { 77 testEngine := getEngine(t) 78 now := time.Now() 79 testEngine.timeService.EXPECT().GetTimeNow().DoAndReturn(func() time.Time { 80 return now 81 }).AnyTimes() 82 83 engine := testEngine.engine 84 require.NoError(t, engine.UpdateAssetForStakingAndDelegation(context.Background(), "VEGA")) 85 require.NoError(t, engine.UpdateDelegatorShareForStakingRewardScheme(context.Background(), num.DecimalFromFloat(0.3))) 86 require.NoError(t, engine.UpdateMinimumValidatorStakeForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(0))) 87 require.NoError(t, engine.UpdateCompetitionLevelForStakingRewardScheme(context.Background(), num.DecimalFromFloat(1.1))) 88 require.NoError(t, engine.UpdateMinValidatorsStakingRewardScheme(context.Background(), 5)) 89 require.NoError(t, engine.UpdateOptimalStakeMultiplierStakingRewardScheme(context.Background(), num.DecimalFromFloat(5))) 90 require.NoError(t, engine.UpdateMaxPayoutPerParticipantForStakingRewardScheme(context.Background(), num.DecimalZero())) 91 require.NoError(t, engine.UpdateErsatzRewardFactor(context.Background(), num.DecimalFromFloat(0.5))) 92 93 epoch := types.Epoch{EndTime: now} 94 rewardAccount, err := testEngine.collateral.GetGlobalRewardAccount("VEGA") 95 require.NoError(t, err) 96 97 testEngine.delegation.EXPECT().ProcessEpochDelegations(gomock.Any(), gomock.Any()).Return(testEngine.validatorData) 98 testEngine.delegation.EXPECT().GetValidatorData().AnyTimes() 99 testEngine.topology.EXPECT().RecalcValidatorSet(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 100 testEngine.topology.EXPECT().GetRewardsScores(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, epochSeq string, delegationState []*types.ValidatorData, stakeScoreParams types.StakeScoreParams) (*types.ScoreData, *types.ScoreData) { 101 return &types.ScoreData{ 102 NodeIDSlice: []string{"node1", "node2"}, 103 NormalisedScores: map[string]num.Decimal{ 104 "node1": num.DecimalFromFloat(0.2), 105 "node2": num.DecimalFromFloat(0.8), 106 }, 107 }, &types.ScoreData{ 108 NodeIDSlice: []string{"node3", "node4"}, 109 NormalisedScores: map[string]num.Decimal{ 110 "node3": num.DecimalFromFloat(0.6), 111 "node4": num.DecimalFromFloat(0.4), 112 }, 113 } 114 }) 115 116 require.NoError(t, testEngine.collateral.IncrementBalance(context.Background(), rewardAccount.ID, num.NewUint(1000000))) 117 118 payouts := engine.calculateRewardPayouts(context.Background(), epoch) 119 primary := payouts[0] 120 ersatz := payouts[1] 121 122 // calculation 123 // node1 has total delegation of 15000 124 // node2 has total delegation of 60000 125 // node3 has total delegation of 4000 126 // node4 has total delegation of 6000 127 // primary validators have stake of 75000 128 // ersatz validators have a stake of 10000 129 // therefore primary get 0.9375 of the reward, ersatz 0.0625 of the reward 130 // primary validators 131 // node1, node2 132 // node1 has normalised score of 0.2 => node1 and its delegators get 0.2 * 0.9375 * 1e6 = 1875000 133 // out of 187500, delegators get 0.3 (delegatorShare) * 2/3 (the ratio of delegation by delegator in node1)= 37500 134 // that leaves 187500-37500 = 150000 to node1 135 // out of the 37500 party1 gets 0.6x (22500) and party2 gets 0.4x (15000) given their ratio of delegation in the node 136 // node2 has normalised score of 0.8 => node 2 and its delegators get 0.8 * 0.9375 *1e6 = 750000 137 // out of the 750000, delegators get 0.3 (delegatorShare) * 2/3 (the ratio of delegation by delegator in node2)= 150000 138 // the 150000 goes exclusively to party1 and added to the 22500 they get from node1 to a total of 172500 139 // node2 gets the rest of the 750000 => 600000 140 // ersatz validators 141 // node3 has normalised score of 0.6 => 0.6 * 62500 = 37500 142 // node4 has normalised score of 0.4 => 0.4 * 62500 = 25000 143 144 require.Equal(t, 4, len(primary.partyToAmount)) 145 146 require.Equal(t, num.NewUint(172500), primary.partyToAmount["party1"]) 147 require.Equal(t, num.NewUint(15000), primary.partyToAmount["party2"]) 148 require.Equal(t, num.NewUint(150000), primary.partyToAmount["node1"]) 149 require.Equal(t, num.NewUint(600000), primary.partyToAmount["node2"]) 150 require.Equal(t, num.NewUint(37500), ersatz.partyToAmount["node3"]) 151 require.Equal(t, num.NewUint(25000), ersatz.partyToAmount["node4"]) 152 require.Equal(t, epoch.EndTime.UnixNano(), primary.timestamp) 153 require.Equal(t, epoch.EndTime.UnixNano(), ersatz.timestamp) 154 require.Equal(t, num.NewUint(937500), primary.totalReward) 155 require.Equal(t, num.NewUint(62500), ersatz.totalReward) 156 } 157 158 func testCalculateRewardsWithMaxPerParticipant(t *testing.T) { 159 testEngine := getEngine(t) 160 now := time.Now() 161 testEngine.timeService.EXPECT().GetTimeNow().DoAndReturn( 162 func() time.Time { 163 return now 164 }).AnyTimes() 165 166 engine := testEngine.engine 167 require.NoError(t, engine.UpdateAssetForStakingAndDelegation(context.Background(), "VEGA")) 168 require.NoError(t, engine.UpdateDelegatorShareForStakingRewardScheme(context.Background(), num.DecimalFromFloat(0.3))) 169 require.NoError(t, engine.UpdateMinimumValidatorStakeForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(0))) 170 require.NoError(t, engine.UpdateCompetitionLevelForStakingRewardScheme(context.Background(), num.DecimalFromFloat(1.1))) 171 require.NoError(t, engine.UpdateMinValidatorsStakingRewardScheme(context.Background(), 5)) 172 require.NoError(t, engine.UpdateOptimalStakeMultiplierStakingRewardScheme(context.Background(), num.DecimalFromFloat(5))) 173 require.NoError(t, engine.UpdateMaxPayoutPerParticipantForStakingRewardScheme(context.Background(), num.DecimalFromFloat(100000))) 174 require.NoError(t, engine.UpdateErsatzRewardFactor(context.Background(), num.DecimalFromFloat(0.5))) 175 176 epoch := types.Epoch{EndTime: now} 177 rewardAccount, err := testEngine.collateral.GetGlobalRewardAccount("VEGA") 178 require.NoError(t, err) 179 testEngine.delegation.EXPECT().ProcessEpochDelegations(gomock.Any(), gomock.Any()).Return(testEngine.validatorData) 180 testEngine.delegation.EXPECT().GetValidatorData().AnyTimes() 181 testEngine.topology.EXPECT().RecalcValidatorSet(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 182 testEngine.topology.EXPECT().GetRewardsScores(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, epochSeq string, delegationState []*types.ValidatorData, stakeScoreParams types.StakeScoreParams) (*types.ScoreData, *types.ScoreData) { 183 return &types.ScoreData{ 184 NodeIDSlice: []string{"node1", "node2"}, 185 NormalisedScores: map[string]num.Decimal{ 186 "node1": num.DecimalFromFloat(0.2), 187 "node2": num.DecimalFromFloat(0.8), 188 }, 189 }, &types.ScoreData{ 190 NodeIDSlice: []string{"node3", "node4"}, 191 NormalisedScores: map[string]num.Decimal{ 192 "node3": num.DecimalFromFloat(0.6), 193 "node4": num.DecimalFromFloat(0.4), 194 }, 195 } 196 }) 197 198 err = testEngine.collateral.IncrementBalance(context.Background(), rewardAccount.ID, num.NewUint(1000000)) 199 require.Nil(t, err) 200 201 payouts := engine.calculateRewardPayouts(context.Background(), epoch) 202 primary := payouts[0] 203 ersatz := payouts[1] 204 205 // calculation 206 // party1 should get 172500 => 100000 207 // party2 should get 15000 => 15000 208 // node1 should get 150000 => 100000 209 // node2 should get 600000 => 100000 210 // node3 should get 37500 211 // node4 should get 25000 212 213 require.Equal(t, 4, len(primary.partyToAmount)) 214 215 require.Equal(t, num.NewUint(100000), primary.partyToAmount["party1"]) 216 require.Equal(t, num.NewUint(15000), primary.partyToAmount["party2"]) 217 require.Equal(t, num.NewUint(100000), primary.partyToAmount["node1"]) 218 require.Equal(t, num.NewUint(100000), primary.partyToAmount["node2"]) 219 require.Equal(t, num.NewUint(37500), ersatz.partyToAmount["node3"]) 220 require.Equal(t, num.NewUint(25000), ersatz.partyToAmount["node4"]) 221 require.Equal(t, epoch.EndTime.UnixNano(), primary.timestamp) 222 require.Equal(t, epoch.EndTime.UnixNano(), ersatz.timestamp) 223 require.Equal(t, num.NewUint(315000), primary.totalReward) 224 require.Equal(t, num.NewUint(62500), ersatz.totalReward) 225 } 226 227 // test payout distribution. 228 func testDistributePayout(t *testing.T) { 229 testEngine := getEngine(t) 230 now := time.Now() 231 testEngine.timeService.EXPECT().GetTimeNow().DoAndReturn( 232 func() time.Time { 233 return now 234 }).AnyTimes() 235 236 engine := testEngine.engine 237 require.NoError(t, engine.UpdateAssetForStakingAndDelegation(context.Background(), "VEGA")) 238 require.NoError(t, engine.UpdateMinimumValidatorStakeForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(0))) 239 require.NoError(t, engine.UpdateMinValidatorsStakingRewardScheme(context.Background(), 5)) 240 require.NoError(t, engine.UpdateOptimalStakeMultiplierStakingRewardScheme(context.Background(), num.DecimalFromFloat(5))) 241 require.NoError(t, engine.UpdateErsatzRewardFactor(context.Background(), num.DecimalFromFloat(0.5))) 242 243 // setup balance of reward account 244 rewardAccount, err := testEngine.collateral.GetGlobalRewardAccount("VEGA") 245 require.NoError(t, err) 246 err = testEngine.collateral.IncrementBalance(context.Background(), rewardAccount.ID, num.NewUint(1000000)) 247 require.Nil(t, err) 248 partyToAmount := map[string]*num.Uint{} 249 partyToAmount["party1"] = num.NewUint(5000) 250 251 payout := &payout{ 252 fromAccount: rewardAccount.ID, 253 totalReward: num.NewUint(5000), 254 partyToAmount: partyToAmount, 255 asset: "VEGA", 256 } 257 258 // testEngine.broker.EXPECT().SendBatch(gomock.Any()).Times(1) 259 engine.distributePayout(context.Background(), payout) 260 261 rewardAccount, _ = engine.collateral.GetAccountByID(rewardAccount.ID) 262 partyAccount := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(context.Background(), "party1", "VEGA") 263 require.Nil(t, err) 264 265 require.Equal(t, num.NewUint(5000), partyAccount.Balance) 266 require.Equal(t, num.NewUint(995000), rewardAccount.Balance) 267 } 268 269 // test payout distribution on epoch end with no delay. 270 func testOnEpochEventNoPayoutDelay(t *testing.T) { 271 testEngine := getEngine(t) 272 now := time.Now() 273 testEngine.timeService.EXPECT().GetTimeNow().DoAndReturn( 274 func() time.Time { 275 return now 276 }).AnyTimes() 277 278 engine := testEngine.engine 279 require.NoError(t, engine.UpdateAssetForStakingAndDelegation(context.Background(), "VEGA")) 280 require.NoError(t, engine.UpdateDelegatorShareForStakingRewardScheme(context.Background(), num.DecimalFromFloat(0.3))) 281 require.NoError(t, engine.UpdateMinimumValidatorStakeForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(0))) 282 require.NoError(t, engine.UpdateCompetitionLevelForStakingRewardScheme(context.Background(), num.DecimalFromFloat(1.1))) 283 require.NoError(t, engine.UpdateMinValidatorsStakingRewardScheme(context.Background(), 5)) 284 require.NoError(t, engine.UpdateOptimalStakeMultiplierStakingRewardScheme(context.Background(), num.DecimalFromFloat(5))) 285 require.NoError(t, engine.UpdateMaxPayoutPerParticipantForStakingRewardScheme(context.Background(), num.DecimalZero())) 286 require.NoError(t, engine.UpdateErsatzRewardFactor(context.Background(), num.DecimalFromFloat(0.5))) 287 288 testEngine.delegation.EXPECT().GetValidatorData().AnyTimes() 289 testEngine.topology.EXPECT().RecalcValidatorSet(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 290 testEngine.topology.EXPECT().GetRewardsScores(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, epochSeq string, delegationState []*types.ValidatorData, stakeScoreParams types.StakeScoreParams) (*types.ScoreData, *types.ScoreData) { 291 return &types.ScoreData{ 292 NodeIDSlice: []string{"node1", "node2"}, 293 NormalisedScores: map[string]num.Decimal{ 294 "node1": num.DecimalFromFloat(0.2), 295 "node2": num.DecimalFromFloat(0.8), 296 }, 297 }, &types.ScoreData{ 298 NodeIDSlice: []string{"node3", "node4"}, 299 NormalisedScores: map[string]num.Decimal{ 300 "node3": num.DecimalFromFloat(0.6), 301 "node4": num.DecimalFromFloat(0.4), 302 }, 303 } 304 }).AnyTimes() 305 306 // setup reward account balance 307 rewardAccount, err := testEngine.collateral.GetGlobalRewardAccount("VEGA") 308 require.NoError(t, err) 309 err = testEngine.collateral.IncrementBalance(context.Background(), rewardAccount.ID, num.NewUint(1000000)) 310 require.Nil(t, err) 311 312 // there is remaining 1000000 to distribute as payout 313 epoch := types.Epoch{StartTime: now, EndTime: now} 314 315 testEngine.delegation.EXPECT().ProcessEpochDelegations(gomock.Any(), gomock.Any()).Return(testEngine.validatorData) 316 engine.OnEpochEvent(context.Background(), epoch) 317 318 // get party account balances 319 ctx := context.Background() 320 party1Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "party1", "VEGA") 321 party2Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "party2", "VEGA") 322 node1Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "node1", "VEGA") 323 node2Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "node2", "VEGA") 324 node3Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "node3", "VEGA") 325 node4Acc := testEngine.collateral.GetOrCreatePartyVestingRewardAccount(ctx, "node4", "VEGA") 326 327 require.Equal(t, num.NewUint(172500), party1Acc.Balance) 328 require.Equal(t, num.NewUint(15000), party2Acc.Balance) 329 require.Equal(t, num.NewUint(150000), node1Acc.Balance) 330 require.Equal(t, num.NewUint(600000), node2Acc.Balance) 331 require.Equal(t, num.NewUint(37500), node3Acc.Balance) 332 require.Equal(t, num.NewUint(25000), node4Acc.Balance) 333 } 334 335 func TestErsatzTendermintRewardSplit(t *testing.T) { 336 testEngine := getEngine(t) 337 now := time.Now() 338 testEngine.timeService.EXPECT().GetTimeNow().DoAndReturn( 339 func() time.Time { 340 return now 341 }).AnyTimes() 342 343 engine := testEngine.engine 344 require.NoError(t, engine.UpdateAssetForStakingAndDelegation(context.Background(), "VEGA")) 345 require.NoError(t, engine.UpdateDelegatorShareForStakingRewardScheme(context.Background(), num.DecimalFromFloat(0.3))) 346 require.NoError(t, engine.UpdateMinimumValidatorStakeForStakingRewardScheme(context.Background(), num.NewDecimalFromFloat(0))) 347 require.NoError(t, engine.UpdateCompetitionLevelForStakingRewardScheme(context.Background(), num.DecimalFromFloat(1.1))) 348 require.NoError(t, engine.UpdateMinValidatorsStakingRewardScheme(context.Background(), 5)) 349 require.NoError(t, engine.UpdateOptimalStakeMultiplierStakingRewardScheme(context.Background(), num.DecimalFromFloat(5))) 350 require.NoError(t, engine.UpdateMaxPayoutPerParticipantForStakingRewardScheme(context.Background(), num.DecimalZero())) 351 require.NoError(t, engine.UpdateErsatzRewardFactor(context.Background(), num.DecimalFromFloat(0.5))) 352 353 testEngine.delegation.EXPECT().GetValidatorData().AnyTimes() 354 testEngine.topology.EXPECT().RecalcValidatorSet(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 355 testEngine.topology.EXPECT().GetRewardsScores(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, epochSeq string, delegationState []*types.ValidatorData, stakeScoreParams types.StakeScoreParams) (*types.ScoreData, *types.ScoreData) { 356 return &types.ScoreData{ 357 NodeIDSlice: []string{"node1", "node2"}, 358 NormalisedScores: map[string]num.Decimal{ 359 "node1": num.DecimalFromFloat(0.2), 360 "node2": num.DecimalFromFloat(0.8), 361 }, 362 }, &types.ScoreData{ 363 NodeIDSlice: []string{"node3", "node4"}, 364 NormalisedScores: map[string]num.Decimal{ 365 "node3": num.DecimalFromFloat(0.6), 366 "node4": num.DecimalFromFloat(0.4), 367 }, 368 } 369 }).AnyTimes() 370 371 // setup reward account balance 372 rewardAccount := testEngine.collateral.GetInfraFeeAccountIDs()[0] 373 err := testEngine.collateral.IncrementBalance(context.Background(), rewardAccount, num.NewUint(1000000)) 374 require.Nil(t, err) 375 376 // there is remaining 1000000 to distribute as payout 377 epoch := types.Epoch{StartTime: now, EndTime: now} 378 379 testEngine.delegation.EXPECT().ProcessEpochDelegations(gomock.Any(), gomock.Any()).Return(testEngine.validatorData) 380 engine.OnEpochEvent(context.Background(), epoch) 381 382 // given the delegation breakdown we expect 383 // tendermint validators to get 0.9375 x 1000000 => 937500 384 // ersatzh validators to get => 0.0625 x 1000000 => 62500 385 // in the tendermint validators node1 gets 0.2 x 937500 => 187500 and node2 gets 0.8 x 937500 => 750000 386 // in the tendermint validators node3 gets 0.6 x 62500 => 37500 and node4 gets 0.4 x 62500 => 25000 387 // from tendermint validators reward balance: 388 // party1 gets 172500 389 // party2 gets 15000 390 // node1 gets 150000 391 // node2 gets 600000 392 // from ersatz validators reward balance: 393 // node3 gets 37500 394 // node 4 gets 25000 395 396 // get party account balances 397 party1Acc, _ := testEngine.collateral.GetPartyGeneralAccount("party1", "VEGA") 398 party2Acc, _ := testEngine.collateral.GetPartyGeneralAccount("party2", "VEGA") 399 node1Acc, _ := testEngine.collateral.GetPartyGeneralAccount("node1", "VEGA") 400 node2Acc, _ := testEngine.collateral.GetPartyGeneralAccount("node2", "VEGA") 401 node3Acc, _ := testEngine.collateral.GetPartyGeneralAccount("node3", "VEGA") 402 node4Acc, _ := testEngine.collateral.GetPartyGeneralAccount("node4", "VEGA") 403 404 require.Equal(t, num.NewUint(172500), party1Acc.Balance) 405 require.Equal(t, num.NewUint(15000), party2Acc.Balance) 406 require.Equal(t, num.NewUint(150000), node1Acc.Balance) 407 require.Equal(t, num.NewUint(600000), node2Acc.Balance) 408 require.Equal(t, num.NewUint(37500), node3Acc.Balance) 409 require.Equal(t, num.NewUint(25000), node4Acc.Balance) 410 } 411 412 type testEngine struct { 413 engine *Engine 414 ctrl *gomock.Controller 415 timeService *mocks.MockTimeService 416 broker *bmocks.MockBroker 417 epochEngine *TestEpochEngine 418 delegation *mocks.MockDelegation 419 collateral *collateral.Engine 420 validatorData []*types.ValidatorData 421 topology *mocks.MockTopology 422 } 423 424 func getEngine(t *testing.T) *testEngine { 425 t.Helper() 426 conf := NewDefaultConfig() 427 ctrl := gomock.NewController(t) 428 broker := bmocks.NewMockBroker(ctrl) 429 logger := logging.NewTestLogger() 430 delegation := mocks.NewMockDelegation(ctrl) 431 epochEngine := &TestEpochEngine{ 432 callbacks: []func(context.Context, types.Epoch){}, 433 restore: []func(context.Context, types.Epoch){}, 434 } 435 ts := mocks.NewMockTimeService(ctrl) 436 437 broker.EXPECT().Send(gomock.Any()).AnyTimes() 438 broker.EXPECT().SendBatch(gomock.Any()).AnyTimes() 439 440 collateralEng := collateral.New(logger, collateral.NewDefaultConfig(), ts, broker) 441 asset := types.Asset{ 442 ID: "VEGA", 443 Details: &types.AssetDetails{ 444 Symbol: "VEGA", 445 Quantum: num.DecimalFromFloat(1), 446 }, 447 } 448 449 require.NoError(t, collateralEng.EnableAsset(context.Background(), asset)) 450 topology := mocks.NewMockTopology(ctrl) 451 marketActivityTracker := mocks.NewMockMarketActivityTracker(ctrl) 452 vesting := mocks.NewMockVesting(ctrl) 453 vesting.EXPECT().AddReward(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 454 transfers := mocks.NewMockTransfers(ctrl) 455 activityStreak := mocks.NewMockActivityStreak(ctrl) 456 engine := New(logger, conf, broker, delegation, epochEngine, collateralEng, ts, marketActivityTracker, topology, vesting, transfers, activityStreak) 457 458 broker.EXPECT().Send(gomock.Any()).AnyTimes() 459 460 delegatorForVal1 := map[string]*num.Uint{} 461 delegatorForVal1["party1"] = num.NewUint(6000) 462 delegatorForVal1["party2"] = num.NewUint(4000) 463 validator1 := &types.ValidatorData{ 464 NodeID: "node1", 465 PubKey: "node1", 466 SelfStake: num.NewUint(5000), 467 StakeByDelegators: num.NewUint(10000), 468 Delegators: delegatorForVal1, 469 } 470 delegatorForVal2 := map[string]*num.Uint{} 471 delegatorForVal2["party1"] = num.NewUint(40000) 472 validator2 := &types.ValidatorData{ 473 NodeID: "node2", 474 PubKey: "node2", 475 SelfStake: num.NewUint(20000), 476 StakeByDelegators: num.NewUint(40000), 477 Delegators: delegatorForVal2, 478 } 479 480 validator3 := &types.ValidatorData{ 481 NodeID: "node3", 482 PubKey: "node3", 483 SelfStake: num.NewUint(4000), 484 StakeByDelegators: num.UintZero(), 485 Delegators: map[string]*num.Uint{}, 486 } 487 488 validator4 := &types.ValidatorData{ 489 NodeID: "node4", 490 PubKey: "node4", 491 SelfStake: num.NewUint(6000), 492 StakeByDelegators: num.UintZero(), 493 Delegators: map[string]*num.Uint{}, 494 } 495 496 validatorData := []*types.ValidatorData{validator1, validator2, validator3, validator4} 497 498 return &testEngine{ 499 engine: engine, 500 ctrl: ctrl, 501 timeService: ts, 502 broker: broker, 503 epochEngine: epochEngine, 504 delegation: delegation, 505 collateral: collateralEng, 506 validatorData: validatorData, 507 topology: topology, 508 } 509 } 510 511 type TestEpochEngine struct { 512 callbacks []func(context.Context, types.Epoch) 513 restore []func(context.Context, types.Epoch) 514 } 515 516 func (e *TestEpochEngine) NotifyOnEpoch(f func(context.Context, types.Epoch), r func(context.Context, types.Epoch)) { 517 e.callbacks = append(e.callbacks, f) 518 e.restore = append(e.callbacks, r) 519 } 520 521 func (e *TestEpochEngine) GetTimeNow() time.Time { 522 return time.Now() 523 }