code.vegaprotocol.io/vega@v0.79.0/core/matching/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 matching_test
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"testing"
    22  
    23  	"code.vegaprotocol.io/vega/core/matching"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    26  	"code.vegaprotocol.io/vega/libs/num"
    27  	"code.vegaprotocol.io/vega/libs/proto"
    28  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    29  
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  const (
    35  	market = "testing market"
    36  	key    = market
    37  	party  = "party"
    38  )
    39  
    40  var priceFactor = num.DecimalFromInt64(10)
    41  
    42  type orderdata struct {
    43  	id          string
    44  	price       uint64
    45  	size        uint64
    46  	side        types.Side
    47  	peggedOrder *types.PeggedOrder
    48  }
    49  
    50  func TestEmpty(t *testing.T) {
    51  	ob := getTestOrderBook(t, market)
    52  
    53  	payload, _, err := ob.ob.GetState(key)
    54  	assert.NoError(t, err)
    55  	assert.NotNil(t, payload)
    56  
    57  	_, _, err = ob.ob.GetState(key)
    58  	assert.NoError(t, err)
    59  }
    60  
    61  func TestBuyOrdersChangeState(t *testing.T) {
    62  	ob := getTestOrderBook(t, market)
    63  
    64  	orders := []orderdata{
    65  		{id: vgcrypto.RandomHash(), price: 100, size: 10, side: types.SideBuy},
    66  		{id: vgcrypto.RandomHash(), price: 101, size: 11, side: types.SideBuy},
    67  		{id: vgcrypto.RandomHash(), price: 102, size: 12, side: types.SideBuy},
    68  		{id: vgcrypto.RandomHash(), price: 103, size: 13, side: types.SideBuy},
    69  	}
    70  
    71  	addOrders(t, ob.ob, orders)
    72  
    73  	s1, _, err := ob.ob.GetState(key)
    74  	assert.NoError(t, err)
    75  	s2, _, err := ob.ob.GetState(key)
    76  	assert.NoError(t, err)
    77  	// These should be the same
    78  	assert.True(t, bytes.Equal(s1, s2))
    79  
    80  	// Add one more order and check that the state value changes
    81  	order := &types.Order{
    82  		MarketID:    market,
    83  		ID:          vgcrypto.RandomHash(),
    84  		Price:       num.NewUint(104),
    85  		Size:        14,
    86  		Remaining:   14,
    87  		Party:       party,
    88  		Side:        types.SideBuy,
    89  		TimeInForce: types.OrderTimeInForceGTC,
    90  		Type:        types.OrderTypeLimit,
    91  		CreatedAt:   1010,
    92  	}
    93  	orderConf, err := ob.ob.SubmitOrder(order)
    94  	assert.NotNil(t, orderConf)
    95  	assert.NoError(t, err)
    96  
    97  	s3, _, err := ob.ob.GetState(key)
    98  	assert.NoError(t, err)
    99  	assert.False(t, bytes.Equal(s1, s3))
   100  }
   101  
   102  func TestSellOrdersChangeState(t *testing.T) {
   103  	ob := getTestOrderBook(t, market)
   104  
   105  	orders := []orderdata{
   106  		{id: vgcrypto.RandomHash(), price: 100, size: 10, side: types.SideSell},
   107  		{id: vgcrypto.RandomHash(), price: 101, size: 11, side: types.SideSell},
   108  		{id: vgcrypto.RandomHash(), price: 102, size: 12, side: types.SideSell},
   109  		{id: vgcrypto.RandomHash(), price: 103, size: 13, side: types.SideSell},
   110  	}
   111  	addOrders(t, ob.ob, orders)
   112  
   113  	s1, _, err := ob.ob.GetState(key)
   114  	assert.NoError(t, err)
   115  	s2, _, err := ob.ob.GetState(key)
   116  	assert.NoError(t, err)
   117  	// These should be the same
   118  	assert.True(t, bytes.Equal(s1, s2))
   119  
   120  	// Add one more order and check that the state value changes
   121  	order := &types.Order{
   122  		MarketID:    market,
   123  		ID:          vgcrypto.RandomHash(),
   124  		Price:       num.NewUint(104),
   125  		Size:        14,
   126  		Remaining:   14,
   127  		Party:       party,
   128  		Side:        types.SideSell,
   129  		TimeInForce: types.OrderTimeInForceGTC,
   130  		Type:        types.OrderTypeLimit,
   131  		CreatedAt:   1010,
   132  	}
   133  	orderConf, err := ob.ob.SubmitOrder(order)
   134  	assert.NotNil(t, orderConf)
   135  	assert.NoError(t, err)
   136  
   137  	s3, _, err := ob.ob.GetState(key)
   138  	assert.NoError(t, err)
   139  	assert.False(t, bytes.Equal(s1, s3))
   140  }
   141  
   142  func addOrders(t *testing.T, ob *matching.CachedOrderBook, orders []orderdata) {
   143  	t.Helper()
   144  	baseorder := &types.Order{
   145  		MarketID:    market,
   146  		Party:       party,
   147  		Side:        types.SideSell,
   148  		TimeInForce: types.OrderTimeInForceGTC,
   149  		Type:        types.OrderTypeLimit,
   150  		Status:      types.OrderStatusActive,
   151  	}
   152  
   153  	createdAt := int64(1000)
   154  	for _, i := range orders {
   155  		order := baseorder.Clone()
   156  		order.ID = i.id
   157  		order.Price = num.NewUint(i.price)
   158  
   159  		order.PeggedOrder = i.peggedOrder
   160  		order.Size = i.size
   161  
   162  		order.Remaining = i.size
   163  		order.Side = i.side
   164  		order.CreatedAt = createdAt
   165  		createdAt++
   166  
   167  		pf, _ := num.UintFromDecimal(priceFactor)
   168  		order.OriginalPrice = order.Price.Clone()
   169  		order.OriginalPrice.Div(order.Price, pf)
   170  
   171  		orderConf, err := ob.SubmitOrder(order)
   172  		assert.NotNil(t, orderConf)
   173  		assert.NoError(t, err)
   174  	}
   175  }
   176  
   177  func TestSaveAndLoadSnapshot(t *testing.T) {
   178  	ob := getTestOrderBook(t, market)
   179  
   180  	// Add some orders
   181  	orders := []orderdata{
   182  		{id: vgcrypto.RandomHash(), price: 99, size: 10, side: types.SideBuy},
   183  		{id: vgcrypto.RandomHash(), price: 100, size: 11, side: types.SideBuy},
   184  		{id: vgcrypto.RandomHash(), price: 102, size: 12, side: types.SideSell},
   185  		{id: vgcrypto.RandomHash(), price: 103, size: 13, side: types.SideSell},
   186  	}
   187  	addOrders(t, ob.ob, orders)
   188  
   189  	// now add some pegged orders
   190  	details := &types.PeggedOrder{
   191  		Offset:    num.NewUint(100),
   192  		Reference: types.PeggedReferenceMid,
   193  	}
   194  	peggedOrders := []orderdata{
   195  		{id: vgcrypto.RandomHash(), price: 95, size: 1, side: types.SideBuy, peggedOrder: details},
   196  		{id: vgcrypto.RandomHash(), price: 105, size: 1, side: types.SideSell, peggedOrder: details},
   197  		{id: vgcrypto.RandomHash(), price: 95, size: 1, side: types.SideBuy, peggedOrder: details},
   198  		{id: vgcrypto.RandomHash(), price: 105, size: 1, side: types.SideSell, peggedOrder: details},
   199  		{id: vgcrypto.RandomHash(), price: 95, size: 1, side: types.SideBuy, peggedOrder: details},
   200  		{id: vgcrypto.RandomHash(), price: 105, size: 1, side: types.SideSell, peggedOrder: details},
   201  	}
   202  
   203  	addOrders(t, ob.ob, peggedOrders)
   204  
   205  	// Create a snapshot
   206  	payload, _, err := ob.ob.GetState(key)
   207  	assert.NoError(t, err)
   208  
   209  	before, _, err := ob.ob.GetState(key)
   210  	assert.NoError(t, err)
   211  
   212  	orders2 := []orderdata{
   213  		{id: vgcrypto.RandomHash(), price: 95, size: 1, side: types.SideBuy},
   214  		{id: vgcrypto.RandomHash(), price: 105, size: 1, side: types.SideSell},
   215  	}
   216  	addOrders(t, ob.ob, orders2)
   217  
   218  	different, _, err := ob.ob.GetState(key)
   219  	assert.NoError(t, err)
   220  
   221  	// Load the snapshot back in
   222  	ob2 := getTestOrderBook(t, market)
   223  	snap := &snapshot.Payload{}
   224  	err = proto.Unmarshal(payload, snap)
   225  	assert.NoError(t, err)
   226  	ob2.ob.LoadState(context.TODO(), types.PayloadFromProto(snap))
   227  
   228  	// Get the state and check it's the same as before
   229  	after, _, err := ob2.ob.GetState(key)
   230  	assert.NoError(t, err)
   231  	assert.True(t, bytes.Equal(before, after))
   232  	assert.False(t, bytes.Equal(before, different))
   233  
   234  	for _, order := range orders {
   235  		o2, err := ob2.ob.OrderBook.GetOrderByID(order.id)
   236  		require.NoError(t, err)
   237  
   238  		// all original prices should be nil until we know the price factor
   239  		assert.Nil(t, o2.OriginalPrice)
   240  	}
   241  
   242  	ob2.ob.OrderBook.RestoreWithMarketPriceFactor(priceFactor)
   243  
   244  	// now the orders should be equal
   245  	for _, order := range orders {
   246  		o1, err := ob.ob.OrderBook.GetOrderByID(order.id)
   247  		require.NoError(t, err)
   248  
   249  		o2, err := ob2.ob.OrderBook.GetOrderByID(order.id)
   250  		require.NoError(t, err)
   251  		assert.Equal(t, o1, o2)
   252  	}
   253  
   254  	assert.Equal(t, ob.ob.GetActivePeggedOrderIDs(), ob2.ob.GetActivePeggedOrderIDs())
   255  }
   256  
   257  func TestStopSnapshotTaking(t *testing.T) {
   258  	ob := getTestOrderBook(t, market)
   259  
   260  	_, _, err := ob.ob.GetState(key)
   261  	assert.NoError(t, err)
   262  	_, _, err = ob.ob.GetState(key)
   263  	assert.NoError(t, err)
   264  
   265  	// signal to kill the engine's snapshots
   266  	ob.ob.StopSnapshots()
   267  
   268  	s, _, err := ob.ob.GetState(key)
   269  	assert.NoError(t, err)
   270  	assert.Nil(t, s)
   271  	assert.True(t, ob.ob.Stopped())
   272  }