code.vegaprotocol.io/vega@v0.79.0/core/vesting/helper_for_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 vesting_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/assets/common" 24 bmocks "code.vegaprotocol.io/vega/core/broker/mocks" 25 "code.vegaprotocol.io/vega/core/integration/stubs" 26 "code.vegaprotocol.io/vega/core/snapshot" 27 "code.vegaprotocol.io/vega/core/stats" 28 "code.vegaprotocol.io/vega/core/types" 29 "code.vegaprotocol.io/vega/core/vesting" 30 "code.vegaprotocol.io/vega/core/vesting/mocks" 31 "code.vegaprotocol.io/vega/libs/num" 32 "code.vegaprotocol.io/vega/logging" 33 "code.vegaprotocol.io/vega/paths" 34 vegapb "code.vegaprotocol.io/vega/protos/vega" 35 36 "github.com/golang/mock/gomock" 37 "github.com/stretchr/testify/require" 38 ) 39 40 type testEngine struct { 41 *vesting.Engine 42 43 ctrl *gomock.Controller 44 col *collateralMock 45 asvm *mocks.MockActivityStreakVestingMultiplier 46 broker *bmocks.MockBroker 47 assets *mocks.MockAssets 48 parties *mocks.MockParties 49 t *mocks.MockTime 50 stakeAccounting *mocks.MockStakeAccounting 51 } 52 53 func getTestEngine(t *testing.T) *testEngine { 54 t.Helper() 55 ctrl := gomock.NewController(t) 56 logger := logging.NewTestLogger() 57 col := newCollateralMock(t) 58 broker := bmocks.NewMockBroker(ctrl) 59 asvm := mocks.NewMockActivityStreakVestingMultiplier(ctrl) 60 assets := mocks.NewMockAssets(ctrl) 61 parties := mocks.NewMockParties(ctrl) 62 tim := mocks.NewMockTime(ctrl) 63 stakeAccounting := mocks.NewMockStakeAccounting(ctrl) 64 65 return &testEngine{ 66 Engine: vesting.New( 67 logger, col, asvm, broker, assets, parties, tim, stakeAccounting, 68 ), 69 ctrl: ctrl, 70 broker: broker, 71 col: col, 72 asvm: asvm, 73 assets: assets, 74 parties: parties, 75 t: tim, 76 stakeAccounting: stakeAccounting, 77 } 78 } 79 80 type testSnapshotEngine struct { 81 engine *vesting.SnapshotEngine 82 83 ctrl *gomock.Controller 84 col *collateralMock 85 asvm *mocks.MockActivityStreakVestingMultiplier 86 broker *bmocks.MockBroker 87 assets *mocks.MockAssets 88 parties *mocks.MockParties 89 t *mocks.MockTime 90 stakeAccounting *mocks.MockStakeAccounting 91 92 currentEpoch uint64 93 } 94 95 func newEngine(t *testing.T) *testSnapshotEngine { 96 t.Helper() 97 ctrl := gomock.NewController(t) 98 col := newCollateralMock(t) 99 asvm := mocks.NewMockActivityStreakVestingMultiplier(ctrl) 100 broker := bmocks.NewMockBroker(ctrl) 101 assets := mocks.NewMockAssets(ctrl) 102 parties := mocks.NewMockParties(ctrl) 103 tim := mocks.NewMockTime(ctrl) 104 stakeAccounting := mocks.NewMockStakeAccounting(ctrl) 105 106 return &testSnapshotEngine{ 107 engine: vesting.NewSnapshotEngine( 108 logging.NewTestLogger(), col, asvm, broker, assets, parties, tim, stakeAccounting, 109 ), 110 ctrl: ctrl, 111 col: col, 112 asvm: asvm, 113 broker: broker, 114 assets: assets, 115 parties: parties, 116 currentEpoch: 10, 117 t: tim, 118 stakeAccounting: stakeAccounting, 119 } 120 } 121 122 type collateralMock struct { 123 vestedAccountAmount map[string]map[string]*num.Uint 124 vestingQuantumBalanceCallCount int 125 } 126 127 func (c *collateralMock) InitVestedBalance(party, asset string, balance *num.Uint) { 128 c.vestedAccountAmount[party] = map[string]*num.Uint{ 129 asset: balance, 130 } 131 } 132 133 func (c *collateralMock) TransferVestedRewards(_ context.Context, transfers []*types.Transfer) ([]*types.LedgerMovement, error) { 134 for _, transfer := range transfers { 135 vestedAccount, ok := c.vestedAccountAmount[transfer.Owner] 136 if !ok { 137 vestedAccount = map[string]*num.Uint{} 138 c.vestedAccountAmount[transfer.Owner] = map[string]*num.Uint{} 139 } 140 141 amount, ok := vestedAccount[transfer.Amount.Asset] 142 if !ok { 143 amount = num.UintZero() 144 vestedAccount[transfer.Amount.Asset] = amount 145 } 146 147 amount.AddSum(transfer.Amount.Amount) 148 } 149 return []*types.LedgerMovement{}, nil 150 } 151 152 func (c *collateralMock) GetVestingRecovery() map[string]map[string]*num.Uint { 153 // Only used for checkpoint. 154 return nil 155 } 156 157 // GetAllVestingQuantumBalance is a custom implementation used to ensure 158 // the vesting engine account for benefit tiers during computation. 159 // Using this implementation saves us from mocking this at every call to 160 // `OnEpochEvent()` with consistent results. 161 func (c *collateralMock) GetAllVestingQuantumBalance(party string) num.Decimal { 162 vestedAccount, ok := c.vestedAccountAmount[party] 163 if !ok { 164 return num.DecimalZero() 165 } 166 167 balance := num.DecimalZero() 168 for _, n := range vestedAccount { 169 balance = balance.Add(num.DecimalFromUint(n)) 170 } 171 172 c.vestingQuantumBalanceCallCount += 1 173 174 return balance 175 } 176 177 func (c *collateralMock) ResetVestingQuantumBalanceCallCount() { 178 c.vestingQuantumBalanceCallCount = 0 179 } 180 181 func (c *collateralMock) GetVestingQuantumBalanceCallCount() int { 182 return c.vestingQuantumBalanceCallCount 183 } 184 185 func (c *collateralMock) GetAllVestingAndVestedAccountForAsset(asset string) []*types.Account { 186 return nil 187 } 188 189 func newCollateralMock(t *testing.T) *collateralMock { 190 t.Helper() 191 192 return &collateralMock{ 193 vestedAccountAmount: make(map[string]map[string]*num.Uint), 194 } 195 } 196 197 type dummyAsset struct { 198 quantum uint64 199 } 200 201 func (d dummyAsset) Type() *types.Asset { 202 return &types.Asset{ 203 Details: &types.AssetDetails{ 204 Quantum: num.DecimalFromInt64(int64(d.quantum)), 205 }, 206 } 207 } 208 209 func (dummyAsset) GetAssetClass() common.AssetClass { return common.ERC20 } 210 func (dummyAsset) IsValid() bool { return true } 211 func (dummyAsset) SetPendingListing() {} 212 func (dummyAsset) SetRejected() {} 213 func (dummyAsset) SetEnabled() {} 214 func (dummyAsset) SetValid() {} 215 func (dummyAsset) String() string { return "" } 216 217 func newSnapshotEngine(t *testing.T, vegaPath paths.Paths, now time.Time, engine *vesting.SnapshotEngine) *snapshot.Engine { 218 t.Helper() 219 220 log := logging.NewTestLogger() 221 timeService := stubs.NewTimeStub() 222 timeService.SetTime(now) 223 statsData := stats.New(log, stats.NewDefaultConfig()) 224 config := snapshot.DefaultConfig() 225 226 snapshotEngine, err := snapshot.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain) 227 require.NoError(t, err) 228 229 snapshotEngine.AddProviders(engine) 230 231 return snapshotEngine 232 } 233 234 func nextEpoch(ctx context.Context, t *testing.T, te *testSnapshotEngine, startEpochTime time.Time) { 235 t.Helper() 236 237 te.engine.OnEpochEvent(ctx, types.Epoch{ 238 Seq: te.currentEpoch, 239 Action: vegapb.EpochAction_EPOCH_ACTION_END, 240 EndTime: startEpochTime.Add(-1 * time.Second), 241 }) 242 243 te.currentEpoch += 1 244 te.engine.OnEpochEvent(ctx, types.Epoch{ 245 Seq: te.currentEpoch, 246 Action: vegapb.EpochAction_EPOCH_ACTION_START, 247 StartTime: startEpochTime, 248 }) 249 }