code.vegaprotocol.io/vega@v0.79.0/core/settlement/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 settlement
    17  
    18  import (
    19  	"context"
    20  	"sort"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/libs/proto"
    25  	"code.vegaprotocol.io/vega/logging"
    26  )
    27  
    28  type SnapshotEngine struct {
    29  	*Engine
    30  	stopped bool
    31  }
    32  
    33  func NewSnapshotEngine(log *logging.Logger, conf Config, product Product, market string, timeService TimeService, broker Broker, positionFactor num.Decimal) *SnapshotEngine {
    34  	return &SnapshotEngine{
    35  		Engine: New(log, conf, product, market, timeService, broker, positionFactor),
    36  	}
    37  }
    38  
    39  // StopSnapshots is called when the engines respective market no longer exists. We need to stop
    40  // taking snapshots and communicate to the snapshot engine to remove us as a provider.
    41  func (e *SnapshotEngine) StopSnapshots() {
    42  	e.log.Debug("market has been cleared, stopping snapshot production", logging.String("marketid", e.market))
    43  	e.stopped = true
    44  }
    45  
    46  func (e *SnapshotEngine) Stopped() bool {
    47  	return e.stopped
    48  }
    49  
    50  func (e *SnapshotEngine) Namespace() types.SnapshotNamespace {
    51  	return types.SettlementSnapshot
    52  }
    53  
    54  func (e *SnapshotEngine) Keys() []string {
    55  	return []string{e.market}
    56  }
    57  
    58  func (e *SnapshotEngine) GetState(k string) ([]byte, []types.StateProvider, error) {
    59  	if k != e.market {
    60  		return nil, nil, types.ErrSnapshotKeyDoesNotExist
    61  	}
    62  	state, err := e.serialise()
    63  	return state, nil, err
    64  }
    65  
    66  func (e *SnapshotEngine) LoadState(_ context.Context, payload *types.Payload) ([]types.StateProvider, error) {
    67  	if e.Namespace() != payload.Data.Namespace() {
    68  		return nil, types.ErrInvalidSnapshotNamespace
    69  	}
    70  
    71  	switch pl := payload.Data.(type) {
    72  	case *types.PayloadSettlement:
    73  		data := pl.SettlementState
    74  
    75  		e.log.Debug("loading settlement snapshot",
    76  			logging.Int("positions", len(data.PartyLastSettledPosition)),
    77  			logging.Int("trades", len(data.Trades)),
    78  		)
    79  
    80  		e.settledPosition = make(map[string]int64, len(data.PartyLastSettledPosition))
    81  		for _, psp := range data.PartyLastSettledPosition {
    82  			e.settledPosition[psp.Party] = psp.SettledPosition
    83  		}
    84  
    85  		e.lastMarkPrice = data.LastMarkPrice
    86  
    87  		// restore trades
    88  		tradeMap := map[string][]*settlementTrade{}
    89  		for _, trade := range data.Trades {
    90  			party := trade.Party
    91  			st := stTypeToInternal(trade)
    92  			ps, ok := tradeMap[party]
    93  			if !ok {
    94  				ps = make([]*settlementTrade, 0, 5) // some buffer
    95  			}
    96  			tradeMap[party] = append(ps, st)
    97  		}
    98  		e.trades = tradeMap
    99  		// we restored state just fine
   100  		return nil, nil
   101  	default:
   102  		return nil, types.ErrUnknownSnapshotType
   103  	}
   104  }
   105  
   106  func (e *SnapshotEngine) serialise() ([]byte, error) {
   107  	// we just use the embedded market positions type for the market ID
   108  	// positions aren't working correctly for some reason, we get them from positions engine
   109  	data := types.SettlementState{
   110  		MarketID:      e.market,
   111  		LastMarkPrice: e.lastMarkPrice,
   112  	}
   113  
   114  	lastSettledPositions := make([]*types.PartySettledPosition, 0, len(e.settledPosition))
   115  	for k, v := range e.settledPosition {
   116  		lastSettledPositions = append(lastSettledPositions, &types.PartySettledPosition{Party: k, SettledPosition: v})
   117  	}
   118  	sort.Slice(lastSettledPositions, func(i, j int) bool { return lastSettledPositions[i].Party < lastSettledPositions[j].Party })
   119  	data.PartyLastSettledPosition = lastSettledPositions
   120  
   121  	// first get all parties that traded
   122  	tradeParties := make([]string, 0, len(e.trades))
   123  	tradeTotal := 0
   124  	// convert to correct type, keep that in a map
   125  	mapped := make(map[string][]*types.SettlementTrade, len(e.trades))
   126  	for k, trades := range e.trades {
   127  		tradeParties = append(tradeParties, k) // slice of parties
   128  		mapped[k] = internalSTToType(trades, k)
   129  		tradeTotal += len(trades) // keep track of the total trades
   130  	}
   131  	// get map keys sorted
   132  	sort.Strings(tradeParties)
   133  	// now do the trades
   134  	trades := make([]*types.SettlementTrade, 0, tradeTotal)
   135  	for _, p := range tradeParties {
   136  		pp := mapped[p]
   137  		// append trades for party
   138  		trades = append(trades, pp...)
   139  	}
   140  	data.Trades = trades
   141  
   142  	// now the payload type to serialise:
   143  	payload := types.Payload{
   144  		Data: &types.PayloadSettlement{
   145  			SettlementState: &data,
   146  		},
   147  	}
   148  	ser, err := proto.Marshal(payload.IntoProto())
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	return ser, nil
   154  }
   155  
   156  func internalSTToType(trades []*settlementTrade, party string) []*types.SettlementTrade {
   157  	ret := make([]*types.SettlementTrade, 0, len(trades))
   158  	for _, t := range trades {
   159  		ret = append(ret, &types.SettlementTrade{
   160  			Price:       t.price,
   161  			MarketPrice: t.marketPrice,
   162  			Size:        t.size,
   163  			NewSize:     t.newSize,
   164  			Party:       party,
   165  		})
   166  	}
   167  	return ret
   168  }
   169  
   170  func stTypeToInternal(st *types.SettlementTrade) *settlementTrade {
   171  	return &settlementTrade{
   172  		size:        st.Size,
   173  		newSize:     st.NewSize,
   174  		price:       st.Price,
   175  		marketPrice: st.MarketPrice,
   176  	}
   177  }