code.vegaprotocol.io/vega@v0.79.0/core/assets/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 assets_test
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"code.vegaprotocol.io/vega/core/integration/stubs"
    25  	snp "code.vegaprotocol.io/vega/core/snapshot"
    26  	"code.vegaprotocol.io/vega/core/stats"
    27  	"code.vegaprotocol.io/vega/core/types"
    28  	"code.vegaprotocol.io/vega/libs/proto"
    29  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    30  	vgtest "code.vegaprotocol.io/vega/libs/test"
    31  	"code.vegaprotocol.io/vega/logging"
    32  	"code.vegaprotocol.io/vega/paths"
    33  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    34  
    35  	"github.com/golang/mock/gomock"
    36  	"github.com/stretchr/testify/require"
    37  )
    38  
    39  func getEngineAndSnapshotEngine(t *testing.T, vegaPath paths.Paths) (*testService, *snp.Engine) {
    40  	t.Helper()
    41  	as := getTestService(t)
    42  	as.broker.EXPECT().Send(gomock.Any()).AnyTimes()
    43  	now := time.Now()
    44  	log := logging.NewTestLogger()
    45  	timeService := stubs.NewTimeStub()
    46  	timeService.SetTime(now)
    47  	statsData := stats.New(log, stats.NewDefaultConfig())
    48  	config := snp.DefaultConfig()
    49  	snapshotEngine, err := snp.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain)
    50  	require.NoError(t, err)
    51  	snapshotEngine.AddProviders(as)
    52  	return as, snapshotEngine
    53  }
    54  
    55  func TestSnapshotRoundTripViaEngine(t *testing.T) {
    56  	ctx := vgtest.VegaContext("chainid", 100)
    57  
    58  	vegaPath := paths.New(t.TempDir())
    59  
    60  	assetEngine1, snapshotEngine1 := getEngineAndSnapshotEngine(t, vegaPath)
    61  	closeSnapshotEngine1 := vgtest.OnlyOnce(snapshotEngine1.Close)
    62  	defer closeSnapshotEngine1()
    63  
    64  	require.NoError(t, snapshotEngine1.Start(context.Background()))
    65  
    66  	for i := 0; i < 3; i++ {
    67  		assetName := vgrand.RandomStr(5)
    68  
    69  		_, err := assetEngine1.NewAsset(ctx, assetName, &types.AssetDetails{
    70  			Source: &types.AssetDetailsBuiltinAsset{},
    71  		})
    72  		require.Nil(t, err)
    73  
    74  		err = assetEngine1.Enable(ctx, assetName)
    75  		require.Nil(t, err)
    76  	}
    77  
    78  	snapshotHash1, err := snapshotEngine1.SnapshotNow(ctx)
    79  	require.NoError(t, err)
    80  
    81  	closeSnapshotEngine1()
    82  
    83  	// Reload the engine using the previous snapshot.
    84  
    85  	_, snapshotEngine2 := getEngineAndSnapshotEngine(t, vegaPath)
    86  	defer snapshotEngine2.Close()
    87  
    88  	// This triggers the state restoration from the local snapshot.
    89  	require.NoError(t, snapshotEngine2.Start(ctx))
    90  
    91  	snapshotHash2, _, _ := snapshotEngine2.Info()
    92  
    93  	require.Equal(t, snapshotHash1, snapshotHash2)
    94  }
    95  
    96  // test round trip of active snapshot hash and serialisation.
    97  func TestActiveSnapshotRoundTrip(t *testing.T) {
    98  	ctx := vgtest.VegaContext("chainid", 100)
    99  
   100  	activeKey := (&types.PayloadActiveAssets{}).Key()
   101  	for i := 0; i < 10; i++ {
   102  		as := getTestService(t)
   103  		as.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   104  
   105  		_, err := as.NewAsset(ctx, "asset1", &types.AssetDetails{
   106  			Source: &types.AssetDetailsBuiltinAsset{},
   107  		})
   108  		require.Nil(t, err)
   109  		err = as.Enable(ctx, "asset1")
   110  		require.Nil(t, err)
   111  		_, err = as.NewAsset(ctx, "asset2", &types.AssetDetails{
   112  			Source: &types.AssetDetailsBuiltinAsset{},
   113  		})
   114  		require.Nil(t, err)
   115  		err = as.Enable(ctx, "asset2")
   116  		require.Nil(t, err)
   117  
   118  		// get the serialised state
   119  		state, _, err := as.GetState(activeKey)
   120  		require.Nil(t, err)
   121  
   122  		// verify state is consistent in the absence of change
   123  		stateNoChange, _, err := as.GetState(activeKey)
   124  		require.Nil(t, err)
   125  
   126  		require.True(t, bytes.Equal(state, stateNoChange))
   127  
   128  		// reload the state
   129  		var active snapshot.Payload
   130  		require.NoError(t, proto.Unmarshal(state, &active))
   131  		payload := types.PayloadFromProto(&active)
   132  
   133  		_, err = as.LoadState(context.Background(), payload)
   134  		require.Nil(t, err)
   135  		statePostReload, _, _ := as.GetState(activeKey)
   136  		require.True(t, bytes.Equal(state, statePostReload))
   137  	}
   138  }
   139  
   140  // test round trip of active snapshot serialisation.
   141  func TestPendingSnapshotRoundTrip(t *testing.T) {
   142  	ctx := vgtest.VegaContext("chainid", 100)
   143  	pendingKey := (&types.PayloadPendingAssets{}).Key()
   144  
   145  	for i := 0; i < 10; i++ {
   146  		as := getTestService(t)
   147  		as.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   148  
   149  		_, err := as.NewAsset(ctx, "asset1", &types.AssetDetails{
   150  			Source: &types.AssetDetailsBuiltinAsset{},
   151  		})
   152  		require.Nil(t, err)
   153  		assetID2, err := as.NewAsset(ctx, "asset2", &types.AssetDetails{
   154  			Source: &types.AssetDetailsBuiltinAsset{},
   155  		})
   156  		require.Nil(t, err)
   157  
   158  		// set asset 2 as pending_listing
   159  		require.NoError(t, as.SetPendingListing(ctx, assetID2))
   160  
   161  		// get the serialised state
   162  		state, _, err := as.GetState(pendingKey)
   163  		require.Nil(t, err)
   164  
   165  		// verify state is consistent in the absence of change
   166  		stateNoChange, _, err := as.GetState(pendingKey)
   167  		require.Nil(t, err)
   168  		require.True(t, bytes.Equal(state, stateNoChange))
   169  
   170  		// reload the state
   171  		var pending snapshot.Payload
   172  		require.NoError(t, proto.Unmarshal(state, &pending))
   173  		payload := types.PayloadFromProto(&pending)
   174  
   175  		_, err = as.LoadState(context.Background(), payload)
   176  		require.Nil(t, err)
   177  		statePostReload, _, _ := as.GetState(pendingKey)
   178  		require.True(t, bytes.Equal(state, statePostReload))
   179  	}
   180  }