code.vegaprotocol.io/vega@v0.79.0/core/execution/engine_snapshot.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 execution 17 18 import ( 19 "context" 20 "fmt" 21 "sort" 22 "time" 23 24 "code.vegaprotocol.io/vega/core/assets" 25 "code.vegaprotocol.io/vega/core/events" 26 "code.vegaprotocol.io/vega/core/execution/common" 27 "code.vegaprotocol.io/vega/core/execution/future" 28 "code.vegaprotocol.io/vega/core/execution/spot" 29 "code.vegaprotocol.io/vega/core/types" 30 "code.vegaprotocol.io/vega/libs/proto" 31 "code.vegaprotocol.io/vega/logging" 32 ) 33 34 var marketsKey = (&types.PayloadExecutionMarkets{}).Key() 35 36 func (e *Engine) marketsStates() ([]*types.ExecMarket, []types.StateProvider) { 37 mkts := len(e.futureMarketsCpy) 38 if mkts == 0 { 39 return nil, nil 40 } 41 mks := make([]*types.ExecMarket, 0, mkts) 42 if prev := len(e.generatedProviders); prev < mkts { 43 mkts -= prev 44 } 45 e.newGeneratedProviders = make([]types.StateProvider, 0, mkts*5) 46 for _, m := range e.futureMarketsCpy { 47 // ensure the next MTM timestamp is set correctly: 48 am := e.futureMarkets[m.Mkt().ID] 49 m.SetNextMTM(am.GetNextMTM()) 50 e.log.Debug("serialising market", logging.String("id", m.Mkt().ID)) 51 mks = append(mks, m.GetState()) 52 53 if _, ok := e.generatedProviders[m.GetID()]; !ok { 54 e.newGeneratedProviders = append(e.newGeneratedProviders, m.GetNewStateProviders()...) 55 e.generatedProviders[m.GetID()] = struct{}{} 56 } 57 } 58 59 return mks, e.newGeneratedProviders 60 } 61 62 func (e *Engine) spotMarketsStates() ([]*types.ExecSpotMarket, []types.StateProvider) { 63 mkts := len(e.spotMarketsCpy) 64 if mkts == 0 { 65 return nil, nil 66 } 67 mks := make([]*types.ExecSpotMarket, 0, mkts) 68 69 // we don't really know how many new markets there are so don't bother with the calculation 70 e.newGeneratedProviders = []types.StateProvider{} 71 for _, m := range e.spotMarketsCpy { 72 e.log.Debug("serialising spot market", logging.String("id", m.Mkt().ID)) 73 mks = append(mks, m.GetState()) 74 if _, ok := e.generatedProviders[m.GetID()]; !ok { 75 e.newGeneratedProviders = append(e.newGeneratedProviders, m.GetNewStateProviders()...) 76 e.generatedProviders[m.GetID()] = struct{}{} 77 } 78 } 79 80 return mks, e.newGeneratedProviders 81 } 82 83 func (e *Engine) restoreSpotMarket(ctx context.Context, em *types.ExecSpotMarket) (*spot.Market, error) { 84 marketConfig := em.Market 85 if len(marketConfig.ID) == 0 { 86 return nil, ErrNoMarketID 87 } 88 89 // ensure the asset for this new market exists 90 asts, err := marketConfig.GetAssets() 91 if err != nil { 92 return nil, err 93 } 94 95 assetDetatils := []*assets.Asset{} 96 for _, asset := range asts { 97 if !e.collateral.AssetExists(asset) { 98 return nil, fmt.Errorf( 99 "unable to restore a spot market %q with an invalid %q asset", 100 marketConfig.ID, 101 asset, 102 ) 103 } 104 ad, err := e.assets.Get(asset) 105 if err != nil { 106 e.log.Error("Failed to restore a market, unknown asset", 107 logging.MarketID(marketConfig.ID), 108 logging.String("asset-id", asset), 109 logging.Error(err), 110 ) 111 return nil, err 112 } 113 assetDetatils = append(assetDetatils, ad) 114 } 115 116 nextMTM := time.Unix(0, em.NextMTM) 117 // create market auction state 118 e.log.Info("restoring market", logging.String("id", em.Market.ID)) 119 120 mkt, err := spot.NewMarketFromSnapshot( 121 ctx, 122 e.log, 123 em, 124 e.Config.Risk, 125 e.Config.Position, 126 e.Config.Settlement, 127 e.Config.Matching, 128 e.Config.Fee, 129 e.Config.Liquidity, 130 e.collateral, 131 e.oracle, 132 e.timeService, 133 e.broker, 134 e.stateVarEngine, 135 assetDetatils[0], 136 assetDetatils[1], 137 e.marketActivityTracker, 138 e.peggedOrderCountUpdated, 139 e.referralDiscountRewardService, 140 e.volumeDiscountService, 141 e.volumeRebateService, 142 e.banking, 143 ) 144 if err != nil { 145 e.log.Error("failed to instantiate market", 146 logging.MarketID(marketConfig.ID), 147 logging.Error(err), 148 ) 149 return nil, err 150 } 151 e.delayTransactionsTarget.MarketDelayRequiredUpdated(mkt.GetID(), marketConfig.EnableTxReordering) 152 e.spotMarkets[marketConfig.ID] = mkt 153 e.spotMarketsCpy = append(e.spotMarketsCpy, mkt) 154 e.allMarkets[marketConfig.ID] = mkt 155 156 if err := e.propagateSpotInitialNetParams(ctx, mkt, true); err != nil { 157 return nil, err 158 } 159 // ensure this is set correctly 160 mkt.SetNextMTM(nextMTM) 161 return mkt, nil 162 } 163 164 func (e *Engine) restoreMarket(ctx context.Context, em *types.ExecMarket) (*future.Market, error) { 165 marketConfig := em.Market 166 167 if len(marketConfig.ID) == 0 { 168 return nil, ErrNoMarketID 169 } 170 171 // ensure the asset for this new market exists 172 assets, err := marketConfig.GetAssets() 173 if err != nil { 174 return nil, err 175 } 176 asset := assets[0] 177 if !e.collateral.AssetExists(asset) { 178 return nil, fmt.Errorf( 179 "unable to create a market %q with an invalid %q asset", 180 marketConfig.ID, 181 asset, 182 ) 183 } 184 ad, err := e.assets.Get(asset) 185 if err != nil { 186 e.log.Error("Failed to restore a market, unknown asset", 187 logging.MarketID(marketConfig.ID), 188 logging.String("asset-id", asset), 189 logging.Error(err), 190 ) 191 return nil, err 192 } 193 194 nextMTM := time.Unix(0, em.NextMTM) 195 nextInternalCompositePriceCalc := time.Unix(0, em.NextInternalCompositePriceCalc) 196 197 // create market auction state 198 e.log.Info("restoring market", logging.String("id", em.Market.ID)) 199 mkt, err := future.NewMarketFromSnapshot( 200 ctx, 201 e.log, 202 em, 203 e.Config.Risk, 204 e.Config.Position, 205 e.Config.Settlement, 206 e.Config.Matching, 207 e.Config.Fee, 208 e.Config.Liquidity, 209 e.collateral, 210 e.oracle, 211 e.timeService, 212 e.broker, 213 e.stateVarEngine, 214 ad, 215 e.marketActivityTracker, 216 e.peggedOrderCountUpdated, 217 e.referralDiscountRewardService, 218 e.volumeDiscountService, 219 e.volumeRebateService, 220 e.banking, 221 e.parties, 222 ) 223 if err != nil { 224 e.log.Error("failed to instantiate market", 225 logging.MarketID(marketConfig.ID), 226 logging.Error(err), 227 ) 228 return nil, err 229 } 230 if em.IsSucceeded { 231 mkt.SetSucceeded() 232 } 233 234 e.delayTransactionsTarget.MarketDelayRequiredUpdated(mkt.GetID(), marketConfig.EnableTxReordering) 235 e.futureMarkets[marketConfig.ID] = mkt 236 e.futureMarketsCpy = append(e.futureMarketsCpy, mkt) 237 e.allMarkets[marketConfig.ID] = mkt 238 239 if err := e.propagateInitialNetParamsToFutureMarket(ctx, mkt, true); err != nil { 240 return nil, err 241 } 242 // ensure this is set correctly 243 mkt.SetNextMTM(nextMTM) 244 mkt.SetNextInternalCompositePriceCalc(nextInternalCompositePriceCalc) 245 return mkt, nil 246 } 247 248 func (e *Engine) restoreMarketsStates(ctx context.Context, ems []*types.ExecMarket) ([]types.StateProvider, error) { 249 e.futureMarkets = map[string]*future.Market{} 250 251 pvds := make([]types.StateProvider, 0, len(ems)*4) 252 for _, em := range ems { 253 m, err := e.restoreMarket(ctx, em) 254 if err != nil { 255 return nil, fmt.Errorf("failed to restore market: %w", err) 256 } 257 258 pvds = append(pvds, m.GetNewStateProviders()...) 259 260 // so that we don't return them again the next state change 261 e.generatedProviders[m.GetID()] = struct{}{} 262 } 263 264 return pvds, nil 265 } 266 267 func (e *Engine) restoreSpotMarketsStates(ctx context.Context, ems []*types.ExecSpotMarket) ([]types.StateProvider, error) { 268 e.spotMarkets = map[string]*spot.Market{} 269 270 pvds := make([]types.StateProvider, 0, len(ems)*4) 271 for _, em := range ems { 272 m, err := e.restoreSpotMarket(ctx, em) 273 if err != nil { 274 return nil, fmt.Errorf("failed to restore spot market: %w", err) 275 } 276 277 pvds = append(pvds, m.GetNewStateProviders()...) 278 279 // so that we don't return them again the next state change 280 e.generatedProviders[m.GetID()] = struct{}{} 281 } 282 283 return pvds, nil 284 } 285 286 func (e *Engine) serialise() (snapshot []byte, providers []types.StateProvider, err error) { 287 mkts, pvds := e.marketsStates() 288 cpStates := make([]*types.CPMarketState, 0, len(e.marketCPStates)) 289 for _, cp := range e.marketCPStates { 290 if cp.Market != nil { 291 cpy := cp 292 cpStates = append(cpStates, cpy) 293 } 294 } 295 // ensure the states are sorted 296 sort.SliceStable(cpStates, func(i, j int) bool { 297 return cpStates[i].Market.ID > cpStates[j].Market.ID 298 }) 299 successors := make([]*types.Successors, 0, len(e.successors)) 300 for pid, ids := range e.successors { 301 if _, ok := e.GetMarket(pid, true); !ok { 302 continue 303 } 304 successors = append(successors, &types.Successors{ 305 ParentMarket: pid, 306 SuccessorMarkets: ids, 307 }) 308 } 309 sort.SliceStable(successors, func(i, j int) bool { 310 return successors[i].ParentMarket > successors[j].ParentMarket 311 }) 312 313 spotMkts, spotPvds := e.spotMarketsStates() 314 315 allMarketIDs := make([]string, 0, len(e.allMarketsCpy)) 316 for _, cm := range e.allMarketsCpy { 317 allMarketIDs = append(allMarketIDs, cm.GetID()) 318 } 319 320 pl := types.Payload{ 321 Data: &types.PayloadExecutionMarkets{ 322 ExecutionMarkets: &types.ExecutionMarkets{ 323 Markets: mkts, 324 SpotMarkets: spotMkts, 325 SettledMarkets: cpStates, 326 Successors: successors, 327 AllMarketIDs: allMarketIDs, 328 }, 329 }, 330 } 331 332 s, err := proto.Marshal(pl.IntoProto()) 333 if err != nil { 334 return nil, nil, err 335 } 336 e.snapshotSerialised = s 337 338 return s, append(pvds, spotPvds...), nil 339 } 340 341 func (e *Engine) Namespace() types.SnapshotNamespace { 342 return types.ExecutionSnapshot 343 } 344 345 func (e *Engine) Keys() []string { 346 return []string{marketsKey} 347 } 348 349 func (e *Engine) Stopped() bool { 350 return false 351 } 352 353 func (e *Engine) GetState(_ string) ([]byte, []types.StateProvider, error) { 354 serialised, providers, err := e.serialise() 355 if err != nil { 356 return nil, providers, err 357 } 358 359 return serialised, providers, nil 360 } 361 362 func (e *Engine) LoadState(ctx context.Context, payload *types.Payload) ([]types.StateProvider, error) { 363 switch pl := payload.Data.(type) { 364 case *types.PayloadExecutionMarkets: 365 providers, err := e.restoreMarketsStates(ctx, pl.ExecutionMarkets.Markets) 366 if err != nil { 367 return nil, fmt.Errorf("failed to restore markets states: %w", err) 368 } 369 // restore settled market state 370 for _, m := range pl.ExecutionMarkets.SettledMarkets { 371 cpy := m 372 e.marketCPStates[m.Market.ID] = cpy 373 } 374 e.restoreSuccessorMaps(pl.ExecutionMarkets.Successors) 375 e.snapshotSerialised, err = proto.Marshal(payload.IntoProto()) 376 if err != nil { 377 return nil, err 378 } 379 spotProviders, err := e.restoreSpotMarketsStates(ctx, pl.ExecutionMarkets.SpotMarkets) 380 e.allMarketsCpy = make([]common.CommonMarket, 0, len(e.allMarkets)) 381 for _, v := range pl.ExecutionMarkets.AllMarketIDs { 382 if mkt, ok := e.allMarkets[v]; ok { 383 e.allMarketsCpy = append(e.allMarketsCpy, mkt) 384 } 385 } 386 return append(providers, spotProviders...), err 387 default: 388 return nil, types.ErrUnknownSnapshotType 389 } 390 } 391 392 func (e *Engine) restoreSuccessorMaps(successors []*types.Successors) { 393 for _, suc := range successors { 394 e.successors[suc.ParentMarket] = suc.SuccessorMarkets 395 for _, s := range suc.SuccessorMarkets { 396 e.isSuccessor[s] = suc.ParentMarket 397 } 398 } 399 } 400 401 func (e *Engine) OnStateLoaded(ctx context.Context) error { 402 for _, m := range e.allMarkets { 403 if err := m.PostRestore(ctx); err != nil { 404 return err 405 } 406 407 // let the core state API know about the market, but not the market data since that will get sent on the very next tick 408 // if we sent it now it will create market-data from the core state at the *end* of the block when it was originally 409 // created from core-state at the *start* of the block. 410 e.broker.Send(events.NewMarketCreatedEvent(ctx, *m.Mkt())) 411 } 412 // use the time as restored by the snapshot 413 t := e.timeService.GetTimeNow() 414 // restore marketCPStates through marketsCpy to ensure the order is preserved 415 for _, m := range e.futureMarketsCpy { 416 if !m.IsSucceeded() { 417 cps := m.GetCPState() 418 cps.TTL = t.Add(e.successorWindow) 419 e.marketCPStates[m.GetID()] = cps 420 } 421 } 422 return nil 423 }