code.vegaprotocol.io/vega@v0.79.0/core/products/perpetual_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 products_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/datasource"
    24  	dstypes "code.vegaprotocol.io/vega/core/datasource/common"
    25  	"code.vegaprotocol.io/vega/core/datasource/external/signedoracle"
    26  	"code.vegaprotocol.io/vega/core/datasource/spec"
    27  	"code.vegaprotocol.io/vega/core/products"
    28  	"code.vegaprotocol.io/vega/core/products/mocks"
    29  	"code.vegaprotocol.io/vega/core/types"
    30  	tmocks "code.vegaprotocol.io/vega/core/vegatime/mocks"
    31  	"code.vegaprotocol.io/vega/libs/num"
    32  	"code.vegaprotocol.io/vega/libs/ptr"
    33  	"code.vegaprotocol.io/vega/logging"
    34  	vegapb "code.vegaprotocol.io/vega/protos/vega"
    35  	datapb "code.vegaprotocol.io/vega/protos/vega/data/v1"
    36  	snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    37  
    38  	"github.com/golang/mock/gomock"
    39  	"github.com/golang/protobuf/proto"
    40  	"github.com/stretchr/testify/assert"
    41  	"github.com/stretchr/testify/require"
    42  )
    43  
    44  func TestPerpetualSnapshot(t *testing.T) {
    45  	perps := testPerpetual(t)
    46  	defer perps.ctrl.Finish()
    47  	expectedTWAP := 1234
    48  	// set of the data points such that difference in averages is 0
    49  	points := getTestDataPoints(t)
    50  	require.GreaterOrEqual(t, 4, len(points))
    51  
    52  	// tell the perpetual that we are ready to accept settlement stuff
    53  	whenLeaveOpeningAuction(t, perps, points[0].t)
    54  
    55  	// submit the first point then enter an auction
    56  	submitPointWithDifference(t, perps, points[0], expectedTWAP)
    57  	whenAuctionStateChanges(t, perps, points[0].t+int64(time.Second), true)
    58  
    59  	// submit a crazy point difference, then a normal point
    60  	submitPointWithDifference(t, perps, points[1], -9999999)
    61  	submitPointWithDifference(t, perps, points[2], expectedTWAP)
    62  
    63  	// now we leave auction and the crazy point difference will not affect the TWAP because it was in an auction period
    64  	whenAuctionStateChanges(t, perps, points[2].t+int64(time.Second), false)
    65  
    66  	fundingPayment := getFundingPayment(t, perps, points[3].t)
    67  	// 2/3 of funding period spent in auction so expecting funding payment of 1/3*1234=~411
    68  	assert.Equal(t, "411", fundingPayment)
    69  	fundingPayment = getFundingPayment(t, perps, points[3].t)
    70  	assert.Equal(t, "411", fundingPayment)
    71  
    72  	// now get the serialised state, and try to load it
    73  	state1 := perps.perpetual.Serialize()
    74  	serialized1, err := proto.Marshal(state1)
    75  	assert.NoError(t, err)
    76  
    77  	payload := &snapshotpb.Product{}
    78  	err = proto.Unmarshal(serialized1, payload)
    79  	assert.NoError(t, err)
    80  
    81  	restoreTime := time.Unix(0, points[3].t) // time.Unix(1000000, 100)
    82  	perps2, scheduleSrc := testPerpetualSnapshot(t, perps.ctrl, payload, restoreTime)
    83  
    84  	// now we serialize again, and check the payload are same
    85  	state2 := perps2.perpetual.Serialize()
    86  	serialized2, err := proto.Marshal(state2)
    87  	assert.NoError(t, err)
    88  	assert.Equal(t, serialized1, serialized2)
    89  
    90  	// check funding payment comes out the same
    91  	fundingPayment = getFundingPayment(t, perps2, points[3].t)
    92  	assert.Equal(t, "411", fundingPayment)
    93  
    94  	// check the the time-trigger has been set properly
    95  	cfg := scheduleSrc.Data.GetInternalTimeTriggerSpecConfiguration()
    96  
    97  	// trigger time in the past should fail, it should be set to restoreTime so should trigger
    98  	// on a future time only. The trigger times are precision seconds so we pass it in truncated.
    99  	assert.False(t, cfg.IsTriggered(restoreTime.Truncate(time.Second)))
   100  	assert.True(t, cfg.IsTriggered(restoreTime.Add(time.Second)))
   101  }
   102  
   103  func TestPerpetualSnapshotNotStarted(t *testing.T) {
   104  	perps := testPerpetual(t)
   105  
   106  	// get fresh state before we've started the first period
   107  	state1 := perps.perpetual.Serialize()
   108  
   109  	serialized1, err := proto.Marshal(state1)
   110  	assert.NoError(t, err)
   111  
   112  	state2 := &snapshotpb.Product{}
   113  	err = proto.Unmarshal(serialized1, state2)
   114  	assert.NoError(t, err)
   115  
   116  	restoreTime := time.Unix(1000000, 100)
   117  	perps2, _ := testPerpetualSnapshot(t, perps.ctrl, state2, restoreTime)
   118  
   119  	// now we serialize again, and check the payload are same
   120  
   121  	state3 := perps2.perpetual.Serialize()
   122  	serialized2, err := proto.Marshal(state3)
   123  	assert.NoError(t, err)
   124  	assert.Equal(t, serialized1, serialized2)
   125  }
   126  
   127  func testPerpetualSnapshot(t *testing.T, ctrl *gomock.Controller, state *snapshotpb.Product, tm time.Time) (*tstPerp, *datasource.Spec) {
   128  	t.Helper()
   129  
   130  	log := logging.NewTestLogger()
   131  	oe := mocks.NewMockOracleEngine(ctrl)
   132  	broker := mocks.NewMockBroker(ctrl)
   133  	ts := tmocks.NewMockTimeService(ctrl)
   134  	dp := uint32(1)
   135  
   136  	pubKeys := []*dstypes.Signer{
   137  		dstypes.CreateSignerFromString("0xDEADBEEF", dstypes.SignerTypePubKey),
   138  	}
   139  	factor, _ := num.DecimalFromString("0.5")
   140  	settlementSrc := &datasource.Spec{
   141  		Data: datasource.NewDefinition(
   142  			datasource.ContentTypeOracle,
   143  		).SetOracleConfig(
   144  			&signedoracle.SpecConfiguration{
   145  				Signers: pubKeys,
   146  				Filters: []*dstypes.SpecFilter{
   147  					{
   148  						Key: &dstypes.SpecPropertyKey{
   149  							Name:                "foo",
   150  							Type:                datapb.PropertyKey_TYPE_INTEGER,
   151  							NumberDecimalPlaces: ptr.From(uint64(dp)),
   152  						},
   153  						Conditions: nil,
   154  					},
   155  				},
   156  			},
   157  		),
   158  	}
   159  
   160  	definition := datasource.NewDefinition(
   161  		datasource.ContentTypeInternalTimeTriggerTermination,
   162  	).SetTimeTriggerTriggersConfig(
   163  		dstypes.InternalTimeTriggers{
   164  			&dstypes.InternalTimeTrigger{
   165  				Initial: &tm,
   166  				Every:   5,
   167  			},
   168  		},
   169  	).SetTimeTriggerConditionConfig(
   170  		[]*dstypes.SpecCondition{
   171  			{
   172  				Operator: datapb.Condition_OPERATOR_GREATER_THAN,
   173  				Value:    "0",
   174  			},
   175  		},
   176  	)
   177  	scheduleSrc := datasource.SpecFromProto(vegapb.NewDataSourceSpec(definition.IntoProto()))
   178  
   179  	perp := &types.Perps{
   180  		MarginFundingFactor:                 factor,
   181  		DataSourceSpecForSettlementData:     settlementSrc,
   182  		DataSourceSpecForSettlementSchedule: scheduleSrc,
   183  		DataSourceSpecBinding: &datasource.SpecBindingForPerps{
   184  			SettlementDataProperty:     "foo",
   185  			SettlementScheduleProperty: "vegaprotocol.builtin.timetrigger",
   186  		},
   187  	}
   188  	oe.EXPECT().Subscribe(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(spec.SubscriptionID(1), func(_ context.Context, _ spec.SubscriptionID) {}, nil)
   189  	ts.EXPECT().GetTimeNow().Times(1).Return(tm)
   190  	perpetual, err := products.NewPerpetualFromSnapshot(context.Background(), log, perp, "", ts, oe, broker, state.GetPerps(), dp)
   191  	if err != nil {
   192  		t.Fatalf("couldn't create a perp for testing: %v", err)
   193  	}
   194  
   195  	return &tstPerp{
   196  		perpetual: perpetual,
   197  		oe:        oe,
   198  		broker:    broker,
   199  		ctrl:      ctrl,
   200  	}, scheduleSrc
   201  }