code.vegaprotocol.io/vega@v0.79.0/core/monitor/price/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 price_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/monitor/price" 24 "code.vegaprotocol.io/vega/core/monitor/price/mocks" 25 "code.vegaprotocol.io/vega/core/types" 26 "code.vegaprotocol.io/vega/libs/crypto" 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 32 "github.com/golang/mock/gomock" 33 "github.com/stretchr/testify/assert" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func createPriceMonitor(t *testing.T, ctrl *gomock.Controller) *price.Engine { 38 t.Helper() 39 40 riskModel, auctionState, settings := createPriceMonitorDeps(t, ctrl) 41 statevar := mocks.NewMockStateVarEngine(ctrl) 42 statevar.EXPECT().RegisterStateVariable(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) 43 auctionState.EXPECT().IsPriceAuction().Times(1).Return(false) 44 45 pm, err := price.NewMonitor("asset", "market", riskModel, auctionState, settings, statevar, logging.NewTestLogger()) 46 require.NoError(t, err) 47 require.NotNil(t, pm) 48 49 return pm 50 } 51 52 func createPriceMonitorDeps(t *testing.T, ctrl *gomock.Controller) (*mocks.MockRangeProvider, *mocks.MockAuctionState, *types.PriceMonitoringSettings) { 53 t.Helper() 54 riskModel := mocks.NewMockRangeProvider(ctrl) 55 auctionStateMock := mocks.NewMockAuctionState(ctrl) 56 57 settings := &types.PriceMonitoringSettings{ 58 Parameters: &types.PriceMonitoringParameters{ 59 Triggers: []*types.PriceMonitoringTrigger{}, 60 }, 61 } 62 63 auctionStateMock.EXPECT().IsFBA().Return(false).AnyTimes() 64 auctionStateMock.EXPECT().InAuction().Return(false).AnyTimes() 65 66 return riskModel, auctionStateMock, settings 67 } 68 69 func getHash(pe *price.Engine) []byte { 70 state := pe.GetState() 71 pmproto := state.IntoProto() 72 bytes, _ := proto.Marshal(pmproto) 73 return crypto.Hash(bytes) 74 } 75 76 func TestEmpty(t *testing.T) { 77 ctrl := gomock.NewController(t) 78 defer ctrl.Finish() 79 80 pm1 := createPriceMonitor(t, ctrl) 81 assert.NotNil(t, pm1) 82 83 // Get the initial state 84 hash1 := getHash(pm1) 85 state1 := pm1.GetState() 86 87 // Create a new market and restore into it 88 riskModel, auctionState, settings := createPriceMonitorDeps(t, ctrl) 89 90 statevar := mocks.NewMockStateVarEngine(ctrl) 91 statevar.EXPECT().RegisterStateVariable(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) 92 pm2, err := price.NewMonitorFromSnapshot("marketID", "assetID", state1, settings, riskModel, auctionState, statevar, logging.NewTestLogger()) 93 require.NoError(t, err) 94 require.NotNil(t, pm2) 95 96 // Now get the state again and check it against the original 97 hash2 := getHash(pm2) 98 99 assert.Equal(t, hash1, hash2) 100 } 101 102 func TestChangedState(t *testing.T) { 103 ctrl := gomock.NewController(t) 104 defer ctrl.Finish() 105 106 pm1 := createPriceMonitor(t, ctrl) 107 assert.NotNil(t, pm1) 108 109 // Get the initial state 110 hash1 := getHash(pm1) 111 112 // Perform some actions on the object 113 as := mocks.NewMockAuctionState(ctrl) 114 as.EXPECT().IsFBA().Return(false).Times(10) 115 as.EXPECT().InAuction().Return(false).Times(10) 116 117 now := time.Now() 118 119 for i := 0; i < 10; i++ { 120 pm1.OnTimeUpdate(now) 121 p := num.NewUint(uint64(100 + i)) 122 b := pm1.CheckPrice(context.Background(), as, p, true, true) 123 now = now.Add(time.Minute * 1) 124 require.False(t, b) 125 } 126 127 // Check something has changed 128 assert.True(t, pm1.Changed()) 129 130 // Get the new hash after the change 131 hash2 := getHash(pm1) 132 assert.NotEqual(t, hash1, hash2) 133 134 // Now try reloading the state 135 state := pm1.GetState() 136 assert.Len(t, state.PricesNow, 1) 137 assert.Len(t, state.PricesPast, 9) 138 139 riskModel, auctionState, settings := createPriceMonitorDeps(t, ctrl) 140 statevar := mocks.NewMockStateVarEngine(ctrl) 141 statevar.EXPECT().RegisterStateVariable(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(1) 142 pm2, err := price.NewMonitorFromSnapshot("marketID", "assetID", state, settings, riskModel, auctionState, statevar, logging.NewTestLogger()) 143 require.NoError(t, err) 144 require.NotNil(t, pm2) 145 146 hash3 := getHash(pm2) 147 assert.Equal(t, hash2, hash3) 148 149 state2 := pm1.GetState() 150 assert.Len(t, state2.PricesNow, 1) 151 assert.Len(t, state2.PricesPast, 9) 152 153 asProto := state2.IntoProto() 154 state3 := types.PriceMonitorFromProto(asProto) 155 assert.Len(t, state3.PricesNow, 1) 156 assert.Len(t, state3.PricesPast, 9) 157 assert.Equal(t, state2.Now.UnixNano(), state3.Now.UnixNano()) 158 assert.Equal(t, state2.Update.UnixNano(), state3.Update.UnixNano()) 159 assert.Equal(t, state2.PricesPast[0].Time.UnixNano(), state3.PricesPast[0].Time.UnixNano()) 160 } 161 162 func TestRestorePriceBoundRepresentation(t *testing.T) { 163 ctrl := gomock.NewController(t) 164 defer ctrl.Finish() 165 riskModel := mocks.NewMockRangeProvider(ctrl) 166 auctionStateMock := mocks.NewMockAuctionState(ctrl) 167 currentPrice := num.NewUint(123) 168 now := time.Date(1993, 2, 2, 6, 0, 0, 1, time.UTC) 169 170 settings := types.PriceMonitoringSettingsFromProto(&vegapb.PriceMonitoringSettings{ 171 Parameters: &vegapb.PriceMonitoringParameters{ 172 Triggers: []*vegapb.PriceMonitoringTrigger{ 173 {Horizon: 3600, Probability: "0.99", AuctionExtension: 60}, 174 {Horizon: 7200, Probability: "0.95", AuctionExtension: 300}, 175 }, 176 }, 177 }) 178 179 _, pMin1, pMax1, _, _ := getPriceBounds(currentPrice, 1, 2) 180 _, pMin2, pMax2, _, _ := getPriceBounds(currentPrice, 3, 4) 181 currentPriceD := currentPrice.ToDecimal() 182 auctionStateMock.EXPECT().IsFBA().Return(false).AnyTimes() 183 auctionStateMock.EXPECT().InAuction().Return(false).AnyTimes() 184 auctionStateMock.EXPECT().IsPriceAuction().Return(false).AnyTimes() 185 statevar := mocks.NewMockStateVarEngine(ctrl) 186 statevar.EXPECT().RegisterStateVariable(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() 187 188 pm, err := price.NewMonitor("asset", "market", riskModel, auctionStateMock, settings, statevar, logging.NewTestLogger()) 189 require.NoError(t, err) 190 require.NotNil(t, pm) 191 downFactors := []num.Decimal{pMin1.Div(currentPriceD), pMin2.Div(currentPriceD)} 192 upFactors := []num.Decimal{pMax1.Div(currentPriceD), pMax2.Div(currentPriceD)} 193 194 pm.UpdateTestFactors(downFactors, upFactors) 195 196 pm.OnTimeUpdate(now) 197 b := pm.CheckPrice(context.Background(), auctionStateMock, currentPrice, true, true) 198 require.False(t, b) 199 200 state := pm.GetState() 201 snap, err := price.NewMonitorFromSnapshot("market", "asset", state, settings, riskModel, auctionStateMock, statevar, logging.NewTestLogger()) 202 require.NoError(t, err) 203 204 min, max := pm.GetValidPriceRange() 205 sMin, sMax := snap.GetValidPriceRange() 206 // check the values of the wrapped decimal are the same 207 require.Equal(t, min, sMin) 208 require.Equal(t, max, sMax) 209 }