code.vegaprotocol.io/vega@v0.79.0/core/vesting/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 vesting_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/assets" 24 "code.vegaprotocol.io/vega/core/types" 25 "code.vegaprotocol.io/vega/libs/num" 26 vgtest "code.vegaprotocol.io/vega/libs/test" 27 "code.vegaprotocol.io/vega/paths" 28 vegapb "code.vegaprotocol.io/vega/protos/vega" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 func TestSnapshotEngine(t *testing.T) { 36 ctx := vgtest.VegaContext("chainid", 100) 37 38 vegaPath := paths.New(t.TempDir()) 39 now := time.Now() 40 41 te1 := newEngine(t) 42 snapshotEngine1 := newSnapshotEngine(t, vegaPath, now, te1.engine) 43 closeSnapshotEngine1 := vgtest.OnlyOnce(snapshotEngine1.Close) 44 defer closeSnapshotEngine1() 45 46 require.NoError(t, snapshotEngine1.Start(ctx)) 47 48 setupMocks(t, te1) 49 setupNetParams(ctx, t, te1) 50 51 te1.engine.AddReward(context.Background(), "party1", "eth", num.NewUint(100), 4) 52 te1.engine.AddReward(context.Background(), "party1", "btc", num.NewUint(150), 1) 53 te1.engine.AddReward(context.Background(), "party1", "eth", num.NewUint(200), 0) 54 55 nextEpoch(ctx, t, te1, time.Now()) 56 57 te1.engine.AddReward(context.Background(), "party2", "btc", num.NewUint(100), 2) 58 te1.engine.AddReward(context.Background(), "party3", "btc", num.NewUint(100), 0) 59 60 nextEpoch(ctx, t, te1, time.Now()) 61 62 te1.engine.AddReward(context.Background(), "party4", "eth", num.NewUint(100), 1) 63 te1.engine.AddReward(context.Background(), "party5", "doge", num.NewUint(100), 0) 64 65 // Take a snapshot. 66 hash1, err := snapshotEngine1.SnapshotNow(ctx) 67 require.NoError(t, err) 68 snapshottedEpoch := te1.currentEpoch 69 70 // This is what must be replayed after snapshot restoration. 71 replayFn := func(te *testSnapshotEngine) { 72 te.engine.AddReward(context.Background(), "party6", "doge", num.NewUint(100), 3) 73 74 nextEpoch(ctx, t, te, time.Now()) 75 76 te.engine.AddReward(context.Background(), "party7", "eth", num.NewUint(100), 2) 77 te.engine.AddReward(context.Background(), "party8", "vega", num.NewUint(100), 10) 78 79 nextEpoch(ctx, t, te, time.Now()) 80 } 81 82 replayFn(te1) 83 84 state1 := map[string][]byte{} 85 for _, key := range te1.engine.Keys() { 86 state, additionalProvider, err := te1.engine.GetState(key) 87 require.NoError(t, err) 88 assert.Empty(t, additionalProvider) 89 state1[key] = state 90 } 91 92 closeSnapshotEngine1() 93 94 // Reload the engine using the previous snapshot. 95 96 te2 := newEngine(t) 97 snapshotEngine2 := newSnapshotEngine(t, vegaPath, now, te2.engine) 98 defer snapshotEngine2.Close() 99 100 setupMocks(t, te2) 101 setupNetParams(ctx, t, te2) 102 103 // Ensure the engine's epoch (and test helpers) starts at the same epoch the 104 // first engine has been snapshotted. 105 te2.currentEpoch = snapshottedEpoch 106 te2.engine.OnEpochRestore(ctx, types.Epoch{ 107 Seq: snapshottedEpoch, 108 Action: vegapb.EpochAction_EPOCH_ACTION_START, 109 }) 110 111 // This triggers the state restoration from the local snapshot. 112 require.NoError(t, snapshotEngine2.Start(ctx)) 113 114 // Comparing the hash after restoration, to ensure it produces the same result. 115 hash2, _, _ := snapshotEngine2.Info() 116 require.Equal(t, hash1, hash2) 117 118 // Replaying the same commands after snapshot has been taken with first engine. 119 replayFn(te2) 120 121 state2 := map[string][]byte{} 122 for _, key := range te2.engine.Keys() { 123 state, additionalProvider, err := te2.engine.GetState(key) 124 require.NoError(t, err) 125 assert.Empty(t, additionalProvider) 126 state2[key] = state 127 } 128 129 for key := range state1 { 130 assert.Equalf(t, state1[key], state2[key], "Key %q does not have the same data", key) 131 } 132 } 133 134 func setupNetParams(ctx context.Context, t *testing.T, te *testSnapshotEngine) { 135 t.Helper() 136 137 require.NoError(t, te.engine.OnBenefitTiersUpdate(ctx, &vegapb.VestingBenefitTiers{ 138 Tiers: []*vegapb.VestingBenefitTier{ 139 { 140 MinimumQuantumBalance: "10000", 141 RewardMultiplier: "1.5", 142 }, 143 { 144 MinimumQuantumBalance: "100000", 145 RewardMultiplier: "2", 146 }, 147 { 148 MinimumQuantumBalance: "500000", 149 RewardMultiplier: "2.5", 150 }, 151 }, 152 })) 153 154 require.NoError(t, te.engine.OnRewardVestingBaseRateUpdate(ctx, num.MustDecimalFromString("0.9"))) 155 require.NoError(t, te.engine.OnRewardVestingMinimumTransferUpdate(ctx, num.MustDecimalFromString("1"))) 156 } 157 158 func setupMocks(t *testing.T, te *testSnapshotEngine) { 159 t.Helper() 160 161 te.asvm.EXPECT().GetRewardsVestingMultiplier(gomock.Any()).AnyTimes().Return(num.MustDecimalFromString("1")) 162 te.assets.EXPECT().Get(gomock.Any()).AnyTimes().Return(assets.NewAsset(dummyAsset{quantum: 10}), nil) 163 te.broker.EXPECT().Send(gomock.Any()).AnyTimes() 164 te.parties.EXPECT().RelatedKeys(gomock.Any()).AnyTimes() 165 }