code.vegaprotocol.io/vega@v0.79.0/core/positions/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 positions_test 17 18 import ( 19 "bytes" 20 "context" 21 "encoding/hex" 22 "testing" 23 "time" 24 25 "code.vegaprotocol.io/vega/core/positions" 26 "code.vegaprotocol.io/vega/core/types" 27 "code.vegaprotocol.io/vega/libs/crypto" 28 "code.vegaprotocol.io/vega/libs/num" 29 "code.vegaprotocol.io/vega/libs/proto" 30 snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 31 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34 ) 35 36 func fillTestPositions(e *positions.SnapshotEngine) { 37 orders := []*types.Order{ 38 { 39 Party: "test_party_1", 40 Side: types.SideBuy, 41 Size: uint64(100), 42 Remaining: uint64(100), 43 Price: num.UintZero(), 44 }, 45 { 46 Party: "test_party_2", 47 Side: types.SideBuy, 48 Size: uint64(200), 49 Remaining: uint64(200), 50 Price: num.UintZero(), 51 }, 52 } 53 54 matchingPrice := num.NewUint(10000) 55 tradeSize := uint64(15) 56 passiveOrder := &types.Order{ 57 ID: "buy_order_id", 58 Party: "test_party_3", 59 Side: types.SideBuy, 60 Size: tradeSize, 61 Remaining: tradeSize, 62 Price: matchingPrice, 63 } 64 65 aggresiveOrder := &types.Order{ 66 ID: "sell_order_id", 67 Party: "test_party_1", 68 Side: types.SideSell, 69 Size: tradeSize, 70 Remaining: tradeSize, 71 Price: matchingPrice, 72 } 73 74 orders = append(orders, passiveOrder, aggresiveOrder) 75 76 for _, order := range orders { 77 e.RegisterOrder(context.TODO(), order) 78 } 79 80 trade := types.Trade{ 81 Type: types.TradeTypeDefault, 82 ID: "trade_id", 83 MarketID: "market_id", 84 Price: matchingPrice, 85 Size: tradeSize, 86 Buyer: passiveOrder.Party, 87 Seller: aggresiveOrder.Party, 88 BuyOrder: passiveOrder.ID, 89 SellOrder: aggresiveOrder.ID, 90 Timestamp: time.Now().Unix(), 91 } 92 e.Update(context.Background(), &trade, passiveOrder, aggresiveOrder) 93 } 94 95 func TestSnapshotSaveAndLoad(t *testing.T) { 96 engine := getTestEngine(t) 97 fillTestPositions(engine) 98 99 keys := engine.Keys() 100 require.Equal(t, 1, len(keys)) 101 require.Equal(t, "test_market", keys[0]) 102 103 s1, _, err := engine.GetState(keys[0]) 104 require.Nil(t, err) 105 s2, _, err := engine.GetState(keys[0]) 106 require.Nil(t, err) 107 108 // With no change the states are equal 109 require.True(t, bytes.Equal(s1, s2)) 110 111 data, _, err := engine.GetState(keys[0]) 112 require.Nil(t, err) 113 114 snap := &snapshot.Payload{} 115 err = proto.Unmarshal(data, snap) 116 require.Nil(t, err) 117 118 snapEngine := getTestEngine(t) 119 _, err = snapEngine.LoadState( 120 context.TODO(), 121 types.PayloadFromProto(snap), 122 ) 123 require.Nil(t, err) 124 125 // Get state again 126 s3, _, err := snapEngine.GetState(keys[0]) 127 require.Nil(t, err) 128 require.True(t, bytes.Equal(s1, s3)) 129 require.Equal(t, len(engine.Positions()), len(snapEngine.Positions())) 130 for _, p := range engine.Positions() { 131 // find it in the other engine by partyID 132 pos, found := snapEngine.GetPositionByPartyID(p.Party()) 133 require.True(t, found) 134 require.Equal(t, p, pos) 135 } 136 } 137 138 func TestSnapshotStateNoChanges(t *testing.T) { 139 engine := getTestEngine(t) 140 fillTestPositions(engine) 141 142 keys := engine.Keys() 143 s1, _, err := engine.GetState(keys[0]) 144 require.Nil(t, err) 145 s2, _, err := engine.GetState(keys[0]) 146 require.Nil(t, err) 147 148 // With no changes we expect the states are equal 149 require.True(t, bytes.Equal(s1, s2)) 150 } 151 152 func TestSnapshotStateRegisterOrder(t *testing.T) { 153 engine := getTestEngine(t) 154 fillTestPositions(engine) 155 156 keys := engine.Keys() 157 s1, _, err := engine.GetState(keys[0]) 158 require.Nil(t, err) 159 160 // Add and order and the state should change 161 newOrder := &types.Order{ 162 Party: "test_party_1", 163 Side: types.SideBuy, 164 Size: uint64(150), 165 Remaining: uint64(150), 166 Price: num.UintZero(), 167 } 168 engine.RegisterOrder(context.TODO(), newOrder) 169 s2, _, err := engine.GetState(keys[0]) 170 require.Nil(t, err) 171 require.False(t, bytes.Equal(s1, s2)) 172 } 173 174 func TestSnapshotStateUnregisterOrder(t *testing.T) { 175 engine := getTestEngine(t) 176 fillTestPositions(engine) 177 178 keys := engine.Keys() 179 s1, _, err := engine.GetState(keys[0]) 180 require.Nil(t, err) 181 182 // Add and order and the state should change 183 newOrder := &types.Order{ 184 Party: "test_party_1", 185 Side: types.SideBuy, 186 Size: uint64(10), 187 Remaining: uint64(10), 188 Price: num.UintZero(), 189 } 190 engine.RegisterOrder(context.TODO(), newOrder) 191 s2, _, err := engine.GetState(keys[0]) 192 require.Nil(t, err) 193 require.False(t, bytes.Equal(s1, s2)) 194 } 195 196 func TestSnapshotStateAmendOrder(t *testing.T) { 197 engine := getTestEngine(t) 198 fillTestPositions(engine) 199 200 // Add and order and the state should change 201 newOrders := []*types.Order{ 202 { 203 Party: "test_party_1", 204 Side: types.SideBuy, 205 Size: uint64(100), 206 Remaining: uint64(100), 207 Price: num.UintZero(), 208 }, 209 { 210 Party: "test_party_1", 211 Side: types.SideBuy, 212 Size: uint64(90), 213 Remaining: uint64(90), 214 Price: num.UintZero(), 215 }, 216 } 217 engine.RegisterOrder(context.TODO(), newOrders[0]) 218 keys := engine.Keys() 219 s1, _, err := engine.GetState(keys[0]) 220 require.Nil(t, err) 221 222 // Amend it 223 engine.AmendOrder(context.TODO(), newOrders[0], newOrders[1]) 224 s2, _, err := engine.GetState(keys[0]) 225 require.Nil(t, err) 226 require.False(t, bytes.Equal(s1, s2)) 227 228 // Then amend it back, state should be the same as originally 229 engine.AmendOrder(context.TODO(), newOrders[1], newOrders[0]) 230 s2, _, err = engine.GetState(keys[0]) 231 require.Nil(t, err) 232 require.True(t, bytes.Equal(s1, s2)) 233 } 234 235 func TestSnapshotStateRemoveDistressed(t *testing.T) { 236 engine := getTestEngine(t) 237 fillTestPositions(engine) 238 239 keys := engine.Keys() 240 s1, _, err := engine.GetState(keys[0]) 241 require.Nil(t, err) 242 243 engine.RemoveDistressed(engine.Positions()) 244 s2, _, err := engine.GetState(keys[0]) 245 require.Nil(t, err) 246 require.False(t, bytes.Equal(s1, s2)) 247 } 248 249 func TestSnapshotStaeUpdateMarkPrice(t *testing.T) { 250 engine := getTestEngine(t) 251 fillTestPositions(engine) 252 253 keys := engine.Keys() 254 s1, _, err := engine.GetState(keys[0]) 255 require.Nil(t, err) 256 257 engine.UpdateMarkPrice(num.NewUint(12)) 258 s2, _, err := engine.GetState(keys[0]) 259 require.Nil(t, err) 260 require.False(t, bytes.Equal(s1, s2)) 261 } 262 263 func TestSnapshotHashNoPositions(t *testing.T) { 264 engine := getTestEngine(t) 265 266 keys := engine.Keys() 267 s1, _, err := engine.GetState(keys[0]) 268 require.Nil(t, err) 269 require.Equal(t, "278f2eff5adc1ea5b8365bd04c6e534ef64ca43df737c22ee61db46a8dac5870", hex.EncodeToString(crypto.Hash(s1))) 270 } 271 272 func TestStopSnapshotTaking(t *testing.T) { 273 engine := getTestEngine(t) 274 keys := engine.Keys() 275 276 // signal to kill the engine's snapshots 277 engine.StopSnapshots() 278 279 s, _, err := engine.GetState(keys[0]) 280 assert.NoError(t, err) 281 assert.Nil(t, s) 282 assert.True(t, engine.Stopped()) 283 } 284 285 func TestSnapshotClosedPositionStillSerializeStats(t *testing.T) { 286 engine := getTestEngine(t) 287 // fillTestPositions(engine) 288 289 keys := engine.Keys() 290 s1, _, err := engine.GetState(keys[0]) 291 require.Nil(t, err) 292 293 // first load two orders 294 295 buyOrder := &types.Order{ 296 Party: "test_party_1", 297 Side: types.SideBuy, 298 Size: uint64(150), 299 Remaining: uint64(150), 300 Price: num.UintZero(), 301 } 302 engine.RegisterOrder(context.TODO(), buyOrder) 303 304 sellOrder := &types.Order{ 305 Party: "test_party_2", 306 Side: types.SideSell, 307 Size: uint64(150), 308 Remaining: uint64(150), 309 Price: num.UintZero(), 310 } 311 engine.RegisterOrder(context.TODO(), sellOrder) 312 313 // then get them to update the positions 314 315 trade := &types.Trade{ 316 Size: 150, 317 Buyer: "test_party_1", 318 Seller: "test_party_2", 319 } 320 321 engine.Update(context.TODO(), trade, buyOrder, sellOrder) 322 323 // now we close the positions 324 // just swap the parties on the orders 325 // and trades 326 buyOrder.Party, sellOrder.Party = sellOrder.Party, buyOrder.Party 327 trade.Buyer, trade.Seller = trade.Seller, trade.Buyer 328 329 engine.RegisterOrder(context.TODO(), buyOrder) 330 engine.RegisterOrder(context.TODO(), sellOrder) 331 engine.Update(context.TODO(), trade, buyOrder, sellOrder) 332 333 // should get 2 closed positions 334 assert.Len(t, engine.GetClosedPositions(), 2) 335 336 s2, _, err := engine.GetState(keys[0]) 337 require.Nil(t, err) 338 require.False(t, bytes.Equal(s1, s2)) 339 340 payload := &snapshot.Payload{} 341 assert.NoError(t, proto.Unmarshal(s2, payload)) 342 343 marketPositions := payload.Data.(*snapshot.Payload_MarketPositions) 344 assert.NotNil(t, marketPositions) 345 // assert the records are saved 346 assert.Len(t, marketPositions.MarketPositions.PartiesRecords, 2) 347 // while yet, there's no positions anymores. 348 assert.Len(t, marketPositions.MarketPositions.Positions, 0) 349 }