code.vegaprotocol.io/vega@v0.79.0/core/snapshot/engine_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 snapshot_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/snapshot" 24 "code.vegaprotocol.io/vega/core/snapshot/mocks" 25 "code.vegaprotocol.io/vega/core/snapshot/tree" 26 "code.vegaprotocol.io/vega/core/types" 27 typemocks "code.vegaprotocol.io/vega/core/types/mocks" 28 vegactx "code.vegaprotocol.io/vega/libs/context" 29 vgcontext "code.vegaprotocol.io/vega/libs/context" 30 "code.vegaprotocol.io/vega/libs/num" 31 vgrand "code.vegaprotocol.io/vega/libs/rand" 32 vgtest "code.vegaprotocol.io/vega/libs/test" 33 "code.vegaprotocol.io/vega/logging" 34 "code.vegaprotocol.io/vega/paths" 35 "code.vegaprotocol.io/vega/version" 36 37 tmtypes "github.com/cometbft/cometbft/abci/types" 38 "github.com/golang/mock/gomock" 39 "github.com/stretchr/testify/assert" 40 "github.com/stretchr/testify/require" 41 ) 42 43 func TestEngine(t *testing.T) { 44 t.Run("Restoring state succeeds", testRestoringStateSucceeds) 45 t.Run("Restoring state at a specific block height succeeds", testRestoringStateAtSpecificBlockHeightSucceeds) 46 t.Run("Taking a snapshot succeeds", TestTakingSnapshotSucceeds) 47 t.Run("State providers can live under same namespace but with different keys", testProvidersSameNamespaceDifferentKeys) 48 } 49 50 // testRestoringStateSucceeds restores a state by simulating state-sync, and save 51 // the snapshot locally. It then simulates restoring the state from the newly 52 // saved snapshots. 53 func testRestoringStateSucceeds(t *testing.T) { 54 // The snapshot to be restored via state-sync and then, from local storage. 55 testSnapshot := firstSnapshot(t) 56 57 ctrl := gomock.NewController(t) 58 59 ctx := context.Background() 60 vegaPaths := paths.New(t.TempDir()) 61 log := logging.NewTestLogger() 62 63 // Some providers matching the snapshot payloads. 64 governanceProvider := newGovernanceProvider(t, ctrl) 65 delegationProvider := newDelegationProvider(t, ctrl) 66 epochProvider := newEpochProvider(t, ctrl) 67 statsService := mocks.NewMockStatsService(ctrl) 68 timeService := mocks.NewMockTimeService(ctrl) 69 70 engine, err := snapshot.NewEngine(vegaPaths, snapshot.DefaultConfig(), log, timeService, statsService) 71 require.NoError(t, err) 72 closeEngine := vgtest.OnlyOnce(engine.Close) 73 defer closeEngine() 74 75 // Since we are initializing an engine, in a brand new environment, the snapshot 76 // databases should be empty. 77 hasSnapshot, err := engine.HasSnapshots() 78 require.NoError(t, err) 79 require.False(t, hasSnapshot, "The engine shouldn't have any snapshot") 80 latestSnapshots, err := engine.ListLatestSnapshots() 81 require.NoError(t, err) 82 require.Empty(t, latestSnapshots, "There shouldn't be any snapshot") 83 84 // Add the providers. 85 engine.AddProviders(governanceProvider) 86 engine.AddProviders(delegationProvider) 87 engine.AddProviders(epochProvider) 88 89 // From that point, start simulating state-sync. 90 91 // Starting the engine. 92 require.NoError(t, engine.Start(ctx)) 93 94 // No state should be restored because there is no local snapshot. 95 require.False(t, engine.HasRestoredStateAlready(), "No state should have been restored") 96 // Therefore, the `Info()` should return empty information. 97 snapshotHash, height, chainID := engine.Info() 98 require.Zero(t, snapshotHash) 99 require.Zero(t, height) 100 require.Zero(t, chainID) 101 102 // Simulating the call to the engine from Tendermint ABCI `OfferSnapshot()`. 103 response := engine.ReceiveSnapshot(testSnapshot.snapshot) 104 require.Equal(t, tmtypes.ResponseOfferSnapshot{ 105 Result: tmtypes.ResponseOfferSnapshot_ACCEPT, 106 }, response) 107 108 // When all the chunks are loaded, the state restoration is triggered by 109 // converting the chunks to payload, that are then broadcast to the providers. 110 111 timeService.EXPECT().SetTimeNow(gomock.Any(), time.Unix(0, testSnapshot.appState.Time)).Times(1) 112 timeService.EXPECT().SetPrevTime(time.Unix(0, testSnapshot.appState.PrevBlockTime)).Times(1) 113 statsService.EXPECT().SetHeight(testSnapshot.appState.Height).Times(1) 114 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceActive()).Return(nil, nil).Times(1) 115 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceEnacted()).Return(nil, nil).Times(1) 116 delegationProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadDelegationActive()).Return(nil, nil).Times(1) 117 epochProvider.EXPECT().LoadState(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1) 118 119 // Loading each chunk in the engine. When done, the state restoration is 120 // triggered automatically. 121 for idx, rawChunk := range testSnapshot.rawChunks { 122 response := engine.ReceiveSnapshotChunk(ctx, rawChunk, vgrand.RandomStr(5)) 123 require.Equal(t, tmtypes.ResponseApplySnapshotChunk{ 124 Result: tmtypes.ResponseApplySnapshotChunk_ACCEPT, 125 }, response, "The raw chunk with index %d should be accepted", idx) 126 } 127 128 // Since the state has been restored, the snapshot databases should have one 129 // snapshot saved. 130 hasSnapshot, err = engine.HasSnapshots() 131 require.NoError(t, err) 132 require.True(t, hasSnapshot, "The engine should have a snapshot") 133 latestSnapshots, err = engine.ListLatestSnapshots() 134 require.NoError(t, err) 135 require.Len(t, latestSnapshots, 1, "There should have 1 snapshot") 136 require.True(t, engine.HasRestoredStateAlready(), "The state should be marked as restored") 137 // And, the method `Info()` should return information of the current state. 138 snapshotHash, height, chainID = engine.Info() 139 require.Equal(t, testSnapshot.snapshot.Hash, snapshotHash) 140 require.EqualValues(t, testSnapshot.appState.Height, height) 141 require.Equal(t, testSnapshot.appState.ChainID, chainID) 142 143 // Start simulating restoration from the local snapshot that has been creating 144 // in the previous steps. This also helps verifying the previous snapshot 145 // has correctly been saved locally, as it should after a state-sync. 146 147 // Closing the previous engine instance, so we can simulate a restart. 148 closeEngine() 149 150 engine, err = snapshot.NewEngine(vegaPaths, snapshot.DefaultConfig(), log, timeService, statsService) 151 require.NoError(t, err) 152 closeEngine = vgtest.OnlyOnce(engine.Close) 153 defer closeEngine() 154 155 // Add same providers as the previous engine instance. 156 engine.AddProviders(governanceProvider) 157 engine.AddProviders(delegationProvider) 158 engine.AddProviders(epochProvider) 159 160 // Since we should have reload the local snapshot, we should find the previous 161 // state loaded but not restored. 162 hasSnapshot, err = engine.HasSnapshots() 163 require.NoError(t, err) 164 require.True(t, hasSnapshot, "The engine should have a snapshot") 165 latestSnapshots, err = engine.ListLatestSnapshots() 166 require.NoError(t, err) 167 require.Len(t, latestSnapshots, 1, "There should have 1 snapshot") 168 169 // The state is not restored yet. 170 require.False(t, engine.HasRestoredStateAlready(), "The state should not be restored yet") 171 snapshotHash, height, chainID = engine.Info() 172 require.Zero(t, snapshotHash) 173 require.Zero(t, height) 174 require.Zero(t, chainID) 175 176 // Setting up the expectation when the the local snapshot will be started. 177 178 // State restored on the snapshot engine itself, from the local snapshot. 179 timeService.EXPECT().SetTimeNow(gomock.Any(), time.Unix(0, testSnapshot.appState.Time)).Times(1) 180 timeService.EXPECT().SetPrevTime(time.Unix(0, testSnapshot.appState.PrevBlockTime)).Times(1) 181 statsService.EXPECT().SetHeight(testSnapshot.appState.Height).Times(1) 182 183 // LoadState() is called once for each key. If there are 2 keys, it's called twice. 184 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceActive()).Return(nil, nil).Times(1) 185 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceEnacted()).Return(nil, nil).Times(1) 186 delegationProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadDelegationActive()).Return(nil, nil).Times(1) 187 epochProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadEpoch()).Return(nil, nil).Times(1) 188 189 // Starting the engine. 190 require.NoError(t, engine.Start(ctx)) 191 192 // Since we have a local snapshot, this time, the engine should have restore 193 // the state. 194 require.True(t, engine.HasRestoredStateAlready(), "The state should be marked as restored") 195 // Therefore, the method `Info()` should return information of the current 196 // state. 197 snapshotHash, height, chainID = engine.Info() 198 require.Equal(t, testSnapshot.snapshot.Hash, snapshotHash) 199 require.EqualValues(t, testSnapshot.appState.Height, height) 200 require.Equal(t, testSnapshot.appState.ChainID, chainID) 201 202 // Attempt to load a snapshot via state-sync after the state has been restored 203 // from the local storage. This should not be possible. 204 205 response = engine.ReceiveSnapshot(testSnapshot.snapshot) 206 require.Equal(t, tmtypes.ResponseOfferSnapshot{ 207 Result: tmtypes.ResponseOfferSnapshot_ABORT, 208 }, response) 209 210 responseForChunk := engine.ReceiveSnapshotChunk(ctx, testSnapshot.rawChunks[0], vgrand.RandomStr(5)) 211 require.Equal(t, tmtypes.ResponseApplySnapshotChunk{ 212 Result: tmtypes.ResponseApplySnapshotChunk_ABORT, 213 }, responseForChunk) 214 215 // Attempt to start the engine a second time to restore state once again 216 // from the local storage. This should not be possible. 217 218 require.Error(t, engine.Start(ctx)) 219 } 220 221 func testRestoringStateAtSpecificBlockHeightSucceeds(t *testing.T) { 222 // The snapshot to be restored via state-sync and then, from local storage. 223 testSnapshotV1 := firstSnapshot(t) 224 testSnapshotV2 := secondSnapshot(t) 225 226 ctrl := gomock.NewController(t) 227 228 ctx := context.Background() 229 vegaPaths := paths.New(t.TempDir()) 230 log := logging.NewTestLogger() 231 232 // Some providers matching the snapshot payloads. 233 governanceProvider := newGovernanceProvider(t, ctrl) 234 delegationProvider := newDelegationProvider(t, ctrl) 235 epochProvider := newEpochProvider(t, ctrl) 236 statsService := mocks.NewMockStatsService(ctrl) 237 timeService := mocks.NewMockTimeService(ctrl) 238 239 config := snapshot.DefaultConfig() 240 241 // We want to restart from the first snapshot. Proposing a more recent 242 // snapshot should be rejected. 243 config.StartHeight = int64(testSnapshotV1.appState.Height) 244 config.RetryLimit = 5 245 246 engine, err := snapshot.NewEngine(vegaPaths, config, log, timeService, statsService) 247 require.NoError(t, err) 248 closeEngine := vgtest.OnlyOnce(engine.Close) 249 defer closeEngine() 250 251 // Add the providers. 252 engine.AddProviders(governanceProvider) 253 engine.AddProviders(delegationProvider) 254 engine.AddProviders(epochProvider) 255 256 // From that point, start simulating state-sync. 257 258 // Starting the engine. 259 require.NoError(t, engine.Start(ctx)) 260 261 // Simulating the call to the engine from Tendermint ABCI `OfferSnapshot()`. 262 // We are expecting the v1, so the v2 should be rejected. 263 response := engine.ReceiveSnapshot(testSnapshotV2.snapshot) 264 require.Equal(t, tmtypes.ResponseOfferSnapshot{ 265 Result: tmtypes.ResponseOfferSnapshot_REJECT, 266 }, response) 267 268 // Simulating the call to the engine from Tendermint ABCI `OfferSnapshot()`. 269 response = engine.ReceiveSnapshot(testSnapshotV1.snapshot) 270 require.Equal(t, tmtypes.ResponseOfferSnapshot{ 271 Result: tmtypes.ResponseOfferSnapshot_ACCEPT, 272 }, response) 273 274 // Attempting to load snapshot chunks that do not match the accepted snapshot 275 // to ensure the engine rejects them. 276 nodeSendingWrongChunk := vgrand.RandomStr(5) 277 responseForChunk := engine.ReceiveSnapshotChunk(ctx, testSnapshotV2.rawChunks[0], nodeSendingWrongChunk) 278 require.Equal(t, tmtypes.ResponseApplySnapshotChunk{ 279 Result: tmtypes.ResponseApplySnapshotChunk_RETRY, 280 RejectSenders: []string{nodeSendingWrongChunk}, 281 }, responseForChunk, "This raw chunk and its sender should be rejected") 282 } 283 284 func TestTakingSnapshotSucceeds(t *testing.T) { 285 // The snapshot to be restored via state-sync and then, from local storage. 286 testSnapshot := firstSnapshot(t) 287 288 ctrl := gomock.NewController(t) 289 290 vegaPaths := paths.New(t.TempDir()) 291 log := logging.NewTestLogger() 292 ctx := vegactx.WithChainID(vegactx.WithTraceID(vegactx.WithBlockHeight(context.Background(), 293 testSnapshot.appState.Height), testSnapshot.appState.Block), testSnapshot.appState.ChainID, 294 ) 295 296 // Some providers matching the snapshot payloads. 297 governanceProvider := newGovernanceProvider(t, ctrl) 298 delegationProvider := newDelegationProvider(t, ctrl) 299 epochProvider := newEpochProvider(t, ctrl) 300 statsService := mocks.NewMockStatsService(ctrl) 301 timeService := mocks.NewMockTimeService(ctrl) 302 303 config := snapshot.DefaultConfig() 304 // To test we keep 2 snapshots. 305 config.KeepRecent = 2 306 307 engine, err := snapshot.NewEngine(vegaPaths, config, log, timeService, statsService) 308 require.NoError(t, err) 309 defer engine.Close() 310 311 // Add the providers. 312 engine.AddProviders(governanceProvider) 313 engine.AddProviders(delegationProvider) 314 engine.AddProviders(epochProvider) 315 316 // Starting the engine. 317 require.NoError(t, engine.Start(ctx)) 318 319 // Set the snapshot interval to 20 to verify the engine only triggers the 320 // snapshot at the right moment. 321 require.NoError(t, engine.OnSnapshotIntervalUpdate(ctx, num.NewUint(20))) 322 323 // Attempt to take the snapshot, 9 times, which should do nothing, as the 324 // engine is set to take the snapshot every 20 blocks. 325 for i := 0; i < 9; i++ { 326 hash, _, err := engine.Snapshot(ctx) 327 require.NoError(t, err) 328 assert.Empty(t, hash) 329 } 330 331 // Decrease the snapshot interval to 10 to verify the engine only triggers the 332 // snapshot at the right moment. Since the left attempts (11) are above the new 333 // limit, they are reset to the new interval. So it will take 10 attempts 334 // to snapshot, like the new interval. 335 require.NoError(t, engine.OnSnapshotIntervalUpdate(ctx, num.NewUint(10))) 336 337 // Attempt to take the snapshot, 9 times, which should do nothing, as the 338 // engine is set to take the snapshot every 10 blocks. 339 for i := 0; i < 9; i++ { 340 hash, _, err := engine.Snapshot(ctx) 341 require.NoError(t, err) 342 assert.Empty(t, hash) 343 } 344 345 // According to the previous the configuration, the next call to snapshot 346 // would have trigger the snapshot. Increase the snapshot interval to 12, this 347 // should also re-peg the left attempt, by adding 2 new attempts. 348 require.NoError(t, engine.OnSnapshotIntervalUpdate(ctx, num.NewUint(12))) 349 350 // Attempt to take the snapshot, twice, which should do nothing, again, as 351 // the engine is set to take the snapshot every 12 blocks. 352 for i := 0; i < 2; i++ { 353 hash, _, err := engine.Snapshot(ctx) 354 require.NoError(t, err) 355 assert.Empty(t, hash) 356 } 357 358 // Add state to the providers for next snapshot attempt. 359 governanceActivePayload := testSnapshot.PayloadGovernanceActive() 360 governanceEnactedPayload := testSnapshot.PayloadGovernanceEnacted() 361 payloadDelegationActive := testSnapshot.PayloadDelegationActive() 362 payloadEpoch := testSnapshot.PayloadEpoch() 363 governanceProvider.EXPECT().GetState(governanceEnactedPayload.Key()).Return(serialize(t, governanceEnactedPayload), nil, nil).Times(1) 364 governanceProvider.EXPECT().GetState(governanceActivePayload.Key()).Return(serialize(t, governanceActivePayload), nil, nil).Times(1) 365 delegationProvider.EXPECT().GetState(payloadDelegationActive.Key()).Return(serialize(t, payloadDelegationActive), nil, nil).Times(1) 366 epochProvider.EXPECT().GetState(payloadEpoch.Key()).Return(serialize(t, payloadEpoch), nil, nil).Times(1) 367 timeService.EXPECT().GetTimeNow().Return(time.Now()).Times(1) 368 timeService.EXPECT().GetTimeLastBatch().Return(time.Now()).Times(1) 369 370 // This time, the snapshot is triggered. 371 hash, done, err := engine.Snapshot(ctx) 372 require.NoError(t, err) 373 assert.NotEmpty(t, hash) 374 375 // Wait for the async save to be done. 376 <-done 377 378 // Add state to the providers for next snapshot attempt. 379 governanceProvider.EXPECT().GetState(governanceEnactedPayload.Key()).Return(serialize(t, governanceEnactedPayload), nil, nil).Times(1) 380 governanceProvider.EXPECT().GetState(governanceActivePayload.Key()).Return(serialize(t, governanceActivePayload), nil, nil).Times(1) 381 delegationProvider.EXPECT().GetState(payloadDelegationActive.Key()).Return(serialize(t, payloadDelegationActive), nil, nil).Times(1) 382 epochProvider.EXPECT().GetState(payloadEpoch.Key()).Return(serialize(t, payloadEpoch), nil, nil).Times(1) 383 timeService.EXPECT().GetTimeNow().Return(time.Now()).Times(1) 384 timeService.EXPECT().GetTimeLastBatch().Return(time.Now()).Times(1) 385 386 // First 11 iterations as the snapshot occurs on th 12th one, as we configured 387 // above. 388 for i := 0; i < 11; i++ { 389 hash, _, err := engine.Snapshot(ctx) 390 require.NoError(t, err) 391 require.Empty(t, hash) 392 } 393 394 // Take a second snapshot on the 12th iteration. 395 hash, _, err = engine.Snapshot(ctx) 396 require.NoError(t, err) 397 require.NotEmpty(t, hash) 398 399 // Wait for the async save to be done. 400 <-done 401 402 savedSnapshots, err := engine.ListLatestSnapshots() 403 require.NoError(t, err) 404 assert.Len(t, savedSnapshots, 2) 405 } 406 407 func testProvidersSameNamespaceDifferentKeys(t *testing.T) { 408 ctrl := gomock.NewController(t) 409 410 vegaPaths := paths.New(t.TempDir()) 411 log := logging.NewTestLogger() 412 413 // Some providers matching the snapshot payloads. 414 statsService := mocks.NewMockStatsService(ctrl) 415 timeService := mocks.NewMockTimeService(ctrl) 416 417 engine, err := snapshot.NewEngine(vegaPaths, snapshot.DefaultConfig(), log, timeService, statsService) 418 require.NoError(t, err) 419 defer engine.Close() 420 421 namespace := types.DelegationSnapshot 422 key1 := vgrand.RandomStr(5) 423 key2 := vgrand.RandomStr(5) 424 key3 := vgrand.RandomStr(5) 425 key4 := vgrand.RandomStr(5) 426 427 provider1 := typemocks.NewMockStateProvider(ctrl) 428 provider1.EXPECT().Namespace().Return(namespace).AnyTimes() 429 provider1.EXPECT().Keys().Return([]string{key1, key2}).AnyTimes() 430 provider1.EXPECT().Stopped().Return(false).AnyTimes() 431 432 provider2 := typemocks.NewMockStateProvider(ctrl) 433 provider2.EXPECT().Namespace().Return(namespace).AnyTimes() 434 provider2.EXPECT().Keys().Return([]string{key3}).AnyTimes() 435 provider2.EXPECT().Stopped().Return(false).AnyTimes() 436 437 require.NotPanics(t, func() { 438 engine.AddProviders(provider1, provider2) 439 }) 440 441 // This provider reuses a key from provider1. 442 provider3 := typemocks.NewMockStateProvider(ctrl) 443 provider3.EXPECT().Namespace().Return(namespace).AnyTimes() 444 provider3.EXPECT().Keys().Return([]string{key2, key4}).AnyTimes() 445 provider3.EXPECT().Stopped().Return(false).AnyTimes() 446 447 require.Panics(t, func() { 448 engine.AddProviders(provider3) 449 }) 450 } 451 452 func TestProtocolVersionInAppstatePayload(t *testing.T) { 453 ctrl := gomock.NewController(t) 454 455 vegaPaths := paths.New(t.TempDir()) 456 log := logging.NewTestLogger() 457 458 // Some providers matching the snapshot payloads. 459 statsService := mocks.NewMockStatsService(ctrl) 460 timeService := mocks.NewMockTimeService(ctrl) 461 engine, err := snapshot.NewEngine(vegaPaths, snapshot.DefaultConfig(), log, timeService, statsService) 462 require.NoError(t, err) 463 464 ctx := vgcontext.WithBlockHeight(context.Background(), 1000) 465 ctx = vgcontext.WithChainID(ctx, "chain-1") 466 require.NoError(t, engine.Start(ctx)) 467 468 timeService.EXPECT().GetTimeNow().AnyTimes() 469 timeService.EXPECT().GetTimeLastBatch().Return(time.Now()).Times(1) 470 _, err = engine.SnapshotNow(ctx) 471 engine.Close() 472 require.NoError(t, err) 473 474 snapshotTree, err := tree.New(log, tree.WithLevelDBDatabase(vegaPaths)) 475 require.NoError(t, err) 476 payloads, err := snapshotTree.AsPayloads() 477 require.NoError(t, err) 478 479 var appstate *types.PayloadAppState 480 for _, p := range payloads { 481 if p.Namespace() == types.AppSnapshot { 482 appstate = p.GetAppState() 483 break 484 } 485 } 486 require.NotNil(t, appstate) 487 assert.True(t, appstate.AppState.ProtocolUpdgade) 488 assert.Equal(t, version.Get(), appstate.AppState.ProtocolVersion) 489 } 490 491 func TestSnapshotVersionCommunicatedToProviders(t *testing.T) { 492 // The snapshot to be restored via state-sync and then, from local storage. 493 testSnapshot := firstSnapshot(t) 494 495 ctrl := gomock.NewController(t) 496 497 vegaPaths := paths.New(t.TempDir()) 498 log := logging.NewTestLogger() 499 500 statsService := mocks.NewMockStatsService(ctrl) 501 timeService := mocks.NewMockTimeService(ctrl) 502 governanceProvider := newGovernanceProvider(t, ctrl) 503 delegationProvider := newDelegationProvider(t, ctrl) 504 epochProvider := newEpochProvider(t, ctrl) 505 506 // new engine same vega-home 507 engine, err := snapshot.NewEngine(vegaPaths, snapshot.DefaultConfig(), log, timeService, statsService) 508 require.NoError(t, err) 509 defer engine.Close() 510 511 engine.AddProviders(governanceProvider, delegationProvider, epochProvider) 512 513 engine.Start(context.Background()) 514 515 // Simulating the call to the engine from Tendermint ABCI `OfferSnapshot()`. 516 response := engine.ReceiveSnapshot(testSnapshot.snapshot) 517 require.Equal(t, tmtypes.ResponseOfferSnapshot{ 518 Result: tmtypes.ResponseOfferSnapshot_ACCEPT, 519 }, response) 520 521 // When all the chunks are loaded, the state restoration is triggered by 522 // converting the chunks to payload, that are then broadcast to the providers. 523 524 timeService.EXPECT().SetTimeNow(gomock.Any(), time.Unix(0, testSnapshot.appState.Time)).Times(1) 525 timeService.EXPECT().SetPrevTime(time.Unix(0, testSnapshot.appState.PrevBlockTime)).Times(1) 526 statsService.EXPECT().SetHeight(testSnapshot.appState.Height).Times(1) 527 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceActive()).Return(nil, nil).Times(1) 528 governanceProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadGovernanceEnacted()).Return(nil, nil).Times(1) 529 delegationProvider.EXPECT().LoadState(gomock.Any(), testSnapshot.PayloadDelegationActive()).Return(nil, nil).Times(1) 530 531 var isUpgradeFrom bool 532 epochProvider.EXPECT().LoadState(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1).Do( 533 func(rctx context.Context, _ *types.Payload) { 534 isUpgradeFrom = vegactx.InProgressUpgradeFrom(rctx, "v0.72.1") 535 }, 536 ) 537 538 // Loading each chunk in the engine. When done, the state restoration is 539 // triggered automatically. 540 for idx, rawChunk := range testSnapshot.rawChunks { 541 response := engine.ReceiveSnapshotChunk(context.Background(), rawChunk, vgrand.RandomStr(5)) 542 require.Equal(t, tmtypes.ResponseApplySnapshotChunk{ 543 Result: tmtypes.ResponseApplySnapshotChunk_ACCEPT, 544 }, response, "The raw chunk with index %d should be accepted", idx) 545 } 546 547 require.True(t, isUpgradeFrom) 548 }