diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 5862f433b1c..aa2c6aa5453 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -278,6 +278,22 @@ func (s *simulator) incrementRoundOnAllValidators() { } } +// ForceChangeOfEpoch will force the change of current epoch +// This method will call the epoch change trigger and generate block till a new epoch is reached +func (s *simulator) ForceChangeOfEpoch() error { + log.Info("force change of epoch") + for shardID, node := range s.nodes { + err := node.ForceChangeOfEpoch() + if err != nil { + return fmt.Errorf("force change of epoch shardID-%d: error-%w", shardID, err) + } + } + + epoch := s.nodes[core.MetachainShardId].GetProcessComponents().EpochStartTrigger().Epoch() + + return s.GenerateBlocksUntilEpochIsReached(int32(epoch + 1)) +} + func (s *simulator) allNodesCreateBlocks() error { for _, node := range s.handlers { // TODO MX-15150 remove this when we remove all goroutines diff --git a/node/chainSimulator/chainSimulator_test.go b/node/chainSimulator/chainSimulator_test.go index 1929944d510..020260760be 100644 --- a/node/chainSimulator/chainSimulator_test.go +++ b/node/chainSimulator/chainSimulator_test.go @@ -155,6 +155,53 @@ func TestChainSimulator_GenerateBlocksAndEpochChangeShouldWork(t *testing.T) { assert.True(t, numAccountsWithIncreasedBalances > 0) } +func TestSimulator_TriggerChangeOfEpoch(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 15000, + } + chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ + BypassTxSignatureCheck: false, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: 3, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 100, + MetaChainMinNodes: 100, + ConsensusGroupSize: 1, + MetaChainConsensusGroupSize: 1, + }) + require.Nil(t, err) + require.NotNil(t, chainSimulator) + + defer chainSimulator.Close() + + err = chainSimulator.ForceChangeOfEpoch() + require.Nil(t, err) + + err = chainSimulator.ForceChangeOfEpoch() + require.Nil(t, err) + + err = chainSimulator.ForceChangeOfEpoch() + require.Nil(t, err) + + err = chainSimulator.ForceChangeOfEpoch() + require.Nil(t, err) + + metaNode := chainSimulator.GetNodeHandler(core.MetachainShardId) + currentEpoch := metaNode.GetProcessComponents().EpochStartTrigger().Epoch() + require.Equal(t, uint32(4), currentEpoch) +} + func TestChainSimulator_SetState(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") diff --git a/node/chainSimulator/components/testOnlyProcessingNode.go b/node/chainSimulator/components/testOnlyProcessingNode.go index 0dbe4430b5c..2439ce1f7d6 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode.go +++ b/node/chainSimulator/components/testOnlyProcessingNode.go @@ -508,6 +508,18 @@ func (node *testOnlyProcessingNode) RemoveAccount(address []byte) error { return err } +// ForceChangeOfEpoch will force change of epoch +func (node *testOnlyProcessingNode) ForceChangeOfEpoch() error { + currentHeader := node.DataComponentsHolder.Blockchain().GetCurrentBlockHeader() + if currentHeader == nil { + currentHeader = node.DataComponentsHolder.Blockchain().GetGenesisHeader() + } + + node.ProcessComponentsHolder.EpochStartTrigger().ForceEpochStart(currentHeader.GetRound() + 1) + + return nil +} + func setNonceAndBalanceForAccount(userAccount state.UserAccountHandler, nonce *uint64, balance string) error { if nonce != nil { // set nonce to zero diff --git a/node/chainSimulator/configs/configs.go b/node/chainSimulator/configs/configs.go index 6f935f98dfe..c83d6494334 100644 --- a/node/chainSimulator/configs/configs.go +++ b/node/chainSimulator/configs/configs.go @@ -119,6 +119,7 @@ func CreateChainSimulatorConfigs(args ArgsChainSimulatorConfigs) (*ArgsConfigsSi configs.GeneralConfig.EpochStartConfig.ExtraDelayForRequestBlockInfoInMilliseconds = 1 configs.GeneralConfig.EpochStartConfig.GenesisEpoch = args.InitialEpoch + configs.GeneralConfig.EpochStartConfig.MinRoundsBetweenEpochs = 1 if args.RoundsPerEpoch.HasValue { configs.GeneralConfig.EpochStartConfig.RoundsPerEpoch = int64(args.RoundsPerEpoch.Value) diff --git a/node/chainSimulator/process/interface.go b/node/chainSimulator/process/interface.go index d7b0f15820e..47f937fb97c 100644 --- a/node/chainSimulator/process/interface.go +++ b/node/chainSimulator/process/interface.go @@ -24,6 +24,7 @@ type NodeHandler interface { SetKeyValueForAddress(addressBytes []byte, state map[string]string) error SetStateForAddress(address []byte, state *dtos.AddressState) error RemoveAccount(address []byte) error + ForceChangeOfEpoch() error Close() error IsInterfaceNil() bool } diff --git a/testscommon/chainSimulator/nodeHandlerMock.go b/testscommon/chainSimulator/nodeHandlerMock.go index 9e0a2ca4d3b..3f306807130 100644 --- a/testscommon/chainSimulator/nodeHandlerMock.go +++ b/testscommon/chainSimulator/nodeHandlerMock.go @@ -27,6 +27,11 @@ type NodeHandlerMock struct { CloseCalled func() error } +// ForceChangeOfEpoch - +func (mock *NodeHandlerMock) ForceChangeOfEpoch() error { + return nil +} + // GetProcessComponents - func (mock *NodeHandlerMock) GetProcessComponents() factory.ProcessComponentsHolder { if mock.GetProcessComponentsCalled != nil {