code.vegaprotocol.io/vega@v0.79.0/core/epochtime/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 epochtime_test
    17  
    18  import (
    19  	"context"
    20  	"encoding/hex"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/crypto"
    26  	"code.vegaprotocol.io/vega/libs/proto"
    27  	"code.vegaprotocol.io/vega/protos/vega"
    28  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    29  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    30  
    31  	"github.com/golang/mock/gomock"
    32  	"github.com/stretchr/testify/require"
    33  )
    34  
    35  func TestEpochSnapshotFunctionallyAfterReload(t *testing.T) {
    36  	now := time.Unix(0, 0).UTC()
    37  
    38  	ctx := context.Background()
    39  	service := getEpochServiceMT(t)
    40  	defer service.ctrl.Finish()
    41  
    42  	service.broker.EXPECT().Send(gomock.Any()).Times(3)
    43  	// Force creation of first epoch to trigger a snapshot of the first epoch
    44  	service.cb(ctx, now)
    45  	// Force creation of first epoch to trigger a snapshot of the first epoch
    46  
    47  	data, _, err := service.GetState("all")
    48  	require.Nil(t, err)
    49  
    50  	snapService := getEpochServiceMT(t)
    51  	defer snapService.ctrl.Finish()
    52  
    53  	snapService.broker.EXPECT().Send(gomock.Any()).Times(2)
    54  	// Fiddle it into a payload by hand
    55  	snap := &snapshot.Payload{}
    56  	err = proto.Unmarshal(data, snap)
    57  	require.Nil(t, err)
    58  
    59  	service.NotifyOnEpoch(onEpoch, onEpochRestore)
    60  	snapService.NotifyOnEpoch(onEpoch, onEpochRestore)
    61  
    62  	_, err = snapService.LoadState(
    63  		ctx,
    64  		types.PayloadFromProto(snap),
    65  	)
    66  	require.Nil(t, err)
    67  
    68  	// Check functional equivalence by stepping forward in time/blocks
    69  	// Reset global used in callback so that is doesn't pick up state from another test
    70  	epochs = []types.Epoch{}
    71  
    72  	// Move time forward in time a small amount that should cause no change
    73  	nt := now.Add(time.Hour)
    74  	service.cb(ctx, nt)
    75  	snapService.cb(ctx, nt)
    76  	require.Equal(t, 0, len(epochs))
    77  
    78  	// Now send end block
    79  	service.OnBlockEnd(ctx)
    80  	snapService.OnBlockEnd((ctx))
    81  	service.cb(ctx, nt)
    82  	snapService.cb(ctx, nt)
    83  	require.Equal(t, 0, len(epochs))
    84  
    85  	// Move even further forward
    86  	nt = now.Add(time.Hour * 25)
    87  	service.cb(ctx, nt)
    88  	snapService.cb(ctx, nt)
    89  	service.OnBlockEnd(ctx)
    90  	snapService.OnBlockEnd((ctx))
    91  	nt = now.Add(time.Hour * 50)
    92  	service.cb(ctx, nt)
    93  	snapService.cb(ctx, nt)
    94  	require.Equal(t, 4, len(epochs))
    95  
    96  	// epochs = {start, end, start, end}
    97  	require.Equal(t, epochs[0], epochs[2])
    98  	require.Equal(t, epochs[1], epochs[3])
    99  }
   100  
   101  func TestEpochSnapshotHash(t *testing.T) {
   102  	now := time.Unix(0, 0).UTC()
   103  
   104  	ctx := context.Background()
   105  	service := getEpochServiceMT(t)
   106  	defer service.ctrl.Finish()
   107  
   108  	service.broker.EXPECT().Send(gomock.Any()).Times(3)
   109  	// Trigger initial block
   110  	service.cb(ctx, now)
   111  	s, _, err := service.GetState("all")
   112  	require.Nil(t, err)
   113  	require.Equal(t, "41a9839f4dc60ac14461f58658c0e1bf7542bd54cbd635f3c0402bef2f07f60f", hex.EncodeToString(crypto.Hash(s)))
   114  
   115  	// Shuffle time along
   116  	now = now.Add(25 * time.Hour)
   117  	service.cb(ctx, now)
   118  	service.OnBlockEnd(ctx)
   119  	s, _, err = service.GetState("all")
   120  	require.Nil(t, err)
   121  	require.Equal(t, "074677210f20ebb3427064339ebbd46dbfd5d2381bcd3b3fd126bbdcb05b6697", hex.EncodeToString(crypto.Hash(s)))
   122  
   123  	// Shuffle time a bit more
   124  	now = now.Add(25 * time.Hour)
   125  	service.cb(ctx, now)
   126  	s, _, err = service.GetState("all")
   127  	require.Nil(t, err)
   128  	require.Equal(t, "2fb572edea4af9154edeff680e23689ed076d08934c60f8a4c1f5743a614954e", hex.EncodeToString(crypto.Hash(s)))
   129  }
   130  
   131  func TestEpochSnapshotCompare(t *testing.T) {
   132  	now := time.Unix(0, 0).UTC()
   133  
   134  	ctx := context.Background()
   135  	service := getEpochServiceMT(t)
   136  	defer service.ctrl.Finish()
   137  
   138  	service.broker.EXPECT().Send(gomock.Any()).Times(1)
   139  
   140  	// Force creation of first epoch to trigger a snapshot of the first epoch
   141  	service.cb(ctx, now)
   142  
   143  	data, _, err := service.GetState("all")
   144  	require.Nil(t, err)
   145  
   146  	snapService := getEpochServiceMT(t)
   147  	defer snapService.ctrl.Finish()
   148  
   149  	// Fiddle it into a payload by hand
   150  	snap := &snapshot.Payload{}
   151  	err = proto.Unmarshal(data, snap)
   152  	require.Nil(t, err)
   153  
   154  	_, err = snapService.LoadState(
   155  		ctx,
   156  		types.PayloadFromProto(snap),
   157  	)
   158  	require.Nil(t, err)
   159  
   160  	// Check that the snapshot of the snapshot is the same as the original snapshot
   161  	newData, _, err := service.GetState("all")
   162  	require.Nil(t, err)
   163  	require.Equal(t, data, newData)
   164  }
   165  
   166  func TestEpochSnapshotAfterCheckpoint(t *testing.T) {
   167  	ctx := context.Background()
   168  	service := getEpochServiceMT(t)
   169  	defer service.ctrl.Finish()
   170  
   171  	service.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   172  
   173  	// load from a checkpoint
   174  	pb := &eventspb.EpochEvent{
   175  		Seq:        10,
   176  		Action:     vega.EpochAction_EPOCH_ACTION_START,
   177  		ExpireTime: 1664369813556378344,
   178  		EndTime:    1664362613556378344,
   179  	}
   180  
   181  	cpt, err := proto.Marshal(pb)
   182  	require.NoError(t, err)
   183  	require.NoError(t, service.Load(ctx, cpt))
   184  
   185  	// Force creation of first epoch to trigger a snapshot of the first epoch
   186  	service.cb(ctx, time.Unix(0, 1664364245193844630))
   187  
   188  	d, _, err := service.GetState("all")
   189  	require.NoError(t, err)
   190  	snap := &snapshot.Payload{}
   191  	err = proto.Unmarshal(d, snap)
   192  	require.Nil(t, err)
   193  
   194  	require.NotNil(t, snap.GetEpoch())
   195  	require.Equal(t, uint64(10), snap.GetEpoch().Seq)
   196  }