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  }