code.vegaprotocol.io/vega@v0.79.0/core/collateral/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 collateral_test
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"strings"
    22  	"testing"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/core/collateral"
    26  	"code.vegaprotocol.io/vega/core/integration/stubs"
    27  	"code.vegaprotocol.io/vega/core/snapshot"
    28  	"code.vegaprotocol.io/vega/core/stats"
    29  	"code.vegaprotocol.io/vega/core/types"
    30  	"code.vegaprotocol.io/vega/libs/config/encoding"
    31  	"code.vegaprotocol.io/vega/libs/num"
    32  	"code.vegaprotocol.io/vega/libs/proto"
    33  	vgtest "code.vegaprotocol.io/vega/libs/test"
    34  	"code.vegaprotocol.io/vega/logging"
    35  	"code.vegaprotocol.io/vega/paths"
    36  
    37  	"github.com/golang/mock/gomock"
    38  	"github.com/stretchr/testify/assert"
    39  	"github.com/stretchr/testify/require"
    40  )
    41  
    42  func TestCheckpoint(t *testing.T) {
    43  	eng := getTestEngine(t)
    44  	ctx := context.Background()
    45  
    46  	party := "foo"
    47  	bal := num.NewUint(500)
    48  	insBal := num.NewUint(42)
    49  	// create party
    50  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
    51  	acc, err := eng.Engine.CreatePartyGeneralAccount(ctx, party, testMarketAsset)
    52  	assert.NoError(t, err)
    53  	err = eng.Engine.UpdateBalance(ctx, acc, bal)
    54  	assert.Nil(t, err)
    55  
    56  	// create a market then top insurance pool,
    57  	// this should get restored in the global pool
    58  	mktInsAcc, err := eng.GetMarketInsurancePoolAccount(testMarketID, testMarketAsset)
    59  	assert.NoError(t, err)
    60  	err = eng.Engine.UpdateBalance(ctx, mktInsAcc.ID, insBal)
    61  	assert.Nil(t, err)
    62  
    63  	pendingTransfersAcc := eng.GetPendingTransfersAccount(testMarketAsset)
    64  	assert.NoError(t, eng.UpdateBalance(ctx, pendingTransfersAcc.ID, num.NewUint(1789)))
    65  
    66  	pendingTransfersAcc = eng.GetPendingTransfersAccount(testMarketAsset)
    67  	assert.NoError(t, eng.UpdateBalance(ctx, pendingTransfersAcc.ID, num.NewUint(1789)))
    68  
    69  	// topup the global reward account
    70  	rewardAccount, err := eng.GetGlobalRewardAccount("VOTE")
    71  	assert.Nil(t, err)
    72  	err = eng.Engine.UpdateBalance(ctx, rewardAccount.ID, num.NewUint(10000))
    73  	assert.Nil(t, err)
    74  
    75  	// topup the infra fee account for the test asset
    76  	for _, feeAccount := range eng.GetInfraFeeAccountIDs() {
    77  		// restricting the topup and the check later to the test asset because that gets enabled back in the test
    78  		if strings.Contains(feeAccount, testMarketAsset) {
    79  			err = eng.Engine.UpdateBalance(ctx, feeAccount, num.NewUint(12345))
    80  			require.NoError(t, err)
    81  		}
    82  	}
    83  
    84  	// topup some reward accounts for markets
    85  	makerReceivedFeeReward1, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market1", types.AccountTypeMakerReceivedFeeReward)
    86  	require.NoError(t, err)
    87  	err = eng.Engine.UpdateBalance(ctx, makerReceivedFeeReward1.ID, num.NewUint(11111))
    88  	require.NoError(t, err)
    89  
    90  	makerReceivedFeeReward2, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market2", types.AccountTypeMakerReceivedFeeReward)
    91  	require.NoError(t, err)
    92  	err = eng.Engine.UpdateBalance(ctx, makerReceivedFeeReward2.ID, num.NewUint(22222))
    93  	require.NoError(t, err)
    94  
    95  	makerPaidFeeReward1, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market3", types.AccountTypeMakerPaidFeeReward)
    96  	require.NoError(t, err)
    97  	err = eng.Engine.UpdateBalance(ctx, makerPaidFeeReward1.ID, num.NewUint(33333))
    98  	require.NoError(t, err)
    99  
   100  	makerPaidFeeReward2, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market4", types.AccountTypeMakerPaidFeeReward)
   101  	require.NoError(t, err)
   102  	err = eng.Engine.UpdateBalance(ctx, makerPaidFeeReward2.ID, num.NewUint(44444))
   103  	require.NoError(t, err)
   104  
   105  	lpFeeReward1, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market5", types.AccountTypeLPFeeReward)
   106  	require.NoError(t, err)
   107  	err = eng.Engine.UpdateBalance(ctx, lpFeeReward1.ID, num.NewUint(55555))
   108  	require.NoError(t, err)
   109  
   110  	lpFeeReward2, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market6", types.AccountTypeLPFeeReward)
   111  	require.NoError(t, err)
   112  	err = eng.Engine.UpdateBalance(ctx, lpFeeReward2.ID, num.NewUint(66666))
   113  	require.NoError(t, err)
   114  
   115  	marketBonusReward1, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market7", types.AccountTypeMarketProposerReward)
   116  	require.NoError(t, err)
   117  	err = eng.Engine.UpdateBalance(ctx, marketBonusReward1.ID, num.NewUint(77777))
   118  	require.NoError(t, err)
   119  
   120  	marketBonusReward2, err := eng.Engine.GetOrCreateRewardAccount(ctx, "VOTE", "market8", types.AccountTypeMarketProposerReward)
   121  	require.NoError(t, err)
   122  	err = eng.Engine.UpdateBalance(ctx, marketBonusReward2.ID, num.NewUint(88888))
   123  	require.NoError(t, err)
   124  
   125  	treasury, err := eng.Engine.GetNetworkTreasuryAccount("VOTE")
   126  	require.NoError(t, err)
   127  	err = eng.Engine.UpdateBalance(ctx, treasury.ID, num.NewUint(99999))
   128  	require.NoError(t, err)
   129  
   130  	ins, err := eng.Engine.GetGlobalInsuranceAccount("VOTE")
   131  	require.NoError(t, err)
   132  	err = eng.Engine.UpdateBalance(ctx, ins.ID, num.NewUint(100900))
   133  	require.NoError(t, err)
   134  
   135  	rewardAccounts := []*types.Account{makerReceivedFeeReward1, makerReceivedFeeReward2, makerPaidFeeReward1, makerPaidFeeReward2, lpFeeReward1, lpFeeReward2, marketBonusReward1, marketBonusReward2}
   136  
   137  	checkpoint, err := eng.Checkpoint()
   138  	require.NoError(t, err)
   139  	require.NotEmpty(t, checkpoint)
   140  
   141  	conf := collateral.NewDefaultConfig()
   142  	conf.Level = encoding.LogLevel{Level: logging.DebugLevel}
   143  	// system accounts created
   144  	loadEng := collateral.New(logging.NewTestLogger(), conf, eng.timeSvc, eng.broker)
   145  	enableGovernanceAsset(t, loadEng)
   146  
   147  	asset := types.Asset{
   148  		ID: testMarketAsset,
   149  		Details: &types.AssetDetails{
   150  			Symbol: testMarketAsset,
   151  		},
   152  	}
   153  	// we need to enable the assets before being able to load the balances
   154  	loadEng.EnableAsset(ctx, asset)
   155  	require.NoError(t, err)
   156  
   157  	err = loadEng.Load(ctx, checkpoint)
   158  	require.NoError(t, err)
   159  	loadedPartyAcc, err := loadEng.GetPartyGeneralAccount(party, testMarketAsset)
   160  	require.NoError(t, err)
   161  	require.Equal(t, bal, loadedPartyAcc.Balance)
   162  
   163  	loadedIns, err := loadEng.GetGlobalInsuranceAccount(testMarketAsset)
   164  	require.NoError(t, err)
   165  	require.Equal(t, insBal, loadedIns.Balance)
   166  
   167  	loadedTreasury, err := loadEng.GetNetworkTreasuryAccount("VOTE")
   168  	require.NoError(t, err)
   169  	require.Equal(t, num.NewUint(99999), loadedTreasury.Balance)
   170  
   171  	loadedReward, err := loadEng.GetGlobalRewardAccount("VOTE")
   172  	require.NoError(t, err)
   173  	require.Equal(t, num.NewUint(10000), loadedReward.Balance)
   174  
   175  	loadedPendingTransfers := loadEng.GetPendingTransfersAccount(testMarketAsset)
   176  	require.Equal(t, num.NewUint(1789), loadedPendingTransfers.Balance)
   177  
   178  	for _, feeAcc := range loadEng.GetInfraFeeAccountIDs() {
   179  		if strings.Contains(feeAcc, testMarketAsset) {
   180  			acc, err := loadEng.GetAccountByID(feeAcc)
   181  			require.NoError(t, err)
   182  			require.Equal(t, num.NewUint(12345), acc.Balance)
   183  		}
   184  	}
   185  
   186  	for i, a := range rewardAccounts {
   187  		acc, err := loadEng.GetAccountByID(a.ID)
   188  		require.NoError(t, err)
   189  		require.Equal(t, num.NewUint(uint64((i+1)*11111)), acc.Balance)
   190  	}
   191  }
   192  
   193  func TestSnapshots(t *testing.T) {
   194  	t.Run("Creating a snapshot produces the same hash every single time", testSnapshotConsistentHash)
   195  	t.Run("Loading a snapshot should produce the same state - check snapshot after restore", testSnapshotRestore)
   196  }
   197  
   198  func testSnapshotConsistentHash(t *testing.T) {
   199  	mkt := "market1"
   200  	ctx := context.Background()
   201  	asset := types.Asset{
   202  		ID: "foo",
   203  		Details: &types.AssetDetails{
   204  			Name:     "foo",
   205  			Symbol:   "FOO",
   206  			Decimals: 5,
   207  			Quantum:  num.DecimalFromFloat(1),
   208  			Source: types.AssetDetailsBuiltinAsset{
   209  				BuiltinAsset: &types.BuiltinAsset{
   210  					MaxFaucetAmountMint: num.NewUint(100000000),
   211  				},
   212  			},
   213  		},
   214  	}
   215  	eng := getTestEngine(t)
   216  	// create assets, accounts, and update balances
   217  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   218  	require.NoError(t, eng.EnableAsset(ctx, asset))
   219  	parties := []string{
   220  		"party1",
   221  		"party2",
   222  		"party3",
   223  	}
   224  	balances := map[string]map[types.AccountType]*num.Uint{
   225  		parties[0]: {
   226  			types.AccountTypeGeneral: num.NewUint(500),
   227  			types.AccountTypeMargin:  num.NewUint(500),
   228  		},
   229  		parties[1]: {
   230  			types.AccountTypeGeneral: num.NewUint(1000),
   231  		},
   232  		parties[2]: {
   233  			types.AccountTypeGeneral: num.NewUint(100000),
   234  			types.AccountTypeBond:    num.NewUint(100),
   235  			types.AccountTypeMargin:  num.NewUint(500),
   236  		},
   237  	}
   238  	inc := num.NewUint(50)
   239  	var last string
   240  	for _, p := range parties {
   241  		// always create general account first
   242  		if gb, ok := balances[p][types.AccountTypeGeneral]; ok {
   243  			id, err := eng.CreatePartyGeneralAccount(ctx, p, asset.ID)
   244  			require.NoError(t, err)
   245  			require.NoError(t, eng.IncrementBalance(ctx, id, gb))
   246  			last = id
   247  		}
   248  		for tp, b := range balances[p] {
   249  			switch tp {
   250  			case types.AccountTypeGeneral:
   251  				continue
   252  			case types.AccountTypeMargin:
   253  				id, err := eng.CreatePartyMarginAccount(ctx, p, mkt, asset.ID)
   254  				require.NoError(t, err)
   255  				require.NoError(t, eng.IncrementBalance(ctx, id, b))
   256  				last = id
   257  			case types.AccountTypeBond:
   258  				id, err := eng.CreatePartyBondAccount(ctx, p, mkt, asset.ID)
   259  				require.NoError(t, err)
   260  				require.NoError(t, eng.IncrementBalance(ctx, id, b))
   261  				last = id
   262  			}
   263  		}
   264  	}
   265  	keys := eng.Keys()
   266  	data := make(map[string][]byte, len(keys))
   267  	for _, k := range keys {
   268  		state, _, err := eng.GetState(k)
   269  		require.NoError(t, err)
   270  		data[k] = state
   271  	}
   272  	// now no changes, check hashes again:
   273  	for k, d := range data {
   274  		state, _, err := eng.GetState(k)
   275  		require.NoError(t, err)
   276  		require.EqualValues(t, d, state)
   277  	}
   278  	// now change one account:
   279  	require.NoError(t, eng.IncrementBalance(ctx, last, inc))
   280  	changes := 0
   281  	for k, d := range data {
   282  		got, _, err := eng.GetState(k)
   283  		require.NoError(t, err)
   284  		if !bytes.Equal(d, got) {
   285  			changes++
   286  		}
   287  	}
   288  	require.Equal(t, 1, changes)
   289  }
   290  
   291  func testSnapshotRestore(t *testing.T) {
   292  	mkt := "market1"
   293  	ctx := context.Background()
   294  	erc20 := types.AssetDetailsErc20{
   295  		ERC20: &types.ERC20{
   296  			ContractAddress: "0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B",
   297  			ChainID:         "1",
   298  		},
   299  	}
   300  	asset := types.Asset{
   301  		ID: "foo",
   302  		Details: &types.AssetDetails{
   303  			Name:     "foo",
   304  			Symbol:   "FOO",
   305  			Decimals: 5,
   306  			Quantum:  num.DecimalFromFloat(1),
   307  			Source:   erc20,
   308  		},
   309  	}
   310  	eng := getTestEngine(t)
   311  	// create assets, accounts, and update balances
   312  	eng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   313  	require.NoError(t, eng.EnableAsset(ctx, asset))
   314  	parties := []string{
   315  		"party1",
   316  		"party2",
   317  		"party3",
   318  		"*",
   319  	}
   320  	balances := map[string]map[types.AccountType]*num.Uint{
   321  		parties[0]: {
   322  			types.AccountTypeGeneral: num.NewUint(500),
   323  			types.AccountTypeMargin:  num.NewUint(500),
   324  		},
   325  		parties[1]: {
   326  			types.AccountTypeGeneral: num.NewUint(1000),
   327  		},
   328  		parties[2]: {
   329  			types.AccountTypeGeneral: num.NewUint(100000),
   330  			types.AccountTypeBond:    num.NewUint(100),
   331  			types.AccountTypeMargin:  num.NewUint(500),
   332  		},
   333  		"*": {
   334  			types.AccountTypeBuyBackFees: num.NewUint(1000),
   335  		},
   336  	}
   337  	inc := num.NewUint(50)
   338  	var last string
   339  	for _, p := range parties {
   340  		// always create general account first
   341  		if gb, ok := balances[p][types.AccountTypeGeneral]; ok && p != "!" {
   342  			id, err := eng.CreatePartyGeneralAccount(ctx, p, asset.ID)
   343  			require.NoError(t, err)
   344  			require.NoError(t, eng.IncrementBalance(ctx, id, gb))
   345  			last = id
   346  		}
   347  		for tp, b := range balances[p] {
   348  			switch tp {
   349  			case types.AccountTypeGeneral:
   350  				continue
   351  			case types.AccountTypeMargin:
   352  				id, err := eng.CreatePartyMarginAccount(ctx, p, mkt, asset.ID)
   353  				require.NoError(t, err)
   354  				require.NoError(t, eng.IncrementBalance(ctx, id, b))
   355  				last = id
   356  			case types.AccountTypeBond:
   357  				id, err := eng.CreatePartyBondAccount(ctx, p, mkt, asset.ID)
   358  				require.NoError(t, err)
   359  				require.NoError(t, eng.IncrementBalance(ctx, id, b))
   360  				last = id
   361  			case types.AccountTypeBuyBackFees:
   362  				id := eng.GetOrCreateBuyBackFeesAccountID(ctx, asset.ID)
   363  				require.NoError(t, eng.IncrementBalance(ctx, id, b))
   364  				last = id
   365  			}
   366  		}
   367  	}
   368  	// earmark 500 out of the 1000 in the buy back account
   369  	_, err := eng.EarmarkForAutomatedPurchase(asset.ID, types.AccountTypeBuyBackFees, num.UintZero(), num.NewUint(500))
   370  	require.NoError(t, err)
   371  
   372  	keys := eng.Keys()
   373  	payloads := make(map[string]*types.Payload, len(keys))
   374  	data := make(map[string][]byte, len(keys))
   375  	for _, k := range keys {
   376  		payloads[k] = &types.Payload{}
   377  		s, _, err := eng.GetState(k)
   378  		require.NoError(t, err)
   379  		data[k] = s
   380  	}
   381  	newEng := getTestEngine(t)
   382  	// we expect 2 batches of events to be sent
   383  
   384  	newEng.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   385  	newEng.broker.EXPECT().SendBatch(gomock.Any()).Times(2)
   386  	for k, pl := range payloads {
   387  		state := data[k]
   388  		ptype := pl.IntoProto()
   389  		require.NoError(t, proto.Unmarshal(state, ptype))
   390  		payloads[k] = types.PayloadFromProto(ptype)
   391  		_, err := newEng.LoadState(ctx, payloads[k])
   392  		require.NoError(t, err)
   393  	}
   394  	for k, d := range data {
   395  		got, _, err := newEng.GetState(k)
   396  		require.NoError(t, err)
   397  		require.EqualValues(t, d, got)
   398  	}
   399  	require.NoError(t, eng.IncrementBalance(ctx, last, inc))
   400  	// unearmark 200 on eng
   401  	require.NoError(t, eng.UnearmarkForAutomatedPurchase(asset.ID, types.AccountTypeBuyBackFees, num.NewUint(200)))
   402  	// now we expect 1 different hash
   403  	diff := 0
   404  	for k, h := range data {
   405  		old, _, err := eng.GetState(k)
   406  		require.NoError(t, err)
   407  		reload, _, err := newEng.GetState(k)
   408  		require.NoError(t, err)
   409  		if !bytes.Equal(h, old) {
   410  			diff++
   411  			require.NotEqualValues(t, reload, old)
   412  		}
   413  	}
   414  	require.Equal(t, 1, diff)
   415  	require.NoError(t, newEng.IncrementBalance(ctx, last, inc))
   416  	require.NoError(t, newEng.UnearmarkForAutomatedPurchase(asset.ID, types.AccountTypeBuyBackFees, num.NewUint(200)))
   417  	// now the state should match up once again
   418  	for k := range data {
   419  		old, _, err := eng.GetState(k)
   420  		require.NoError(t, err)
   421  		restore, _, err := newEng.GetState(k)
   422  		require.NoError(t, err)
   423  		require.EqualValues(t, old, restore)
   424  	}
   425  }
   426  
   427  func TestSnapshotRoundTripViaEngine(t *testing.T) {
   428  	mkt := "market1"
   429  	ctx := vgtest.VegaContext("chainid", 100)
   430  
   431  	erc20 := types.AssetDetailsErc20{
   432  		ERC20: &types.ERC20{
   433  			ContractAddress: "0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B",
   434  			ChainID:         "1",
   435  		},
   436  	}
   437  	asset := types.Asset{
   438  		ID: "foo",
   439  		Details: &types.AssetDetails{
   440  			Name:     "foo",
   441  			Symbol:   "FOO",
   442  			Decimals: 5,
   443  			Quantum:  num.DecimalFromFloat(1),
   444  			Source:   erc20,
   445  		},
   446  	}
   447  	collateralEngine1 := getTestEngine(t)
   448  	// create assets, accounts, and update balances
   449  	collateralEngine1.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   450  	require.NoError(t, collateralEngine1.EnableAsset(ctx, asset))
   451  	parties := []string{
   452  		"party1",
   453  		"party2",
   454  		"party3",
   455  	}
   456  	balances := map[string]map[types.AccountType]*num.Uint{
   457  		parties[0]: {
   458  			types.AccountTypeGeneral: num.NewUint(500),
   459  			types.AccountTypeMargin:  num.NewUint(500),
   460  		},
   461  		parties[1]: {
   462  			types.AccountTypeGeneral: num.NewUint(1000),
   463  		},
   464  		parties[2]: {
   465  			types.AccountTypeGeneral: num.NewUint(100000),
   466  			types.AccountTypeBond:    num.NewUint(100),
   467  			types.AccountTypeMargin:  num.NewUint(500),
   468  		},
   469  	}
   470  	for _, p := range parties {
   471  		// always create general account first
   472  		if gb, ok := balances[p][types.AccountTypeGeneral]; ok {
   473  			id, err := collateralEngine1.CreatePartyGeneralAccount(ctx, p, asset.ID)
   474  			require.NoError(t, err)
   475  			require.NoError(t, collateralEngine1.IncrementBalance(ctx, id, gb))
   476  		}
   477  		for tp, b := range balances[p] {
   478  			switch tp {
   479  			case types.AccountTypeGeneral:
   480  				continue
   481  			case types.AccountTypeMargin:
   482  				id, err := collateralEngine1.CreatePartyMarginAccount(ctx, p, mkt, asset.ID)
   483  				require.NoError(t, err)
   484  				require.NoError(t, collateralEngine1.IncrementBalance(ctx, id, b))
   485  			case types.AccountTypeBond:
   486  				id, err := collateralEngine1.CreatePartyBondAccount(ctx, p, mkt, asset.ID)
   487  				require.NoError(t, err)
   488  				require.NoError(t, collateralEngine1.IncrementBalance(ctx, id, b))
   489  			}
   490  		}
   491  	}
   492  
   493  	newAsset := types.Asset{
   494  		ID: "foo2",
   495  		Details: &types.AssetDetails{
   496  			Name:     "foo2",
   497  			Symbol:   "FOO2",
   498  			Decimals: 5,
   499  			Quantum:  num.DecimalFromFloat(2),
   500  			Source:   erc20,
   501  		},
   502  	}
   503  
   504  	// setup snapshot engine
   505  	now := time.Now()
   506  	log := logging.NewTestLogger()
   507  	timeService := stubs.NewTimeStub()
   508  	vegaPath := paths.New(t.TempDir())
   509  	timeService.SetTime(now)
   510  	statsData := stats.New(log, stats.NewDefaultConfig())
   511  	config := snapshot.DefaultConfig()
   512  
   513  	snapshotEngine1, err := snapshot.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain)
   514  	require.NoError(t, err)
   515  	snapshotEngine1.AddProviders(collateralEngine1.Engine)
   516  	snapshotEngine1CloseFn := vgtest.OnlyOnce(snapshotEngine1.Close)
   517  	defer snapshotEngine1CloseFn()
   518  
   519  	require.NoError(t, snapshotEngine1.Start(ctx))
   520  
   521  	hash1, err := snapshotEngine1.SnapshotNow(ctx)
   522  	require.NoError(t, err)
   523  
   524  	require.NoError(t, collateralEngine1.EnableAsset(ctx, newAsset))
   525  
   526  	id, err := collateralEngine1.CreatePartyGeneralAccount(ctx, "party4", newAsset.ID)
   527  	require.NoError(t, err)
   528  	require.NoError(t, collateralEngine1.IncrementBalance(ctx, id, num.NewUint(100)))
   529  
   530  	state1 := map[string][]byte{}
   531  	for _, key := range collateralEngine1.Keys() {
   532  		state, additionalProvider, err := collateralEngine1.GetState(key)
   533  		require.NoError(t, err)
   534  		assert.Empty(t, additionalProvider)
   535  		state1[key] = state
   536  	}
   537  
   538  	snapshotEngine1CloseFn()
   539  
   540  	collateralEngine2 := getTestEngine(t)
   541  	collateralEngine2.broker.EXPECT().SendBatch(gomock.Any()).AnyTimes()
   542  	collateralEngine2.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   543  
   544  	snapshotEngine2, err := snapshot.NewEngine(vegaPath, config, log, timeService, statsData.Blockchain)
   545  	require.NoError(t, err)
   546  	defer snapshotEngine2.Close()
   547  
   548  	snapshotEngine2.AddProviders(collateralEngine2.Engine)
   549  
   550  	// This triggers the state restoration from the local snapshot.
   551  	require.NoError(t, snapshotEngine2.Start(ctx))
   552  
   553  	// Comparing the hash after restoration, to ensure it produces the same result.
   554  	hash2, _, _ := snapshotEngine2.Info()
   555  	require.Equal(t, hash1, hash2)
   556  
   557  	require.NoError(t, collateralEngine2.EnableAsset(ctx, newAsset))
   558  
   559  	id2, err := collateralEngine2.CreatePartyGeneralAccount(ctx, "party4", newAsset.ID)
   560  	require.NoError(t, err)
   561  	require.NoError(t, collateralEngine2.IncrementBalance(ctx, id2, num.NewUint(100)))
   562  
   563  	state2 := map[string][]byte{}
   564  	for _, key := range collateralEngine2.Keys() {
   565  		state, additionalProvider, err := collateralEngine2.GetState(key)
   566  		require.NoError(t, err)
   567  		assert.Empty(t, additionalProvider)
   568  		state2[key] = state
   569  	}
   570  
   571  	for key := range state1 {
   572  		assert.Equalf(t, state1[key], state2[key], "Key %q does not have the same data", key)
   573  	}
   574  }