Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added & integrated manual round handler #5684

Merged
merged 8 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion integrationTests/realcomponents/processorRunner_test.go
Expand Up @@ -12,7 +12,7 @@ func TestNewProcessorRunnerAndClose(t *testing.T) {
t.Skip("this is not a short test")
}

cfg, err := testscommon.CreateTestConfigs("../../cmd/node/config")
cfg, err := testscommon.CreateTestConfigs(t.TempDir(), "../../cmd/node/config")
require.Nil(t, err)

pr := NewProcessorRunner(t, *cfg)
Expand Down
Expand Up @@ -23,7 +23,7 @@ func TestTransactionSimulationComponentConstructionOnMetachain(t *testing.T) {
t.Skip("this is not a short test")
}

cfg, err := testscommon.CreateTestConfigs("../../../cmd/node/config")
cfg, err := testscommon.CreateTestConfigs(t.TempDir(), "../../../cmd/node/config")
require.Nil(t, err)

cfg.EpochConfig.EnableEpochs.ESDTEnableEpoch = 0
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestTransactionSimulationComponentConstructionOnShard(t *testing.T) {
t.Skip("this is not a short test")
}

cfg, err := testscommon.CreateTestConfigs("../../../cmd/node/config")
cfg, err := testscommon.CreateTestConfigs(t.TempDir(), "../../../cmd/node/config")
require.Nil(t, err)

cfg.EpochConfig.EnableEpochs.SCDeployEnableEpoch = 0
Expand Down
83 changes: 49 additions & 34 deletions node/chainSimulator/chainSimulator.go
@@ -1,7 +1,6 @@
package chainSimulator

import (
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/data/endProcess"
"github.com/multiversx/mx-chain-go/config"
"github.com/multiversx/mx-chain-go/node/chainSimulator/components"
Expand All @@ -18,7 +17,13 @@ type simulator struct {
}

// NewChainSimulator will create a new instance of simulator
func NewChainSimulator(numOfShards uint32, pathToInitialConfig string) (*simulator, error) {
func NewChainSimulator(
tempDir string,
numOfShards uint32,
pathToInitialConfig string,
genesisTimestamp int64,
roundDurationInMillis uint64,
) (*simulator, error) {
syncedBroadcastNetwork := components.NewSyncedBroadcastNetwork()

instance := &simulator{
Expand All @@ -28,47 +33,51 @@ func NewChainSimulator(numOfShards uint32, pathToInitialConfig string) (*simulat
chanStopNodeProcess: make(chan endProcess.ArgEndProcess),
}

err := instance.createChainHandlers(numOfShards, pathToInitialConfig)
err := instance.createChainHandlers(tempDir, numOfShards, pathToInitialConfig, genesisTimestamp, roundDurationInMillis)
if err != nil {
return nil, err
}

return instance, nil
}

func (s *simulator) createChainHandlers(numOfShards uint32, originalConfigPath string) error {
func (s *simulator) createChainHandlers(
tempDir string,
numOfShards uint32,
originalConfigPath string,
genesisTimestamp int64,
roundDurationInMillis uint64,
) error {
outputConfigs, err := configs.CreateChainSimulatorConfigs(configs.ArgsChainSimulatorConfigs{
NumOfShards: numOfShards,
OriginalConfigsPath: originalConfigPath,
GenesisAddressWithStake: testdata.GenesisAddressWithStake,
GenesisAddressWithBalance: testdata.GenesisAddressWithBalance,
GenesisTimeStamp: genesisTimestamp,
RoundDurationInMillis: roundDurationInMillis,
TempDir: tempDir,
})
if err != nil {
return err
}

blsKey := outputConfigs.ValidatorsPublicKeys[core.MetachainShardId]
metaChainHandler, err := s.createChainHandler(core.MetachainShardId, outputConfigs.Configs, 0, outputConfigs.GasScheduleFilename, blsKey)
if err != nil {
return err
}

s.nodes = append(s.nodes, metaChainHandler)

for idx := uint32(0); idx < numOfShards; idx++ {
blsKey = outputConfigs.ValidatorsPublicKeys[idx+1]
shardChainHandler, errS := s.createChainHandler(idx, outputConfigs.Configs, int(idx)+1, outputConfigs.GasScheduleFilename, blsKey)
if errS != nil {
return errS
for idx := range outputConfigs.ValidatorsPrivateKeys {
chainHandler, errCreate := s.createChainHandler(outputConfigs.Configs, idx, outputConfigs.GasScheduleFilename)
if errCreate != nil {
return errCreate
}

s.nodes = append(s.nodes, shardChainHandler)
s.nodes = append(s.nodes, chainHandler)
}

return nil
}

func (s *simulator) createChainHandler(shardID uint32, configs *config.Configs, skIndex int, gasScheduleFilename string, blsKeyBytes []byte) (ChainHandler, error) {
func (s *simulator) createChainHandler(
configs *config.Configs,
skIndex int,
gasScheduleFilename string,
) (ChainHandler, error) {
args := components.ArgsTestOnlyProcessingNode{
Config: *configs.GeneralConfig,
EpochConfig: *configs.EpochConfig,
Expand All @@ -83,7 +92,6 @@ func (s *simulator) createChainHandler(shardID uint32, configs *config.Configs,
SyncedBroadcastNetwork: s.syncedBroadcastNetwork,
NumShards: s.numOfShards,
GasScheduleFilename: gasScheduleFilename,
ShardID: shardID,
SkIndex: skIndex,
}

Expand All @@ -92,28 +100,35 @@ func (s *simulator) createChainHandler(shardID uint32, configs *config.Configs,
return nil, err
}

return process.NewBlocksCreator(testNode, blsKeyBytes)
return process.NewBlocksCreator(testNode)
}

// GenerateBlocks will generate the provided number of blocks
func (s *simulator) GenerateBlocks(numOfBlocks int) error {
for idx := 0; idx < numOfBlocks; idx++ {
for idxNode, node := range s.nodes {
// TODO change this
if idxNode == 0 {
err := node.CreateNewBlock()
if err != nil {
return err
}
} else if idxNode == 1 {
err := node.CreateNewBlock()
if err != nil {
return err
}
}
s.incrementRoundOnAllValidators()
err := s.allNodesCreateBlocks()
if err != nil {
return err
}
}
return nil
}

func (s *simulator) incrementRoundOnAllValidators() {
for _, node := range s.nodes {
node.IncrementRound()
}
}

func (s *simulator) allNodesCreateBlocks() error {
for _, node := range s.nodes {
err := node.CreateNewBlock()
if err != nil {
return err
}
}

return nil
}

Expand Down
16 changes: 15 additions & 1 deletion node/chainSimulator/chainSimulator_test.go
Expand Up @@ -12,9 +12,23 @@ const (
)

func TestNewChainSimulator(t *testing.T) {
chainSimulator, err := NewChainSimulator(3, defaultPathToInitialConfig)
startTime := time.Now().Unix()
roundDurationInMillis := uint64(6000)
chainSimulator, err := NewChainSimulator(t.TempDir(), 3, defaultPathToInitialConfig, startTime, roundDurationInMillis)
require.Nil(t, err)
require.NotNil(t, chainSimulator)
defer chainSimulator.Stop()

time.Sleep(time.Second)
}

func TestChainSimulator_GenerateBlocksShouldWork(t *testing.T) {
startTime := time.Now().Unix()
roundDurationInMillis := uint64(6000)
chainSimulator, err := NewChainSimulator(t.TempDir(), 3, defaultPathToInitialConfig, startTime, roundDurationInMillis)
require.Nil(t, err)
require.NotNil(t, chainSimulator)
defer chainSimulator.Stop()

time.Sleep(time.Second)

Expand Down
14 changes: 8 additions & 6 deletions node/chainSimulator/components/coreComponents.go
Expand Up @@ -136,8 +136,14 @@ func CreateCoreComponentsHolder(args ArgsCoreComponentsHolder) (factory.CoreComp
instance.watchdog = &watchdog.DisabledWatchdog{}
instance.alarmScheduler = &mock.AlarmSchedulerStub{}
instance.syncTimer = &testscommon.SyncTimerStub{}
// TODO discuss with Iulian about the round handler
instance.roundHandler = &testscommon.RoundHandlerMock{}

instance.genesisNodesSetup, err = sharding.NewNodesSetup(args.NodesSetupPath, instance.addressPubKeyConverter, instance.validatorPubKeyConverter, args.NumShards)
if err != nil {
return nil, err
}

roundDuration := time.Millisecond * time.Duration(instance.genesisNodesSetup.GetRoundDuration())
instance.roundHandler = NewManualRoundHandler(instance.genesisNodesSetup.GetStartTime(), roundDuration)

instance.wasmVMChangeLocker = &sync.RWMutex{}
instance.txVersionChecker = versioning.NewTxVersionChecker(args.Config.GeneralSettings.MinTransactionVersion)
Expand Down Expand Up @@ -191,10 +197,6 @@ func CreateCoreComponentsHolder(args ArgsCoreComponentsHolder) (factory.CoreComp
instance.ratingsData = &testscommon.RatingsInfoMock{}
instance.rater = &testscommon.RaterMock{}

instance.genesisNodesSetup, err = sharding.NewNodesSetup(args.NodesSetupPath, instance.addressPubKeyConverter, instance.validatorPubKeyConverter, args.NumShards)
if err != nil {
return nil, err
}
// TODO check if we need nodes shuffler
instance.nodesShuffler = &shardingMocks.NodeShufflerMock{}

Expand Down
63 changes: 63 additions & 0 deletions node/chainSimulator/components/manualRoundHandler.go
@@ -0,0 +1,63 @@
package components

import (
"sync/atomic"
"time"
)

type manualRoundHandler struct {
index int64
genesisTimeStamp int64
roundDuration time.Duration
}

// NewManualRoundHandler returns a manual round handler instance
func NewManualRoundHandler(genesisTimeStamp int64, roundDuration time.Duration) *manualRoundHandler {
return &manualRoundHandler{
genesisTimeStamp: genesisTimeStamp,
roundDuration: roundDuration,
}
}

// IncrementIndex will increment the current round index
func (handler *manualRoundHandler) IncrementIndex() {
atomic.AddInt64(&handler.index, 1)
}

// Index returns the current index
func (handler *manualRoundHandler) Index() int64 {
return atomic.LoadInt64(&handler.index)
}

// BeforeGenesis returns false
func (handler *manualRoundHandler) BeforeGenesis() bool {
return false
}

// UpdateRound does nothing as this implementation does not work with real timers
func (handler *manualRoundHandler) UpdateRound(_ time.Time, _ time.Time) {
}

// TimeStamp returns the time based of the genesis timestamp and the current round
func (handler *manualRoundHandler) TimeStamp() time.Time {
rounds := atomic.LoadInt64(&handler.index)
timeFromGenesis := handler.roundDuration * time.Duration(rounds)
timestamp := time.Unix(handler.genesisTimeStamp, 0).Add(timeFromGenesis)

return timestamp
}

// TimeDuration returns the provided time duration for this instance
func (handler *manualRoundHandler) TimeDuration() time.Duration {
return handler.roundDuration
}

// RemainingTime returns the max time as the start time is not taken into account
func (handler *manualRoundHandler) RemainingTime(_ time.Time, maxTime time.Duration) time.Duration {
return maxTime
}

// IsInterfaceNil returns true if there is no value under the interface
func (handler *manualRoundHandler) IsInterfaceNil() bool {
return handler == nil
}