diff --git a/cmd/node/config/economics.toml b/cmd/node/config/economics.toml index f0bac97a055..f34d9ed57f3 100644 --- a/cmd/node/config/economics.toml +++ b/cmd/node/config/economics.toml @@ -39,9 +39,10 @@ [FeeSettings] GasLimitSettings = [ - {EnableEpoch = 0, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "1500000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "15000000000", MaxGasLimitPerTx = "1500000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000"}, - {EnableEpoch = 1, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "250000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "250000000", MaxGasLimitPerTx = "600000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000"}, - {EnableEpoch = 2, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "250000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "250000000", MaxGasLimitPerTx = "600000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000"}, + {EnableEpoch = 0, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "1500000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "15000000000", MaxGasLimitPerTx = "1500000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000", MaxGasHigherFactorAccepted = "10"}, + {EnableEpoch = 1, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "250000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "250000000", MaxGasLimitPerTx = "600000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000", MaxGasHigherFactorAccepted = "10"}, + {EnableEpoch = 2, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "250000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "250000000", MaxGasLimitPerTx = "600000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000", MaxGasHigherFactorAccepted = "10"}, + {EnableEpoch = 3, MaxGasLimitPerBlock = "1500000000", MaxGasLimitPerMiniBlock = "250000000", MaxGasLimitPerMetaBlock = "15000000000", MaxGasLimitPerMetaMiniBlock = "250000000", MaxGasLimitPerTx = "600000000", MinGasLimit = "50000", ExtraGasLimitGuardedTx = "50000", MaxGasHigherFactorAccepted = "2"}, ] MinGasPrice = "1000000000" #will yield min tx fee of 0.00005 eGLD GasPriceModifier = 0.01 diff --git a/cmd/node/config/external.toml b/cmd/node/config/external.toml index 6fbbbb195c6..73bc78bae55 100644 --- a/cmd/node/config/external.toml +++ b/cmd/node/config/external.toml @@ -12,8 +12,8 @@ Username = "" Password = "" # EnabledIndexes represents a slice of indexes that will be enabled for indexing. Full list is: - # ["rating", "transactions", "blocks", "validators", "miniblocks", "rounds", "accounts", "accountshistory", "receipts", "scresults", "accountsesdt", "accountsesdthistory", "epochinfo", "scdeploys", "tokens", "tags", "logs", "delegators", "operations", "esdts"] - EnabledIndexes = ["rating", "transactions", "blocks", "validators", "miniblocks", "rounds", "accounts", "accountshistory", "receipts", "scresults", "accountsesdt", "accountsesdthistory", "epochinfo", "scdeploys", "tokens", "tags", "logs", "delegators", "operations", "esdts"] + # ["rating", "transactions", "blocks", "validators", "miniblocks", "rounds", "accounts", "accountshistory", "receipts", "scresults", "accountsesdt", "accountsesdthistory", "epochinfo", "scdeploys", "tokens", "tags", "logs", "delegators", "operations", "esdts", "events"] + EnabledIndexes = ["rating", "transactions", "blocks", "validators", "miniblocks", "rounds", "accounts", "accountshistory", "receipts", "scresults", "accountsesdt", "accountsesdthistory", "epochinfo", "scdeploys", "tokens", "tags", "logs", "delegators", "operations", "esdts", "events"] # EventNotifierConnector defines settings needed to configure and launch the event notifier component # HTTP event notifier connector integration will be DEPRECATED in the following iterations diff --git a/config/economicsConfig.go b/config/economicsConfig.go index 35c67d92469..4d33b87f548 100644 --- a/config/economicsConfig.go +++ b/config/economicsConfig.go @@ -41,6 +41,7 @@ type GasLimitSetting struct { MaxGasLimitPerTx string MinGasLimit string ExtraGasLimitGuardedTx string + MaxGasHigherFactorAccepted string } // FeeSettings will hold economics fee settings diff --git a/config/tomlConfig_test.go b/config/tomlConfig_test.go index 767e37e3950..4803aa048dd 100644 --- a/config/tomlConfig_test.go +++ b/config/tomlConfig_test.go @@ -271,7 +271,9 @@ func TestTomlEconomicsParser(t *testing.T) { minGasLimit := "18446744073709551615" extraGasLimitGuardedTx := "50000" maxGasPriceSetGuardian := "1234567" + maxGasHigherFactorAccepted := "10" protocolSustainabilityAddress := "erd1932eft30w753xyvme8d49qejgkjc09n5e49w4mwdjtm0neld797su0dlxp" + denomination := 18 cfgEconomicsExpected := EconomicsConfig{ @@ -299,9 +301,10 @@ func TestTomlEconomicsParser(t *testing.T) { FeeSettings: FeeSettings{ GasLimitSettings: []GasLimitSetting{ { - MaxGasLimitPerBlock: maxGasLimitPerBlock, - MinGasLimit: minGasLimit, - ExtraGasLimitGuardedTx: extraGasLimitGuardedTx, + MaxGasLimitPerBlock: maxGasLimitPerBlock, + MinGasLimit: minGasLimit, + ExtraGasLimitGuardedTx: extraGasLimitGuardedTx, + MaxGasHigherFactorAccepted: maxGasHigherFactorAccepted, }, }, MinGasPrice: minGasPrice, @@ -328,7 +331,7 @@ func TestTomlEconomicsParser(t *testing.T) { ProtocolSustainabilityAddress = "` + protocolSustainabilityAddress + `" [FeeSettings] - GasLimitSettings = [{EnableEpoch = 0, MaxGasLimitPerBlock = "` + maxGasLimitPerBlock + `", MaxGasLimitPerMiniBlock = "", MaxGasLimitPerMetaBlock = "", MaxGasLimitPerMetaMiniBlock = "", MaxGasLimitPerTx = "", MinGasLimit = "` + minGasLimit + `", ExtraGasLimitGuardedTx = "` + extraGasLimitGuardedTx + `"}] + GasLimitSettings = [{EnableEpoch = 0, MaxGasLimitPerBlock = "` + maxGasLimitPerBlock + `", MaxGasLimitPerMiniBlock = "", MaxGasLimitPerMetaBlock = "", MaxGasLimitPerMetaMiniBlock = "", MaxGasLimitPerTx = "", MinGasLimit = "` + minGasLimit + `", ExtraGasLimitGuardedTx = "` + extraGasLimitGuardedTx + `", MaxGasHigherFactorAccepted = "` + maxGasHigherFactorAccepted + `"}] MinGasPrice = "` + minGasPrice + `" MaxGasPriceSetGuardian = "` + maxGasPriceSetGuardian + `" ` diff --git a/genesis/process/disabled/feeHandler.go b/genesis/process/disabled/feeHandler.go index 0b3051cf845..9f2a8f7ec29 100644 --- a/genesis/process/disabled/feeHandler.go +++ b/genesis/process/disabled/feeHandler.go @@ -77,6 +77,11 @@ func (fh *FeeHandler) MaxGasLimitPerMiniBlockForSafeCrossShard() uint64 { return math.MaxUint64 } +// MaxGasHigherFactorAccepted returns 10 +func (fh *FeeHandler) MaxGasHigherFactorAccepted() uint64 { + return 10 +} + // MaxGasLimitPerTx returns max uint64 func (fh *FeeHandler) MaxGasLimitPerTx() uint64 { return math.MaxUint64 @@ -169,22 +174,22 @@ func (fh *FeeHandler) ComputeTxFeeBasedOnGasUsed(_ data.TransactionWithFeeHandle } // ComputeTxFeeInEpoch returns 0 -func (fh *FeeHandler) ComputeTxFeeInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int { +func (fh *FeeHandler) ComputeTxFeeInEpoch(_ data.TransactionWithFeeHandler, _ uint32) *big.Int { return big.NewInt(0) } // ComputeGasLimitInEpoch returns 0 -func (fh *FeeHandler) ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) uint64 { +func (fh *FeeHandler) ComputeGasLimitInEpoch(_ data.TransactionWithFeeHandler, _ uint32) uint64 { return 0 } // ComputeGasUsedAndFeeBasedOnRefundValueInEpoch returns 0 -func (fh *FeeHandler) ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) { +func (fh *FeeHandler) ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(_ data.TransactionWithFeeHandler, _ *big.Int, _ uint32) (uint64, *big.Int) { return 0, big.NewInt(0) } // ComputeTxFeeBasedOnGasUsedInEpoch returns 0 -func (fh *FeeHandler) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int { +func (fh *FeeHandler) ComputeTxFeeBasedOnGasUsedInEpoch(_ data.TransactionWithFeeHandler, _ uint64, _ uint32) *big.Int { return big.NewInt(0) } diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index b7426c63f5f..c685b00fafb 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -794,7 +794,7 @@ func testFixRelayedMoveBalanceWithChainSimulatorScCall( require.NoError(t, err) // send relayed tx, fix still not active - innerTx = generateTransaction(owner.Bytes, 2, scAddressBytes, big.NewInt(0), txDataAdd, 3000000) + innerTx = generateTransaction(owner.Bytes, 2, scAddressBytes, big.NewInt(0), txDataAdd, 1230000) marshalledTx, err = json.Marshal(innerTx) require.NoError(t, err) txData = []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) @@ -817,7 +817,7 @@ func testFixRelayedMoveBalanceWithChainSimulatorScCall( require.NoError(t, err) // send relayed tx after fix - innerTx = generateTransaction(owner.Bytes, 3, scAddressBytes, big.NewInt(0), txDataAdd, 3000000) + innerTx = generateTransaction(owner.Bytes, 3, scAddressBytes, big.NewInt(0), txDataAdd, 1500000) marshalledTx, err = json.Marshal(innerTx) require.NoError(t, err) txData = []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) diff --git a/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go b/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go index acb0c7537ed..53509154985 100644 --- a/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go +++ b/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go @@ -1884,7 +1884,7 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInBatches(t *testing.T, require.Nil(t, err) require.NotNil(t, unStakeTx) - unStakeTxFee, _ := big.NewInt(0).SetString(unStakeTx.Fee, 10) + unStakeTxFee1, _ := big.NewInt(0).SetString(unStakeTx.Fee, 10) testEpoch := targetEpoch + 1 err = cs.GenerateBlocksUntilEpochIsReached(testEpoch) @@ -1898,6 +1898,8 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInBatches(t *testing.T, require.Nil(t, err) require.NotNil(t, unStakeTx) + unStakeTxFee2, _ := big.NewInt(0).SetString(unStakeTx.Fee, 10) + testEpoch++ err = cs.GenerateBlocksUntilEpochIsReached(testEpoch) require.Nil(t, err) @@ -1910,6 +1912,8 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInBatches(t *testing.T, require.Nil(t, err) require.NotNil(t, unStakeTx) + unStakeTxFee3, _ := big.NewInt(0).SetString(unStakeTx.Fee, 10) + testEpoch++ err = cs.GenerateBlocksUntilEpochIsReached(testEpoch) require.Nil(t, err) @@ -1977,9 +1981,9 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInBatches(t *testing.T, txsFee.Add(txsFee, stakeTxFee) txsFee.Add(txsFee, unBondTxFee) - txsFee.Add(txsFee, unStakeTxFee) - txsFee.Add(txsFee, unStakeTxFee) - txsFee.Add(txsFee, unStakeTxFee) + txsFee.Add(txsFee, unStakeTxFee1) + txsFee.Add(txsFee, unStakeTxFee2) + txsFee.Add(txsFee, unStakeTxFee3) balanceAfterUnbonding.Add(balanceAfterUnbonding, txsFee) diff --git a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go index 423faa3fbab..bcc63c71d28 100644 --- a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go +++ b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go @@ -34,7 +34,7 @@ import ( var log = logger.GetOrCreate("stakingProvider") const gasLimitForConvertOperation = 510_000_000 -const gasLimitForDelegationContractCreationOperation = 500_000_000 +const gasLimitForDelegationContractCreationOperation = 100_000_000 const gasLimitForAddNodesOperation = 500_000_000 const gasLimitForUndelegateOperation = 500_000_000 const gasLimitForMergeOperation = 600_000_000 diff --git a/integrationTests/chainSimulator/vm/esdtImprovements_test.go b/integrationTests/chainSimulator/vm/esdtImprovements_test.go index e0f23f1ce8c..8361feb4fee 100644 --- a/integrationTests/chainSimulator/vm/esdtImprovements_test.go +++ b/integrationTests/chainSimulator/vm/esdtImprovements_test.go @@ -3868,7 +3868,9 @@ func TestChainSimulator_CheckRolesWhichHasToBeSingular(t *testing.T) { } func TestChainSimulator_metaESDT_mergeMetaDataFromMultipleUpdates(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) @@ -4237,7 +4239,9 @@ func transferSpecialRoleToAddr( } func TestChainSimulator_dynamicNFT_mergeMetaDataFromMultipleUpdates(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) @@ -4385,7 +4389,9 @@ func TestChainSimulator_dynamicNFT_mergeMetaDataFromMultipleUpdates(t *testing.T } func TestChainSimulator_dynamicNFT_changeMetaDataForOneNFTShouldNotChangeOtherNonces(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) @@ -4498,7 +4504,9 @@ func TestChainSimulator_dynamicNFT_changeMetaDataForOneNFTShouldNotChangeOtherNo } func TestChainSimulator_dynamicNFT_updateBeforeCreateOnSameAccountShouldOverwrite(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) @@ -4595,7 +4603,9 @@ func TestChainSimulator_dynamicNFT_updateBeforeCreateOnSameAccountShouldOverwrit } func TestChainSimulator_dynamicNFT_updateBeforeCreateOnDifferentAccountsShouldMergeMetaDataWhenTransferred(t *testing.T) { - t.Parallel() + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 14c7a6a1ba2..c6f27b1f1e9 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -1151,6 +1151,7 @@ func createDefaultEconomicsConfig() *config.EconomicsConfig { MaxGasLimitPerTx: maxGasLimitPerBlock, MinGasLimit: minGasLimit, ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: minGasPrice, diff --git a/integrationTests/vm/testInitializer.go b/integrationTests/vm/testInitializer.go index c6e33ddc21a..af0b607c4d6 100644 --- a/integrationTests/vm/testInitializer.go +++ b/integrationTests/vm/testInitializer.go @@ -359,6 +359,7 @@ func createEconomicsData(enableEpochsConfig config.EnableEpochs, gasPriceModifie MaxGasLimitPerTx: maxGasLimitPerBlock, MinGasLimit: minGasLimit, ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: minGasPrice, diff --git a/integrationTests/vm/wasm/utils.go b/integrationTests/vm/wasm/utils.go index bfe7b4b7ca9..61402910679 100644 --- a/integrationTests/vm/wasm/utils.go +++ b/integrationTests/vm/wasm/utils.go @@ -242,6 +242,7 @@ func (context *TestContext) initFeeHandlers() { MaxGasLimitPerTx: maxGasLimitPerBlock, MinGasLimit: minGasLimit, ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: minGasPrice, diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 0d3d4d25e6a..e1786e43528 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -11,7 +11,9 @@ import ( "time" "github.com/multiversx/mx-chain-go/config" + "github.com/multiversx/mx-chain-go/factory" "github.com/multiversx/mx-chain-go/node/chainSimulator/components" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/heartbeat" "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" chainSimulatorErrors "github.com/multiversx/mx-chain-go/node/chainSimulator/errors" @@ -130,18 +132,20 @@ func (s *simulator) createChainHandlers(args ArgsBaseChainSimulator) error { return err } + monitor := heartbeat.NewHeartbeatMonitor() + for idx := -1; idx < int(args.NumOfShards); idx++ { shardIDStr := fmt.Sprintf("%d", idx) if idx == -1 { shardIDStr = "metachain" } - node, errCreate := s.createTestNode(*outputConfigs, args, shardIDStr) + node, errCreate := s.createTestNode(*outputConfigs, args, shardIDStr, monitor) if errCreate != nil { return errCreate } - chainHandler, errCreate := process.NewBlocksCreator(node) + chainHandler, errCreate := process.NewBlocksCreator(node, monitor) if errCreate != nil { return errCreate } @@ -195,7 +199,7 @@ func computeStartTimeBaseOnInitialRound(args ArgsChainSimulator) int64 { } func (s *simulator) createTestNode( - outputConfigs configs.ArgsConfigsSimulator, args ArgsBaseChainSimulator, shardIDStr string, + outputConfigs configs.ArgsConfigsSimulator, args ArgsBaseChainSimulator, shardIDStr string, monitor factory.HeartbeatV2Monitor, ) (process.NodeHandler, error) { argsTestOnlyProcessorNode := components.ArgsTestOnlyProcessingNode{ Configs: outputConfigs.Configs, @@ -214,6 +218,7 @@ func (s *simulator) createTestNode( MetaChainConsensusGroupSize: args.MetaChainConsensusGroupSize, RoundDurationInMillis: args.RoundDurationInMillis, VmQueryDelayAfterStartInMs: args.VmQueryDelayAfterStartInMs, + Monitor: monitor, } return components.NewTestOnlyProcessingNode(argsTestOnlyProcessorNode) diff --git a/node/chainSimulator/chainSimulator_test.go b/node/chainSimulator/chainSimulator_test.go index 18f54ccbfe9..2ba89205afe 100644 --- a/node/chainSimulator/chainSimulator_test.go +++ b/node/chainSimulator/chainSimulator_test.go @@ -82,13 +82,17 @@ func TestChainSimulator_GenerateBlocksShouldWork(t *testing.T) { }) require.Nil(t, err) require.NotNil(t, chainSimulator) - defer chainSimulator.Close() time.Sleep(time.Second) err = chainSimulator.GenerateBlocks(50) require.Nil(t, err) + + heartBeats, err := chainSimulator.GetNodeHandler(0).GetFacadeHandler().GetHeartbeats() + require.Nil(t, err) + require.Equal(t, 4, len(heartBeats)) + } func TestChainSimulator_GenerateBlocksAndEpochChangeShouldWork(t *testing.T) { diff --git a/node/chainSimulator/components/coreComponents_test.go b/node/chainSimulator/components/coreComponents_test.go index 7056d9ae48c..96ace01e30c 100644 --- a/node/chainSimulator/components/coreComponents_test.go +++ b/node/chainSimulator/components/coreComponents_test.go @@ -73,6 +73,7 @@ func createArgsCoreComponentsHolder() ArgsCoreComponentsHolder { MaxGasLimitPerTx: "10000000000", MinGasLimit: "10", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, GasPriceModifier: 0.01, diff --git a/node/chainSimulator/components/heartbeat/heartBeat.go b/node/chainSimulator/components/heartbeat/heartBeat.go new file mode 100644 index 00000000000..ffdd53b6961 --- /dev/null +++ b/node/chainSimulator/components/heartbeat/heartBeat.go @@ -0,0 +1,52 @@ +package heartbeat + +import ( + "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-go/factory" + "github.com/multiversx/mx-chain-go/heartbeat" +) + +type heartBeatComponents struct { + monitor factory.HeartbeatV2Monitor +} + +// NewSyncedHeartbeatComponents will create a new instance of heartbeat components +func NewSyncedHeartbeatComponents(monitor factory.HeartbeatV2Monitor) (factory.HeartbeatV2ComponentsHandler, error) { + if check.IfNil(monitor) { + return nil, heartbeat.ErrNilHeartbeatMonitor + } + + return &heartBeatComponents{ + monitor: monitor, + }, nil +} + +// Create will do nothing +func (h *heartBeatComponents) Create() error { + return nil +} + +// Close will do nothing +func (h *heartBeatComponents) Close() error { + return nil +} + +// CheckSubcomponents will do nothing +func (h *heartBeatComponents) CheckSubcomponents() error { + return nil +} + +// String will return a string +func (h *heartBeatComponents) String() string { + return "heartBeat" +} + +// Monitor will return the monitor +func (h *heartBeatComponents) Monitor() factory.HeartbeatV2Monitor { + return h.monitor +} + +// IsInterfaceNil returns true if there is no value under the interface +func (h *heartBeatComponents) IsInterfaceNil() bool { + return h == nil +} diff --git a/node/chainSimulator/components/heartbeat/monitor.go b/node/chainSimulator/components/heartbeat/monitor.go new file mode 100644 index 00000000000..9fda1a369f8 --- /dev/null +++ b/node/chainSimulator/components/heartbeat/monitor.go @@ -0,0 +1,39 @@ +package heartbeat + +import ( + "sync" + + "github.com/multiversx/mx-chain-go/heartbeat/data" +) + +type heartbeatMonitor struct { + heartbeats []data.PubKeyHeartbeat + mutex sync.RWMutex +} + +// NewHeartbeatMonitor will create a new instance of heartbeat monitor +func NewHeartbeatMonitor() *heartbeatMonitor { + return &heartbeatMonitor{ + heartbeats: make([]data.PubKeyHeartbeat, 0), + } +} + +// GetHeartbeats will return the heartbeats +func (hm *heartbeatMonitor) GetHeartbeats() []data.PubKeyHeartbeat { + hm.mutex.RLock() + defer hm.mutex.RUnlock() + + return hm.heartbeats +} + +// SetHeartbeats will set the provided heartbeats +func (hm *heartbeatMonitor) SetHeartbeats(heartbeats []data.PubKeyHeartbeat) { + hm.mutex.Lock() + hm.heartbeats = heartbeats + hm.mutex.Unlock() +} + +// IsInterfaceNil returns true if there is no value under the interface +func (hm *heartbeatMonitor) IsInterfaceNil() bool { + return nil == hm +} diff --git a/node/chainSimulator/components/nodeFacade.go b/node/chainSimulator/components/nodeFacade.go index 934807c0659..139053cbf94 100644 --- a/node/chainSimulator/components/nodeFacade.go +++ b/node/chainSimulator/components/nodeFacade.go @@ -12,13 +12,15 @@ import ( "github.com/multiversx/mx-chain-go/common/forking" "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/facade" + "github.com/multiversx/mx-chain-go/factory" apiComp "github.com/multiversx/mx-chain-go/factory/api" nodePack "github.com/multiversx/mx-chain-go/node" + simulatorHeartbeat "github.com/multiversx/mx-chain-go/node/chainSimulator/components/heartbeat" "github.com/multiversx/mx-chain-go/node/metrics" "github.com/multiversx/mx-chain-go/process/mock" ) -func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInterface APIConfigurator, vmQueryDelayAfterStartInMs uint64) error { +func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInterface APIConfigurator, vmQueryDelayAfterStartInMs uint64, monitor factory.HeartbeatV2Monitor) error { log.Debug("creating api resolver structure") err := node.createMetrics(configs) @@ -73,6 +75,13 @@ func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInte flagsConfig := configs.FlagsConfig + heartbeatComponents, err := simulatorHeartbeat.NewSyncedHeartbeatComponents(monitor) + if err != nil { + return err + } + + node.closeHandler.AddComponent(heartbeatComponents) + nd, err := nodePack.NewNode( nodePack.WithStatusCoreComponents(node.StatusCoreComponents), nodePack.WithCoreComponents(node.CoreComponentsHolder), @@ -95,6 +104,7 @@ func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInte nodePack.WithNodeStopChannel(node.CoreComponentsHolder.ChanStopNodeProcess()), nodePack.WithImportMode(configs.ImportDbConfig.IsImportDBMode), nodePack.WithESDTNFTStorageHandler(node.ProcessComponentsHolder.ESDTDataStorageHandlerForAPI()), + nodePack.WithHeartbeatV2Components(heartbeatComponents), ) if err != nil { return errors.New("error creating node: " + err.Error()) diff --git a/node/chainSimulator/components/statusComponents.go b/node/chainSimulator/components/statusComponents.go index be094472fc1..ab561e25c2c 100644 --- a/node/chainSimulator/components/statusComponents.go +++ b/node/chainSimulator/components/statusComponents.go @@ -9,16 +9,22 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/appStatusPolling" "github.com/multiversx/mx-chain-core-go/core/check" + nodeData "github.com/multiversx/mx-chain-core-go/data" + outportCore "github.com/multiversx/mx-chain-core-go/data/outport" factoryMarshalizer "github.com/multiversx/mx-chain-core-go/marshal/factory" indexerFactory "github.com/multiversx/mx-chain-es-indexer-go/process/factory" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/common/statistics" "github.com/multiversx/mx-chain-go/config" + "github.com/multiversx/mx-chain-go/epochStart" + "github.com/multiversx/mx-chain-go/epochStart/notifier" "github.com/multiversx/mx-chain-go/errors" + "github.com/multiversx/mx-chain-go/factory" "github.com/multiversx/mx-chain-go/integrationTests/mock" "github.com/multiversx/mx-chain-go/outport" - "github.com/multiversx/mx-chain-go/outport/factory" + outportFactory "github.com/multiversx/mx-chain-go/outport/factory" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" "github.com/multiversx/mx-chain-go/testscommon" ) @@ -32,10 +38,11 @@ type statusComponentsHolder struct { statusPollingIntervalSec int cancelFunc func() mutex sync.RWMutex + nodesCoordinator nodesCoordinator.NodesCoordinator } // CreateStatusComponents will create a new instance of status components holder -func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandler, statusPollingIntervalSec int, external config.ExternalConfig, coreComponents process.CoreComponentsHolder) (*statusComponentsHolder, error) { +func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandler, statusPollingIntervalSec int, external config.ExternalConfig, coreComponents factory.CoreComponentsHandler) (*statusComponentsHolder, error) { if check.IfNil(appStatusHandler) { return nil, core.ErrNilAppStatusHandler } @@ -51,12 +58,12 @@ func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandl if err != nil { return nil, err } - instance.outportHandler, err = factory.CreateOutport(&factory.OutportFactoryArgs{ + instance.outportHandler, err = outportFactory.CreateOutport(&outportFactory.OutportFactoryArgs{ IsImportDB: false, ShardID: shardID, RetrialInterval: time.Second, HostDriversArgs: hostDriverArgs, - EventNotifierFactoryArgs: &factory.EventNotifierFactoryArgs{}, + EventNotifierFactoryArgs: &outportFactory.EventNotifierFactoryArgs{}, ElasticIndexerFactoryArgs: makeElasticIndexerArgs(external, coreComponents), }) if err != nil { @@ -65,13 +72,45 @@ func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandl instance.softwareVersionChecker = &mock.SoftwareVersionCheckerMock{} instance.managedPeerMonitor = &testscommon.ManagedPeersMonitorStub{} + if shardID == core.MetachainShardId { + coreComponents.EpochStartNotifierWithConfirm().RegisterHandler(instance.epochStartEventHandler()) + } + instance.collectClosableComponents() return instance, nil } -func makeHostDriversArgs(external config.ExternalConfig) ([]factory.ArgsHostDriverFactory, error) { - argsHostDriverFactorySlice := make([]factory.ArgsHostDriverFactory, 0, len(external.HostDriversConfig)) +// SetNodesCoordinator will set the nodes coordinator +func (s *statusComponentsHolder) SetNodesCoordinator(nodesCoordinator nodesCoordinator.NodesCoordinator) { + s.mutex.Lock() + s.nodesCoordinator = nodesCoordinator + s.mutex.Unlock() +} + +func (s *statusComponentsHolder) epochStartEventHandler() epochStart.ActionHandler { + subscribeHandler := notifier.NewHandlerForEpochStart(func(hdr nodeData.HeaderHandler) { + currentEpoch := hdr.GetEpoch() + validatorsPubKeys, err := s.nodesCoordinator.GetAllEligibleValidatorsPublicKeys(currentEpoch) + if err != nil { + log.Warn("s.nodesCoordinator.GetAllEligibleValidatorPublicKeys for current epoch failed", + "epoch", currentEpoch, + "error", err.Error()) + } + + s.outportHandler.SaveValidatorsPubKeys(&outportCore.ValidatorsPubKeys{ + ShardID: hdr.GetShardID(), + ShardValidatorsPubKeys: outportCore.ConvertPubKeys(validatorsPubKeys), + Epoch: currentEpoch, + }) + + }, func(_ nodeData.HeaderHandler) {}, common.IndexerOrder) + + return subscribeHandler +} + +func makeHostDriversArgs(external config.ExternalConfig) ([]outportFactory.ArgsHostDriverFactory, error) { + argsHostDriverFactorySlice := make([]outportFactory.ArgsHostDriverFactory, 0, len(external.HostDriversConfig)) for idx := 0; idx < len(external.HostDriversConfig); idx++ { hostConfig := external.HostDriversConfig[idx] if !hostConfig.Enabled { @@ -83,7 +122,7 @@ func makeHostDriversArgs(external config.ExternalConfig) ([]factory.ArgsHostDriv return argsHostDriverFactorySlice, err } - argsHostDriverFactorySlice = append(argsHostDriverFactorySlice, factory.ArgsHostDriverFactory{ + argsHostDriverFactorySlice = append(argsHostDriverFactorySlice, outportFactory.ArgsHostDriverFactory{ Marshaller: marshaller, HostConfig: hostConfig, }) diff --git a/node/chainSimulator/components/testOnlyProcessingNode.go b/node/chainSimulator/components/testOnlyProcessingNode.go index efa4c12102c..bc8f9b8de1a 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode.go +++ b/node/chainSimulator/components/testOnlyProcessingNode.go @@ -37,6 +37,7 @@ type ArgsTestOnlyProcessingNode struct { ChanStopNodeProcess chan endProcess.ArgEndProcess SyncedBroadcastNetwork SyncedBroadcastNetworkHandler + Monitor factory.HeartbeatV2Monitor InitialRound int64 InitialNonce uint64 @@ -148,7 +149,8 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces } selfShardID := instance.GetShardCoordinator().SelfId() - instance.StatusComponentsHolder, err = CreateStatusComponents( + + statusComponentsH, err := CreateStatusComponents( selfShardID, instance.StatusCoreComponents.AppStatusHandler(), args.Configs.GeneralConfig.GeneralSettings.StatusPollingIntervalSec, @@ -159,6 +161,8 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces return nil, err } + instance.StatusComponentsHolder = statusComponentsH + err = instance.createBlockChain(selfShardID) if err != nil { return nil, err @@ -191,6 +195,8 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces return nil, err } + statusComponentsH.SetNodesCoordinator(instance.NodesCoordinator) + instance.DataComponentsHolder, err = CreateDataComponents(ArgsDataComponentsHolder{ Chain: instance.ChainHandler, StorageService: instance.StoreService, @@ -242,7 +248,7 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces return nil, err } - err = instance.createFacade(args.Configs, args.APIInterface, args.VmQueryDelayAfterStartInMs) + err = instance.createFacade(args.Configs, args.APIInterface, args.VmQueryDelayAfterStartInMs, args.Monitor) if err != nil { return nil, err } diff --git a/node/chainSimulator/components/testOnlyProcessingNode_test.go b/node/chainSimulator/components/testOnlyProcessingNode_test.go index c363ca8019c..801c11585e9 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode_test.go +++ b/node/chainSimulator/components/testOnlyProcessingNode_test.go @@ -2,6 +2,7 @@ package components import ( "errors" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/heartbeat" "math/big" "strings" "testing" @@ -44,6 +45,7 @@ func createMockArgsTestOnlyProcessingNode(t *testing.T) ArgsTestOnlyProcessingNo SyncedBroadcastNetwork: NewSyncedBroadcastNetwork(), ChanStopNodeProcess: make(chan endProcess.ArgEndProcess), APIInterface: api.NewNoApiInterface(), + Monitor: heartbeat.NewHeartbeatMonitor(), ShardIDStr: "0", RoundDurationInMillis: 6000, MinNodesMeta: 1, diff --git a/node/chainSimulator/process/interface.go b/node/chainSimulator/process/interface.go index 47f937fb97c..7ae2f07517e 100644 --- a/node/chainSimulator/process/interface.go +++ b/node/chainSimulator/process/interface.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-go/api/shared" "github.com/multiversx/mx-chain-go/consensus" "github.com/multiversx/mx-chain-go/factory" + "github.com/multiversx/mx-chain-go/heartbeat/data" "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" "github.com/multiversx/mx-chain-go/sharding" ) @@ -28,3 +29,9 @@ type NodeHandler interface { Close() error IsInterfaceNil() bool } + +// HeartbeatMonitorWithSet defines what a heartbeat monitor with set should be able to do +type HeartbeatMonitorWithSet interface { + SetHeartbeats(heartbeats []data.PubKeyHeartbeat) + IsInterfaceNil() bool +} diff --git a/node/chainSimulator/process/processor.go b/node/chainSimulator/process/processor.go index d8f225bfde8..1c9819e27f0 100644 --- a/node/chainSimulator/process/processor.go +++ b/node/chainSimulator/process/processor.go @@ -1,10 +1,13 @@ package process import ( + "time" + "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/consensus/spos" + heartbeatData "github.com/multiversx/mx-chain-go/heartbeat/data" "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" logger "github.com/multiversx/mx-chain-logger-go" ) @@ -17,16 +20,18 @@ type manualRoundHandler interface { type blocksCreator struct { nodeHandler NodeHandler + monitor HeartbeatMonitorWithSet } // NewBlocksCreator will create a new instance of blocksCreator -func NewBlocksCreator(nodeHandler NodeHandler) (*blocksCreator, error) { +func NewBlocksCreator(nodeHandler NodeHandler, monitor HeartbeatMonitorWithSet) (*blocksCreator, error) { if check.IfNil(nodeHandler) { return nil, ErrNilNodeHandler } return &blocksCreator{ nodeHandler: nodeHandler, + monitor: monitor, }, nil } @@ -123,6 +128,11 @@ func (creator *blocksCreator) CreateNewBlock() error { return err } + err = creator.setHeartBeat(header) + if err != nil { + return err + } + miniBlocks, transactions, err := bp.MarshalizedDataToBroadcast(header, block) if err != nil { return err @@ -141,6 +151,32 @@ func (creator *blocksCreator) CreateNewBlock() error { return creator.nodeHandler.GetBroadcastMessenger().BroadcastTransactions(transactions, blsKey.PubKey()) } +func (creator *blocksCreator) setHeartBeat(header data.HeaderHandler) error { + if !header.IsStartOfEpochBlock() { + return nil + } + + validators := creator.nodeHandler.GetProcessComponents().ValidatorsProvider().GetLatestValidators() + + var heartbeats []heartbeatData.PubKeyHeartbeat + for key, validator := range validators { + heartbeats = append(heartbeats, heartbeatData.PubKeyHeartbeat{ + PublicKey: key, + TimeStamp: time.Now(), + IsActive: true, + NumInstances: 1, + ComputedShardID: creator.nodeHandler.GetShardCoordinator().SelfId(), + ReceivedShardID: validator.ShardId, + }) + } + + if len(heartbeats) > 0 { + creator.monitor.SetHeartbeats(heartbeats) + } + + return nil +} + func (creator *blocksCreator) getPreviousHeaderData() (nonce, round uint64, prevHash, prevRandSeed []byte, epoch uint32) { currentHeader := creator.nodeHandler.GetChainHandler().GetCurrentBlockHeader() diff --git a/node/chainSimulator/process/processor_test.go b/node/chainSimulator/process/processor_test.go index 80ffd568134..84a93eea028 100644 --- a/node/chainSimulator/process/processor_test.go +++ b/node/chainSimulator/process/processor_test.go @@ -14,6 +14,7 @@ import ( mockConsensus "github.com/multiversx/mx-chain-go/consensus/mock" "github.com/multiversx/mx-chain-go/factory" "github.com/multiversx/mx-chain-go/integrationTests/mock" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/heartbeat" chainSimulatorProcess "github.com/multiversx/mx-chain-go/node/chainSimulator/process" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" @@ -35,14 +36,14 @@ func TestNewBlocksCreator(t *testing.T) { t.Run("nil node handler should error", func(t *testing.T) { t.Parallel() - creator, err := chainSimulatorProcess.NewBlocksCreator(nil) + creator, err := chainSimulatorProcess.NewBlocksCreator(nil, heartbeat.NewHeartbeatMonitor()) require.Equal(t, chainSimulatorProcess.ErrNilNodeHandler, err) require.Nil(t, creator) }) t.Run("should work", func(t *testing.T) { t.Parallel() - creator, err := chainSimulatorProcess.NewBlocksCreator(&chainSimulator.NodeHandlerMock{}) + creator, err := chainSimulatorProcess.NewBlocksCreator(&chainSimulator.NodeHandlerMock{}, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) require.NotNil(t, creator) }) @@ -51,10 +52,10 @@ func TestNewBlocksCreator(t *testing.T) { func TestBlocksCreator_IsInterfaceNil(t *testing.T) { t.Parallel() - creator, _ := chainSimulatorProcess.NewBlocksCreator(nil) + creator, _ := chainSimulatorProcess.NewBlocksCreator(nil, heartbeat.NewHeartbeatMonitor()) require.True(t, creator.IsInterfaceNil()) - creator, _ = chainSimulatorProcess.NewBlocksCreator(&chainSimulator.NodeHandlerMock{}) + creator, _ = chainSimulatorProcess.NewBlocksCreator(&chainSimulator.NodeHandlerMock{}, heartbeat.NewHeartbeatMonitor()) require.False(t, creator.IsInterfaceNil()) } @@ -86,7 +87,7 @@ func TestBlocksCreator_IncrementRound(t *testing.T) { } }, } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) creator.IncrementRound() @@ -119,7 +120,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -227,7 +228,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -246,7 +247,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -267,7 +268,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -319,7 +320,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -340,7 +341,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -361,7 +362,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -382,7 +383,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -521,7 +522,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { }, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -530,7 +531,7 @@ func TestBlocksCreator_CreateNewBlock(t *testing.T) { t.Run("should work", func(t *testing.T) { t.Parallel() - creator, err := chainSimulatorProcess.NewBlocksCreator(getNodeHandler()) + creator, err := chainSimulatorProcess.NewBlocksCreator(getNodeHandler(), heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() @@ -547,7 +548,7 @@ func testCreateNewBlock(t *testing.T, blockProcess process.BlockProcessor, expec NodesCoord: nc, } } - creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler) + creator, err := chainSimulatorProcess.NewBlocksCreator(nodeHandler, heartbeat.NewHeartbeatMonitor()) require.NoError(t, err) err = creator.CreateNewBlock() diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index 84e161ef86f..44c5165d1cd 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -400,6 +400,17 @@ func (ed *economicsData) MaxGasLimitPerBlockForSafeCrossShard() uint64 { return ed.MaxGasLimitPerBlockForSafeCrossShardInEpoch(currentEpoch) } +// MaxGasHigherFactorAccepted returns maximum gas higher factor accepted +func (ed *economicsData) MaxGasHigherFactorAccepted() uint64 { + currentEpoch := ed.enableEpochsHandler.GetCurrentEpoch() + return ed.MaxGasHigherFactorAcceptedInEpoch(currentEpoch) +} + +// MaxGasHigherFactorAcceptedInEpoch returns maximum gas higher factor accepted for epoch +func (ed *economicsData) MaxGasHigherFactorAcceptedInEpoch(epoch uint32) uint64 { + return ed.getGasHigherFactorAccepted(epoch) +} + // MaxGasLimitPerBlockForSafeCrossShardInEpoch returns maximum gas limit per block for safe cross shard in a specific epoch func (ed *economicsData) MaxGasLimitPerBlockForSafeCrossShardInEpoch(epoch uint32) uint64 { return ed.getMaxGasLimitPerBlockForSafeCrossShard(epoch) diff --git a/process/economics/economicsData_test.go b/process/economics/economicsData_test.go index 1f2c913a826..f97dec2104e 100644 --- a/process/economics/economicsData_test.go +++ b/process/economics/economicsData_test.go @@ -64,6 +64,7 @@ func feeSettingsDummy(gasModifier float64) config.FeeSettings { MaxGasLimitPerTx: "100000", MinGasLimit: "500", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "18446744073709551615", @@ -84,6 +85,7 @@ func feeSettingsReal() config.FeeSettings { MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "1000000000", @@ -389,6 +391,36 @@ func TestNewEconomicsData_InvalidExtraGasLimitGuardedTxShouldErr(t *testing.T) { } } +func TestNewEconomicsData_InvalidMaxGasHigherFactorAccepted(t *testing.T) { + t.Parallel() + + args := createArgsForEconomicsData(1) + badExtraMaxGasHigherFactorAccepted := []string{ + "-1", + "-100000000000000000000", + "badValue", + "", + "#########", + "11112S", + "1111O0000", + "10ERD", + } + + for _, gasLimitGuardedTx := range badExtraMaxGasHigherFactorAccepted { + args.Economics.FeeSettings.GasLimitSettings[0].MaxGasHigherFactorAccepted = gasLimitGuardedTx + _, err := economics.NewEconomicsData(args) + assert.True(t, errors.Is(err, process.ErrInvalidMaxGasHigherFactorAccepted)) + } + + args.Economics.FeeSettings.GasLimitSettings[0].MaxGasHigherFactorAccepted = "0" + _, err := economics.NewEconomicsData(args) + assert.True(t, errors.Is(err, process.ErrInvalidMaxGasHigherFactorAccepted)) + + args.Economics.FeeSettings.GasLimitSettings[0].MaxGasHigherFactorAccepted = "2" + _, err = economics.NewEconomicsData(args) + assert.Nil(t, err) +} + func TestNewEconomicsData_MaxGasLimitPerBlockLowerThanMinGasLimitShouldErr(t *testing.T) { t.Parallel() @@ -716,6 +748,7 @@ func TestEconomicsData_ConfirmedGasLimitSettingsChangeOrderedConfigs(t *testing. MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, { EnableEpoch: 2, @@ -726,6 +759,7 @@ func TestEconomicsData_ConfirmedGasLimitSettingsChangeOrderedConfigs(t *testing. MaxGasLimitPerTx: "500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, } @@ -800,6 +834,7 @@ func TestEconomicsData_ConfirmedGasLimitSettingsChangeUnOrderedConfigs(t *testin MaxGasLimitPerTx: "500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, { EnableEpoch: 0, @@ -810,6 +845,7 @@ func TestEconomicsData_ConfirmedGasLimitSettingsChangeUnOrderedConfigs(t *testin MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, } diff --git a/process/economics/export_test.go b/process/economics/export_test.go index f466b60301e..fac481d4086 100644 --- a/process/economics/export_test.go +++ b/process/economics/export_test.go @@ -37,6 +37,7 @@ func (ed *economicsData) GetGasLimitSetting(epoch uint32) *config.GasLimitSettin gasLimitSetting.MaxGasLimitPerTx = strconv.FormatUint(cfg.maxGasLimitPerTx, 10) gasLimitSetting.MinGasLimit = strconv.FormatUint(cfg.minGasLimit, 10) gasLimitSetting.ExtraGasLimitGuardedTx = strconv.FormatUint(cfg.extraGasLimitGuardedTx, 10) + gasLimitSetting.MaxGasHigherFactorAccepted = strconv.FormatUint(cfg.maxGasHigherFactorAccepted, 10) return gasLimitSetting } diff --git a/process/economics/gasConfigHandler.go b/process/economics/gasConfigHandler.go index 02fcc3cece6..2955160b1c8 100644 --- a/process/economics/gasConfigHandler.go +++ b/process/economics/gasConfigHandler.go @@ -26,6 +26,7 @@ type gasConfig struct { maxGasLimitPerTx uint64 minGasLimit uint64 extraGasLimitGuardedTx uint64 + maxGasHigherFactorAccepted uint64 } type gasConfigHandler struct { @@ -113,6 +114,12 @@ func (handler *gasConfigHandler) getMaxGasLimitPerMiniBlock(epoch uint32) uint64 return gc.maxGasLimitPerMiniBlock } +// getMaxGasLimitPerMiniBlock returns max gas limit per mini block in a specific epoch +func (handler *gasConfigHandler) getGasHigherFactorAccepted(epoch uint32) uint64 { + gc := handler.getGasConfigForEpoch(epoch) + return gc.maxGasHigherFactorAccepted +} + // getMaxGasLimitPerBlockForSafeCrossShard returns maximum gas limit per block for safe cross shard in a specific epoch func (handler *gasConfigHandler) getMaxGasLimitPerBlockForSafeCrossShard(epoch uint32) uint64 { gc := handler.getGasConfigForEpoch(epoch) @@ -225,6 +232,11 @@ func checkAndParseGasLimitSettings(gasLimitSetting config.GasLimitSetting) (*gas return nil, fmt.Errorf("%w for epoch %d", process.ErrInvalidExtraGasLimitGuardedTx, gasLimitSetting.EnableEpoch) } + gc.maxGasHigherFactorAccepted, err = strconv.ParseUint(gasLimitSetting.MaxGasHigherFactorAccepted, conversionBase, bitConversionSize) + if err != nil { + return nil, fmt.Errorf("%w for epoch %d", process.ErrInvalidMaxGasHigherFactorAccepted, gasLimitSetting.EnableEpoch) + } + if gc.maxGasLimitPerBlock < gc.minGasLimit { return nil, fmt.Errorf("%w: maxGasLimitPerBlock = %d minGasLimit = %d in epoch %d", process.ErrInvalidMaxGasLimitPerBlock, gc.maxGasLimitPerBlock, gc.minGasLimit, gasLimitSetting.EnableEpoch) } @@ -240,6 +252,9 @@ func checkAndParseGasLimitSettings(gasLimitSetting config.GasLimitSetting) (*gas if gc.maxGasLimitPerTx < gc.minGasLimit { return nil, fmt.Errorf("%w: maxGasLimitPerTx = %d minGasLimit = %d in epoch %d", process.ErrInvalidMaxGasLimitPerTx, gc.maxGasLimitPerTx, gc.minGasLimit, gasLimitSetting.EnableEpoch) } + if gc.maxGasHigherFactorAccepted < 1 { + return nil, fmt.Errorf("%w for epoch %d, it is set to 0", process.ErrInvalidMaxGasHigherFactorAccepted, gasLimitSetting.EnableEpoch) + } return gc, nil } diff --git a/process/economics/testEconomicsData.go b/process/economics/testEconomicsData.go index 7e60812d1df..556cedb3ef6 100644 --- a/process/economics/testEconomicsData.go +++ b/process/economics/testEconomicsData.go @@ -68,6 +68,11 @@ func (ted *TestEconomicsData) SetMaxInflationRate(maximumInflation float64) { ted.yearSettings[0].MaximumInflation = maximumInflation } +// MaxGasHigherFactorAccepted returns 10 +func (ted *TestEconomicsData) MaxGasHigherFactorAccepted() uint64 { + return 10 +} + // SetStatusHandler returns nil func (ted *TestEconomicsData) SetStatusHandler(_ core.AppStatusHandler) error { return nil diff --git a/process/errors.go b/process/errors.go index 2f58af09f46..7cf46d995b5 100644 --- a/process/errors.go +++ b/process/errors.go @@ -534,6 +534,9 @@ var ErrInvalidExtraGasLimitGuardedTx = errors.New("invalid extra gas limit for g // ErrInvalidMaxGasPriceSetGuardian signals that an invalid maximum gas price has been provided in the config file var ErrInvalidMaxGasPriceSetGuardian = errors.New("invalid maximum gas price for set guardian") +// ErrInvalidMaxGasHigherFactorAccepted signals that an invalid gas factor has been provided in the config file +var ErrInvalidMaxGasHigherFactorAccepted = errors.New("invalid gas higher factor accepted") + // ErrGuardianSignatureNotExpected signals that the guardian signature is not expected var ErrGuardianSignatureNotExpected = errors.New("guardian signature not expected") diff --git a/process/factory/metachain/vmContainerFactory_test.go b/process/factory/metachain/vmContainerFactory_test.go index ff542213ef4..95d0fc05610 100644 --- a/process/factory/metachain/vmContainerFactory_test.go +++ b/process/factory/metachain/vmContainerFactory_test.go @@ -312,6 +312,7 @@ func TestVmContainerFactory_Create(t *testing.T) { MaxGasLimitPerTx: "10000000000", MinGasLimit: "10", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "10", diff --git a/process/interface.go b/process/interface.go index e5800a54796..7fdaec95b99 100644 --- a/process/interface.go +++ b/process/interface.go @@ -701,6 +701,7 @@ type feeHandler interface { ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int + MaxGasHigherFactorAccepted() uint64 } // TxGasHandler handles a transaction gas and gas cost diff --git a/process/peer/process_test.go b/process/peer/process_test.go index d4c85a5601f..3df1a8f5505 100644 --- a/process/peer/process_test.go +++ b/process/peer/process_test.go @@ -94,6 +94,7 @@ func createMockArguments() peer.ArgValidatorStatisticsProcessor { MaxGasLimitPerTx: "10000000", MinGasLimit: "10", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "10", diff --git a/process/smartContract/process_test.go b/process/smartContract/process_test.go index b6c81113f45..d1d52651fc1 100644 --- a/process/smartContract/process_test.go +++ b/process/smartContract/process_test.go @@ -4232,6 +4232,7 @@ func createRealEconomicsDataArgs() *economics.ArgsNewEconomicsData { MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, GasPerDataByte: "1500", diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index e0d88916a52..4ce291b5d45 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -2145,7 +2145,7 @@ func (sc *scProcessor) penalizeUserIfNeeded( return } - isTooMuchProvided := isTooMuchGasProvided(gasProvidedForProcessing, vmOutput.GasRemaining) + isTooMuchProvided := isTooMuchGasProvided(gasProvidedForProcessing, vmOutput.GasRemaining, sc.economicsFee) if !isTooMuchProvided { return } @@ -2174,13 +2174,17 @@ func (sc *scProcessor) penalizeUserIfNeeded( vmOutput.GasRemaining = 0 } -func isTooMuchGasProvided(gasProvided uint64, gasRemained uint64) bool { +func isTooMuchGasProvided( + gasProvided uint64, + gasRemained uint64, + economicsFee process.FeeHandler, +) bool { if gasProvided <= gasRemained { return false } gasUsed := gasProvided - gasRemained - return gasProvided > gasUsed*process.MaxGasFeeHigherFactorAccepted + return gasProvided > gasUsed*economicsFee.MaxGasHigherFactorAccepted() } func (sc *scProcessor) createSCRsWhenError( diff --git a/process/smartContract/processorV2/process_test.go b/process/smartContract/processorV2/process_test.go index 638e096005e..8cc162cd3a2 100644 --- a/process/smartContract/processorV2/process_test.go +++ b/process/smartContract/processorV2/process_test.go @@ -3443,20 +3443,41 @@ func TestScProcessor_penalizeUserIfNeededShouldWork(t *testing.T) { func TestScProcessor_isTooMuchGasProvidedShouldWork(t *testing.T) { t.Parallel() + economicsHandler := &economicsmocks.EconomicsHandlerStub{} + gasProvided := uint64(100) - maxGasToRemain := gasProvided - (gasProvided / process.MaxGasFeeHigherFactorAccepted) + maxGasToRemain := gasProvided - (gasProvided / economicsHandler.MaxGasHigherFactorAccepted()) + + isTooMuchGas := isTooMuchGasProvided(gasProvided, gasProvided, economicsHandler) + assert.False(t, isTooMuchGas) + + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain-1, economicsHandler) + assert.False(t, isTooMuchGas) + + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain, economicsHandler) + assert.False(t, isTooMuchGas) + + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain+1, economicsHandler) + assert.True(t, isTooMuchGas) - isTooMuchGas := isTooMuchGasProvided(gasProvided, gasProvided) + economicsHandler.MaxGasHigherFactorAcceptedCalled = func() uint64 { + return 2 + } + + maxGasToRemain = gasProvided - (gasProvided / economicsHandler.MaxGasHigherFactorAccepted()) + + isTooMuchGas = isTooMuchGasProvided(gasProvided, gasProvided, economicsHandler) assert.False(t, isTooMuchGas) - isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain-1) + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain-1, economicsHandler) assert.False(t, isTooMuchGas) - isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain) + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain, economicsHandler) assert.False(t, isTooMuchGas) - isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain+1) + isTooMuchGas = isTooMuchGasProvided(gasProvided, maxGasToRemain+1, economicsHandler) assert.True(t, isTooMuchGas) + } func TestSCProcessor_createSCRWhenError(t *testing.T) { @@ -4177,6 +4198,7 @@ func createRealEconomicsDataArgs() *economics.ArgsNewEconomicsData { MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, GasPerDataByte: "1500", diff --git a/testscommon/components/configs.go b/testscommon/components/configs.go index f86a5ae59cc..12598af042c 100644 --- a/testscommon/components/configs.go +++ b/testscommon/components/configs.go @@ -249,6 +249,7 @@ func CreateDummyEconomicsConfig() config.EconomicsConfig { MaxGasLimitPerTx: "1500000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "1000000000", diff --git a/testscommon/economicsConfig.go b/testscommon/economicsConfig.go index 59ec0088240..aae732d7446 100644 --- a/testscommon/economicsConfig.go +++ b/testscommon/economicsConfig.go @@ -39,6 +39,7 @@ func GetEconomicsConfig() config.EconomicsConfig { MaxGasLimitPerTx: "600000000", MinGasLimit: "50000", ExtraGasLimitGuardedTx: "50000", + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: "1000000000", diff --git a/testscommon/economicsmocks/economicsDataHandlerStub.go b/testscommon/economicsmocks/economicsDataHandlerStub.go index a69206b12e6..b371d101522 100644 --- a/testscommon/economicsmocks/economicsDataHandlerStub.go +++ b/testscommon/economicsmocks/economicsDataHandlerStub.go @@ -30,6 +30,7 @@ type EconomicsHandlerStub struct { MinGasLimitCalled func() uint64 ExtraGasLimitGuardedTxCalled func() uint64 MaxGasPriceSetGuardianCalled func() uint64 + MaxGasHigherFactorAcceptedCalled func() uint64 GenesisTotalSupplyCalled func() *big.Int ComputeFeeForProcessingCalled func(tx data.TransactionWithFeeHandler, gasToUse uint64) *big.Int RewardsTopUpGradientPointCalled func() *big.Int @@ -212,6 +213,14 @@ func (e *EconomicsHandlerStub) MaxGasLimitPerMiniBlockForSafeCrossShard() uint64 return 1000000 } +// MaxGasHigherFactorAccepted - +func (e *EconomicsHandlerStub) MaxGasHigherFactorAccepted() uint64 { + if e.MaxGasHigherFactorAcceptedCalled != nil { + return e.MaxGasHigherFactorAcceptedCalled() + } + return 10 +} + // MaxGasLimitPerTx - func (e *EconomicsHandlerStub) MaxGasLimitPerTx() uint64 { if e.MaxGasLimitPerTxCalled != nil { diff --git a/testscommon/economicsmocks/economicsHandlerMock.go b/testscommon/economicsmocks/economicsHandlerMock.go index 304e86e37d2..a0f4d841808 100644 --- a/testscommon/economicsmocks/economicsHandlerMock.go +++ b/testscommon/economicsmocks/economicsHandlerMock.go @@ -31,6 +31,7 @@ type EconomicsHandlerMock struct { DeveloperPercentageCalled func() float64 MinGasPriceCalled func() uint64 GasPerDataByteCalled func() uint64 + MaxGasHigherFactorAcceptedCalled func() uint64 RewardsTopUpGradientPointCalled func() *big.Int RewardsTopUpFactorCalled func() float64 ComputeFeeForProcessingCalled func(tx data.TransactionWithFeeHandler, gasToUse uint64) *big.Int @@ -348,6 +349,14 @@ func (ehm *EconomicsHandlerMock) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.Trans return nil } +// MaxGasHigherFactorAccepted - +func (ehm *EconomicsHandlerMock) MaxGasHigherFactorAccepted() uint64 { + if ehm.MaxGasHigherFactorAcceptedCalled != nil { + return ehm.MaxGasHigherFactorAcceptedCalled() + } + return 10 +} + // IsInterfaceNil returns true if there is no value under the interface func (ehm *EconomicsHandlerMock) IsInterfaceNil() bool { return ehm == nil diff --git a/testscommon/stakingcommon/stakingCommon.go b/testscommon/stakingcommon/stakingCommon.go index 1af9b441b9c..bdad4a47bde 100644 --- a/testscommon/stakingcommon/stakingCommon.go +++ b/testscommon/stakingcommon/stakingCommon.go @@ -266,6 +266,7 @@ func CreateEconomicsData() process.EconomicsDataHandler { MaxGasLimitPerTx: maxGasLimitPerBlock, MinGasLimit: minGasLimit, ExtraGasLimitGuardedTx: maxGasLimitPerBlock, + MaxGasHigherFactorAccepted: "10", }, }, MinGasPrice: minGasPrice,