code.vegaprotocol.io/vega@v0.79.0/core/matching/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 matching
    17  
    18  import (
    19  	"context"
    20  	"log"
    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  func (b *OrderBook) StopSnapshots() {
    29  	b.log.Debug("market has been cleared, stopping snapshot production", logging.String("marketid", b.marketID))
    30  	b.stopped = true
    31  }
    32  
    33  func (b *OrderBook) Keys() []string {
    34  	return []string{b.snapshot.Key()}
    35  }
    36  
    37  func (b *OrderBook) Stopped() bool {
    38  	return b.stopped
    39  }
    40  
    41  func (b OrderBook) Namespace() types.SnapshotNamespace {
    42  	return types.MatchingSnapshot
    43  }
    44  
    45  func (b *OrderBook) GetState(key string) ([]byte, []types.StateProvider, error) {
    46  	if key != b.snapshot.Key() {
    47  		return nil, nil, types.ErrSnapshotKeyDoesNotExist
    48  	}
    49  
    50  	if b.stopped {
    51  		return nil, nil, nil
    52  	}
    53  
    54  	// Copy all the state into a domain object
    55  	payload := b.buildPayload()
    56  
    57  	s, err := proto.Marshal(payload.IntoProto())
    58  	return s, nil, err
    59  }
    60  
    61  func (b *OrderBook) buildPayload() *types.Payload {
    62  	return &types.Payload{
    63  		Data: &types.PayloadMatchingBook{
    64  			MatchingBook: &types.MatchingBook{
    65  				MarketID:        b.marketID,
    66  				Buy:             b.copyOrders(b.buy),
    67  				Sell:            b.copyOrders(b.sell),
    68  				LastTradedPrice: b.lastTradedPrice,
    69  				Auction:         b.auction,
    70  				BatchID:         b.batchID,
    71  				PeggedOrderIDs:  b.GetActivePeggedOrderIDs(),
    72  			},
    73  		},
    74  	}
    75  }
    76  
    77  func (b *OrderBook) copyOrders(obs *OrderBookSide) []*types.Order {
    78  	orders := make([]*types.Order, 0)
    79  	pricelevels := obs.getLevels()
    80  	for _, pl := range pricelevels {
    81  		for _, order := range pl.orders {
    82  			orders = append(orders, order.Clone())
    83  		}
    84  	}
    85  	return orders
    86  }
    87  
    88  func (b *OrderBook) LoadState(_ context.Context, payload *types.Payload) ([]types.StateProvider, error) {
    89  	if b.Namespace() != payload.Namespace() {
    90  		return nil, types.ErrInvalidSnapshotNamespace
    91  	}
    92  
    93  	var mb *types.MatchingBook
    94  
    95  	switch pl := payload.Data.(type) {
    96  	case *types.PayloadMatchingBook:
    97  		mb = pl.MatchingBook
    98  	default:
    99  		return nil, types.ErrUnknownSnapshotType
   100  	}
   101  
   102  	// Check we have an empty book here or else we should panic
   103  	if len(b.buy.levels) > 0 || len(b.sell.levels) > 0 {
   104  		log.Panic("orderbook is not empty so we should not be loading snapshot state")
   105  	}
   106  
   107  	b.marketID = mb.MarketID
   108  	b.batchID = mb.BatchID
   109  	b.auction = mb.Auction
   110  	b.lastTradedPrice = mb.LastTradedPrice
   111  
   112  	for _, o := range mb.Buy {
   113  		b.buy.addOrder(o)
   114  		b.add(o)
   115  	}
   116  
   117  	for _, o := range mb.Sell {
   118  		b.sell.addOrder(o)
   119  		b.add(o)
   120  	}
   121  
   122  	if len(mb.PeggedOrderIDs) != 0 {
   123  		// the pegged orders will be added in an arbitrary order during b.add() above
   124  		// which is all we can do if we've upgraded from older versions. If we have peggedOrder IDs
   125  		// in the snapshot then we clear them and re-add in the snapshot order
   126  		// (which will be the order they were added to the book)
   127  		b.peggedOrders.Clear()
   128  		for _, pid := range mb.PeggedOrderIDs {
   129  			b.peggedOrders.Add(pid)
   130  		}
   131  	}
   132  
   133  	if b.auction {
   134  		b.indicativePriceAndVolume = NewIndicativePriceAndVolume(b.log, b.buy, b.sell)
   135  	}
   136  
   137  	return nil, nil
   138  }
   139  
   140  // RestoreWithMarketPriceFactor takes the given market price factor and updates all the OriginalPrices
   141  // in the orders accordingly.
   142  func (b *OrderBook) RestoreWithMarketPriceFactor(priceFactor num.Decimal) {
   143  	for _, o := range b.ordersByID {
   144  		if o.Price.IsZero() {
   145  			continue
   146  		}
   147  		o.OriginalPrice, _ = num.UintFromDecimal(o.Price.ToDecimal().Div(priceFactor))
   148  	}
   149  }