Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
41597fe
Merge pull request #157 from multiversx/merge-main-in-supernova
miiu96 Aug 12, 2025
3dcc4e5
update go mod
danielradu10 Oct 7, 2025
a127d3d
fix
danielradu10 Oct 7, 2025
572525f
Merge pull request #167 from multiversx/update-go-mod
sstanculeanu Oct 7, 2025
86a5743
update
danielradu10 Oct 9, 2025
4d71f58
Merge pull request #168 from multiversx/update-rc-supernova
danielradu10 Oct 9, 2025
e9bc316
updated mx-chain-go
sstanculeanu Oct 14, 2025
7eb0e77
Merge pull request #169 from multiversx/fix-genesis-time-mismatch-in-…
sstanculeanu Oct 14, 2025
f9f5817
updated mx-chain-go
sstanculeanu Oct 17, 2025
6eb2769
Merge pull request #170 from multiversx/time-duration-fix-manual-roun…
sstanculeanu Oct 17, 2025
0bdb3c4
updated mx-chain-go
sstanculeanu Oct 21, 2025
e333969
Merge pull request #171 from multiversx/fix-custom-configs-chain-simu…
sstanculeanu Oct 28, 2025
9e68456
updated mx-chain-go with the latest chain simulator arguments
sstanculeanu Oct 28, 2025
9dfa7f7
updated mx-chain-go
sstanculeanu Oct 28, 2025
7ec3cec
updated mx-chain-go
sstanculeanu Oct 29, 2025
16860d5
Merge pull request #174 from multiversx/update-node
sstanculeanu Oct 29, 2025
14983c2
bump mx-chain-go
ssd04 Nov 11, 2025
7c159da
Merge pull request #178 from multiversx/update-mx-chain-go
ssd04 Nov 11, 2025
1c67899
Merge branch 'rc/supernova' of https://github.com/multiversx/mx-chain…
sstanculeanu Nov 12, 2025
a7725b3
go mod tidy
sstanculeanu Nov 12, 2025
06082d8
increase timeout
sstanculeanu Nov 12, 2025
f347825
Merge pull request #173 from multiversx/new-parameters
sstanculeanu Nov 12, 2025
c4d8ef2
fix supernova activation round
miiu96 Nov 13, 2025
8cac912
Merge branch 'main' of https://github.com/multiversx/mx-chain-simulat…
sstanculeanu Nov 24, 2025
f9f6fb6
updated mx-chain-go after merge
sstanculeanu Nov 24, 2025
c28e818
Merge pull request #181 from multiversx/merge-main-into-rc-supernova
sstanculeanu Nov 24, 2025
3173352
Merge branch 'rc/supernova' into fix-supernova-actionvation-round
miiu96 Nov 27, 2025
7fdd69f
update
miiu96 Nov 27, 2025
6461d6f
testing with ram
raduchis Nov 28, 2025
2964329
latest commit
miiu96 Dec 2, 2025
22aab80
cpu profile added
raduchis Dec 2, 2025
b5b9d4d
Bypass blocks signature
axenteoctavian Dec 2, 2025
048498d
fix go.mod
axenteoctavian Dec 2, 2025
f66e0e5
updated name to enable-profiling
raduchis Dec 2, 2025
43d56b1
Merge pull request #180 from multiversx/fix-supernova-actionvation-round
axenteoctavian Dec 3, 2025
71da764
Merge branch 'rc/supernova' into bypass-blocks-signature
axenteoctavian Dec 3, 2025
61815e7
Merge branch 'main' of https://github.com/multiversx/mx-chain-simulat…
sstanculeanu Dec 8, 2025
87808d5
updated mx-chain-go
sstanculeanu Dec 8, 2025
52726eb
Update go.mod
axenteoctavian Dec 8, 2025
c1b3e2f
fix
miiu96 Dec 8, 2025
2d34f31
Merge pull request #190 from multiversx/merge-main-into-rc/supernova-…
sstanculeanu Dec 8, 2025
71e8fa6
Merge branch 'rc/supernova' into bypass-blocks-signature
axenteoctavian Dec 12, 2025
8c773ac
Update go.mod
axenteoctavian Dec 12, 2025
baacc71
updated mx-chain-go to v1.11.2-0.20251215095623-aaca4d73f477
raduchis Dec 15, 2025
6d12db1
Merge pull request #192 from multiversx/supernova-to-chain-simulator-…
raduchis Dec 15, 2025
205b7bc
Merge branch 'refs/heads/rc/supernova' into bypass-blocks-signature
axenteoctavian Dec 16, 2025
5030edd
Update go.mod
axenteoctavian Dec 16, 2025
3a46bd4
fixes after review
axenteoctavian Dec 16, 2025
7f0959c
Merge branch 'rc/supernova' into pprof-and-shutdown
raduchis Dec 16, 2025
b7705e0
Merge pull request #185 from multiversx/pprof-and-shutdown
raduchis Dec 16, 2025
afdf5d0
Merge branch 'rc/supernova' into bypass-blocks-signature
axenteoctavian Dec 17, 2025
6a11acd
Merge pull request #183 from multiversx/bypass-blocks-signature
axenteoctavian Dec 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,12 @@ The **_[config.toml](./cmd/chainsimulator/config/config.toml)_** file:
num-of-shards = 3
# round-duration-in-milliseconds parameter specifies the duration of a simulated round. The timestamp between two headers will correspond to the round duration but will not reflect real-time
round-duration-in-milliseconds = 6000
# supernova-round-duration-in-milliseconds parameter specifies the duration of a simulated round after supernova. The timestamp between two headers will correspond to the round duration but will not reflect real-time
supernova-round-duration-in-milliseconds = 600
# rounds-per-epoch specifies the number of rounds per epoch
rounds-per-epoch = 20
# supernova-rounds-per-epoch specifies the number of rounds per epoch after supernova
supernova-rounds-per-epoch = 200
# initial-round specifies with what round the chain simulator will start
initial-round = 0
# initial-nonce specifies with what nonce the chain simulator will start
Expand Down
4 changes: 4 additions & 0 deletions cmd/chainsimulator/config/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
num-of-shards = 3
# round-duration-in-milliseconds parameter specifies the duration of a simulated round. The timestamp between two headers will correspond to the round duration but will not reflect real-time
round-duration-in-milliseconds = 6000
# supernova-round-duration-in-milliseconds parameter specifies the duration of a simulated round after supernova. The timestamp between two headers will correspond to the round duration but will not reflect real-time
supernova-round-duration-in-milliseconds = 600
# rounds-per-epoch specifies the number of rounds per epoch
rounds-per-epoch = 20
# supernova-rounds-per-epoch specifies the number of rounds per epoch after supernova
supernova-rounds-per-epoch = 200
# initial-round when the chain simulator will start
initial-round = 0
# initial-epoch when the chain simulator will start
Expand Down
29 changes: 28 additions & 1 deletion cmd/chainsimulator/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import (
"time"

logger "github.com/multiversx/mx-chain-logger-go"
"github.com/multiversx/mx-chain-simulator-go/config"
"github.com/urfave/cli"

"github.com/multiversx/mx-chain-simulator-go/config"
)

const nodeOverrideDefaultFilename = "nodeOverrideDefault.toml"
Expand Down Expand Up @@ -66,6 +67,11 @@ var (
Usage: "The number of rounds per epoch",
Value: 20,
}
supernovaRoundsPerEpoch = cli.IntFlag{
Name: "supernova-rounds-per-epoch",
Usage: "The number of rounds per epoch after supernova",
Value: 200,
}
numOfShards = cli.IntFlag{
Name: "num-of-shards",
Usage: "The number of shards",
Expand All @@ -81,10 +87,19 @@ var (
Usage: "The round duration in milliseconds",
Value: 6000,
}
supernovaRoundDurationInMs = cli.IntFlag{
Name: "supernova-round-duration",
Usage: "The round duration in milliseconds after supernova",
Value: 600,
}
bypassTransactionsSignature = cli.BoolTFlag{
Name: "bypass-txs-signature",
Usage: "This flag is used to bypass the transactions signature verification (by default true)",
}
bypassBlocksSignature = cli.BoolTFlag{
Name: "bypass-blocks-signature",
Usage: "This flag is used to bypass the blocks signature verification (by default true)",
}
numValidatorsPerShard = cli.IntFlag{
Name: "num-validators-per-shard",
Usage: "This flag is used to specify the number of validators per shard",
Expand Down Expand Up @@ -137,13 +152,21 @@ var (
Name: "fetch-configs-and-close",
Usage: "This flag is used to specify to fetch all configs and close the chain simulator after",
}
enableProfiling = cli.BoolFlag{
Name: "enable-profiling",
Usage: "Boolean option for enabling CPU profiling. If set, CPU profile will be saved to a file.",
}
)

func applyFlags(ctx *cli.Context, cfg *config.Config) {
if ctx.IsSet(roundsPerEpoch.Name) {
cfg.Config.Simulator.RoundsPerEpoch = ctx.GlobalInt(roundsPerEpoch.Name)
}

if ctx.IsSet(supernovaRoundsPerEpoch.Name) {
cfg.Config.Simulator.SupernovaRoundsPerEpoch = ctx.GlobalInt(supernovaRoundsPerEpoch.Name)
}

if ctx.IsSet(numOfShards.Name) {
cfg.Config.Simulator.NumOfShards = ctx.GlobalInt(numOfShards.Name)
}
Expand All @@ -156,6 +179,10 @@ func applyFlags(ctx *cli.Context, cfg *config.Config) {
cfg.Config.Simulator.RoundDurationInMs = ctx.GlobalInt(roundDurationInMs.Name)
}

if ctx.IsSet(supernovaRoundDurationInMs.Name) {
cfg.Config.Simulator.SupernovaRoundDurationInMs = ctx.GlobalInt(supernovaRoundDurationInMs.Name)
}

if ctx.IsSet(initialRound.Name) {
cfg.Config.Simulator.InitialRound = ctx.GlobalInt64(initialRound.Name)
}
Expand Down
143 changes: 123 additions & 20 deletions cmd/chainsimulator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ package main
import (
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"runtime/debug"
"runtime/pprof"
"strconv"
"strings"
"syscall"
"time"

"github.com/gin-gonic/gin"
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/core/closing"
Expand All @@ -20,14 +23,15 @@ import (
"github.com/multiversx/mx-chain-go/node/chainSimulator/components/api"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/multiversx/mx-chain-logger-go/file"
"github.com/urfave/cli"

"github.com/multiversx/mx-chain-simulator-go/config"
"github.com/multiversx/mx-chain-simulator-go/pkg/facade"
"github.com/multiversx/mx-chain-simulator-go/pkg/factory"
endpoints "github.com/multiversx/mx-chain-simulator-go/pkg/proxy/api"
"github.com/multiversx/mx-chain-simulator-go/pkg/proxy/configs"
"github.com/multiversx/mx-chain-simulator-go/pkg/proxy/configs/git"
"github.com/multiversx/mx-chain-simulator-go/pkg/proxy/creator"
"github.com/urfave/cli"
)

const timeToAllowProxyToStart = time.Millisecond * 10
Expand Down Expand Up @@ -68,10 +72,13 @@ func main() {
pathToProxyConfigs,
startTime,
roundsPerEpoch,
supernovaRoundsPerEpoch,
numOfShards,
serverPort,
roundDurationInMs,
supernovaRoundDurationInMs,
bypassTransactionsSignature,
bypassBlocksSignature,
numValidatorsPerShard,
numWaitingValidatorsPerShard,
numValidatorsMeta,
Expand All @@ -84,6 +91,7 @@ func main() {
skipConfigsDownload,
fetchConfigsAndClose,
pathWhereToSaveLogs,
enableProfiling,
}

app.Authors = []cli.Author{
Expand Down Expand Up @@ -136,12 +144,19 @@ func startChainSimulator(ctx *cli.Context) error {
}

bypassTxsSignature := ctx.GlobalBool(bypassTransactionsSignature.Name)
log.Warn("signature", "bypass", bypassTxsSignature)
log.Debug("signature", "bypass", bypassTxsSignature)
bypassBlocksSignature := ctx.GlobalBool(bypassBlocksSignature.Name)
log.Debug("blocks", "bypass", bypassBlocksSignature)
roundDurationInMillis := uint64(cfg.Config.Simulator.RoundDurationInMs)
supernovaRoundDurationInMillis := uint64(cfg.Config.Simulator.SupernovaRoundDurationInMs)
rounds := core.OptionalUint64{
HasValue: true,
Value: uint64(cfg.Config.Simulator.RoundsPerEpoch),
}
supernovaRounds := core.OptionalUint64{
HasValue: true,
Value: uint64(cfg.Config.Simulator.SupernovaRoundsPerEpoch),
}

numValidatorsShard := ctx.GlobalInt(numValidatorsPerShard.Name)
if numValidatorsShard < 1 {
Expand Down Expand Up @@ -170,23 +185,43 @@ func startChainSimulator(ctx *cli.Context) error {
return err
}

// CPU profiling setup - only if enable-profiling flag is set
var profileFile *os.File
profilingEnabled := ctx.GlobalBool(enableProfiling.Name)
if profilingEnabled {
pathLogsSave := ctx.GlobalString(pathWhereToSaveLogs.Name)
profileFile, err = startCPUProfiling(pathLogsSave, startTimeUnix)
if err != nil {
return fmt.Errorf("%w while starting CPU profiling", err)
}

// Ensure pprof is stopped and file is synced/closed even on early exits
defer func() {
log.Info("stopping CPU profile (defer)")
stopCPUProfiling(profileFile)
}()
}

var alterConfigsError error
argsChainSimulator := chainSimulator.ArgsChainSimulator{
BypassTxSignatureCheck: bypassTxsSignature,
TempDir: tempDir,
PathToInitialConfig: nodeConfigs,
NumOfShards: uint32(cfg.Config.Simulator.NumOfShards),
GenesisTimestamp: startTimeUnix,
RoundDurationInMillis: roundDurationInMillis,
RoundsPerEpoch: rounds,
ApiInterface: apiConfigurator,
MinNodesPerShard: uint32(numValidatorsShard),
NumNodesWaitingListShard: uint32(numWaitingValidatorsShard),
MetaChainMinNodes: uint32(numValidatorsMetaShard),
NumNodesWaitingListMeta: uint32(numWaitingValidatorsMetaShard),
InitialRound: cfg.Config.Simulator.InitialRound,
InitialNonce: cfg.Config.Simulator.InitialNonce,
InitialEpoch: cfg.Config.Simulator.InitialEpoch,
BypassTxSignatureCheck: bypassTxsSignature,
BypassBlockSignatureCheck: bypassBlocksSignature,
TempDir: tempDir,
PathToInitialConfig: nodeConfigs,
NumOfShards: uint32(cfg.Config.Simulator.NumOfShards),
GenesisTimestamp: startTimeUnix,
RoundDurationInMillis: roundDurationInMillis,
SupernovaRoundDurationInMillis: supernovaRoundDurationInMillis,
RoundsPerEpoch: rounds,
SupernovaRoundsPerEpoch: supernovaRounds,
ApiInterface: apiConfigurator,
MinNodesPerShard: uint32(numValidatorsShard),
NumNodesWaitingListShard: uint32(numWaitingValidatorsShard),
MetaChainMinNodes: uint32(numValidatorsMetaShard),
NumNodesWaitingListMeta: uint32(numWaitingValidatorsMetaShard),
InitialRound: cfg.Config.Simulator.InitialRound,
InitialNonce: cfg.Config.Simulator.InitialNonce,
InitialEpoch: cfg.Config.Simulator.InitialEpoch,
AlterConfigsFunction: func(cfg *nodeConfig.Configs) {
alterConfigsError = overridableConfig.OverrideConfigValues(overrideCfg.OverridableConfigTomlValues, cfg)
},
Expand Down Expand Up @@ -268,7 +303,28 @@ func startChainSimulator(ctx *cli.Context) error {
return err
}

err = endpointsProc.ExtendProxyServer(proxyInstance.GetHttpServer())
// Create a channel for programmatic shutdown
shutdownChan := make(chan struct{})

// Add a shutdown endpoint before extending the proxy server
httpServer := proxyInstance.GetHttpServer()
ginEngine, ok := httpServer.Handler.(*gin.Engine)
if !ok {
return fmt.Errorf("cannot cast httpServer.Handler to gin.Engine")
}

ginEngine.POST("/simulator/shutdown", func(c *gin.Context) {
log.Info("shutdown requested via HTTP endpoint")
c.JSON(http.StatusOK, gin.H{"message": "shutdown initiated"})

// Trigger shutdown in a goroutine to allow the response to be sent
go func() {
time.Sleep(100 * time.Millisecond)
close(shutdownChan)
}()
})

err = endpointsProc.ExtendProxyServer(httpServer)
if err != nil {
return err
}
Expand All @@ -280,9 +336,19 @@ func startChainSimulator(ctx *cli.Context) error {

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
<-interrupt

log.Info("close")
// Wait for either signal or programmatic shutdown
select {
case sig := <-interrupt:
log.Info("close", "signal", sig)
case <-shutdownChan:
log.Info("close", "trigger", "HTTP shutdown endpoint")
}

// Stop CPU profiling FIRST and flush to disk (only if profiling is enabled)
if profilingEnabled {
stopCPUProfiling(profileFile)
}

generator.Close()

Expand All @@ -297,6 +363,43 @@ func startChainSimulator(ctx *cli.Context) error {
return nil
}

func startCPUProfiling(pathLogsSave string, startTimeUnix int64) (*os.File, error) {
timestampMilisecond := time.Unix(startTimeUnix, 0).UnixNano() / 1000000
cpuProfilePath := fmt.Sprintf("%s/cpu-%d.pprof", pathLogsSave, timestampMilisecond)

profileFile, err := os.Create(cpuProfilePath)
if err != nil {
return nil, fmt.Errorf("could not create CPU profile: %w", err)
}

if err := pprof.StartCPUProfile(profileFile); err != nil {
_ = profileFile.Close()
return nil, fmt.Errorf("could not start CPU profile: %w", err)
}

log.Info("CPU profiling started", "path", cpuProfilePath)
return profileFile, nil
}

func stopCPUProfiling(profileFile *os.File) {
if profileFile == nil {
return
}

log.Info("stopping CPU profile")
pprof.StopCPUProfile()

if err := profileFile.Sync(); err != nil {
log.Error("error syncing CPU profile file", "err", err)
}

if err := profileFile.Close(); err != nil {
log.Error("error closing CPU profile file", "err", err)
} else {
log.Info("CPU profile file closed successfully")
}
}

func initializeLogger(ctx *cli.Context, cfg config.Config) (closing.Closer, error) {
logLevelFlagValue := ctx.GlobalString(logLevel.Name)
err := logger.SetLogLevel(logLevelFlagValue)
Expand Down
20 changes: 11 additions & 9 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import "github.com/multiversx/mx-chain-go/config"
type Config struct {
Config struct {
Simulator struct {
ServerPort int `toml:"server-port"`
NumOfShards int `toml:"num-of-shards"`
RoundsPerEpoch int `toml:"rounds-per-epoch"`
RoundDurationInMs int `toml:"round-duration-in-milliseconds"`
InitialRound int64 `toml:"initial-round"`
InitialNonce uint64 `toml:"initial-nonce"`
InitialEpoch uint32 `toml:"initial-epoch"`
MxChainRepo string `toml:"mx-chain-go-repo"`
MxProxyRepo string `toml:"mx-chain-proxy-go-repo"`
ServerPort int `toml:"server-port"`
NumOfShards int `toml:"num-of-shards"`
RoundsPerEpoch int `toml:"rounds-per-epoch"`
SupernovaRoundsPerEpoch int `toml:"supernova-rounds-per-epoch"`
RoundDurationInMs int `toml:"round-duration-in-milliseconds"`
SupernovaRoundDurationInMs int `toml:"supernova-round-duration-in-milliseconds"`
InitialRound int64 `toml:"initial-round"`
InitialNonce uint64 `toml:"initial-nonce"`
InitialEpoch uint32 `toml:"initial-epoch"`
MxChainRepo string `toml:"mx-chain-go-repo"`
MxProxyRepo string `toml:"mx-chain-proxy-go-repo"`
} `toml:"simulator"`
Logs struct {
LogFileLifeSpanInMB int `toml:"log-file-life-span-in-mb"`
Expand Down
2 changes: 1 addition & 1 deletion examples/generateBlocks/epoch-reached.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

def main():
# create a network provider config to increase timeout
config = NetworkProviderConfig(requests_options={"timeout": 10})
config = NetworkProviderConfig(requests_options={"timeout": 200})

# create a network provider
provider = ProxyNetworkProvider(url=SIMULATOR_URL, config=config)
Expand Down
6 changes: 3 additions & 3 deletions examples/staking/staking.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ def main():

# check if the owner receive more than 5 egld in rewards
claim_reward_tx = get_tx_and_verify_status(provider, tx_hash.hex())
one_egld = 1000000000000000000
min_rewards = 400000000000000000
rewards_value = claim_reward_tx.smart_contract_results[0].raw.get("value", 0)
if rewards_value < one_egld:
if rewards_value < min_rewards:
sys.exit(f"owner of the delegation contract didn't receive the expected amount of rewards: expected more than "
f"1 EGLD, received: {rewards_value}")
f"0.4 EGLD, received: {rewards_value}")

print(f"owner has received rewards, received rewards: {rewards_value}")

Expand Down
Loading
Loading