-
Notifications
You must be signed in to change notification settings - Fork 36
Localnet: add support for Supernova #560
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
Changes from all commits
bd237cd
049cb40
71a58eb
92cbcf8
a69bf61
1cb258c
b765d63
a57fa49
cfb3a86
22f5b6f
54511a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,3 +6,8 @@ | |
| FILE_MODE_EXECUTABLE = ( | ||
| stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH | ||
| ) | ||
|
|
||
| # See https://github.com/multiversx/mx-chain-go/blob/master/cmd/node/config/config.toml. | ||
| ROUNDS_PER_EPOCH_TO_MIN_ROUNDS_BETWEEN_EPOCHS_RATIO = 4 | ||
| # See https://github.com/multiversx/mx-chain-go/blob/master/cmd/node/config/enableRounds.toml. | ||
| NUM_ROUNDS_BETWEEN_SUPERNOVA_ACTIVATION_EPOCH_AND_ACTIVATION_ROUND = 20 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,18 @@ | ||
| from typing import Any, Dict | ||
|
|
||
| from multiversx_sdk_cli.localnet.config_root import ConfigRoot | ||
| from multiversx_sdk_cli.localnet.constants import ( | ||
| NUM_ROUNDS_BETWEEN_SUPERNOVA_ACTIVATION_EPOCH_AND_ACTIVATION_ROUND, | ||
| ROUNDS_PER_EPOCH_TO_MIN_ROUNDS_BETWEEN_EPOCHS_RATIO, | ||
| ) | ||
| from multiversx_sdk_cli.localnet.nodes_setup_json import CHAIN_ID | ||
|
|
||
| ConfigDict = Dict[str, Any] | ||
|
|
||
|
|
||
| def patch_config(data: ConfigDict, config: ConfigRoot): | ||
| def patch_config(data: ConfigDict, config: ConfigRoot, enable_epochs_config: ConfigDict): | ||
| supernova_activation_epoch = enable_epochs_config["EnableEpochs"].get("SupernovaEnableEpoch", None) | ||
|
|
||
| data["GeneralSettings"]["ChainID"] = CHAIN_ID | ||
|
|
||
| # "--operation-mode=historical-balances" is not available for nodes, | ||
|
|
@@ -18,33 +24,58 @@ def patch_config(data: ConfigDict, config: ConfigRoot): | |
| data["StoragePruning"]["ObserverCleanOldEpochsData"] = False | ||
| data["StoragePruning"]["AccountsTrieCleanOldEpochsData"] = False | ||
|
|
||
| # Make epochs shorter | ||
| epoch_start_config: ConfigDict = dict() | ||
| epoch_start_config["RoundsPerEpoch"] = config.general.rounds_per_epoch | ||
| epoch_start_config["MinRoundsBetweenEpochs"] = int(config.general.rounds_per_epoch / 4) | ||
| # Some time after the release of Supernova, we should drop this custom (and somewhat cumbersome) logic. | ||
| if supernova_activation_epoch is None: | ||
| # Before Supernova (as software version, not as "era after activation"), | ||
| # we alter epoch duration by adjusting "RoundsPerEpoch" and "MinRoundsBetweenEpochs" in section "EpochStartConfig". | ||
| # In a Supernova-aware node configuration, these entries do not exist anymore (see "ChainParametersByEpoch"). | ||
| epoch_start_config: ConfigDict = dict() | ||
| epoch_start_config["RoundsPerEpoch"] = config.general.rounds_per_epoch | ||
| epoch_start_config["MinRoundsBetweenEpochs"] = int( | ||
| config.general.rounds_per_epoch / ROUNDS_PER_EPOCH_TO_MIN_ROUNDS_BETWEEN_EPOCHS_RATIO | ||
| ) | ||
|
|
||
| data["EpochStartConfig"].update(epoch_start_config) | ||
|
|
||
| data["EpochStartConfig"].update(epoch_start_config) | ||
| data["WebServerAntiflood"]["VmQueryDelayAfterStartInSec"] = 30 | ||
|
|
||
| # Always use the latest VM | ||
| data["VirtualMachine"]["Execution"]["WasmVMVersions"] = [{"StartEpoch": 0, "Version": "*"}] | ||
| data["VirtualMachine"]["Querying"]["WasmVMVersions"] = [{"StartEpoch": 0, "Version": "*"}] | ||
|
|
||
| # Adjust "ChainParametersByEpoch" (for Andromeda) | ||
| # Adjust "ChainParametersByEpoch" | ||
| chain_parameters_by_epoch = data["GeneralSettings"].get("ChainParametersByEpoch", []) | ||
|
|
||
| if chain_parameters_by_epoch: | ||
| # For convenience, keep a single entry ... | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tricky. Changed to use the whole collection of |
||
| chain_parameters_by_epoch.clear() | ||
| chain_parameters_by_epoch.append({}) | ||
| for item in chain_parameters_by_epoch: | ||
| enable_epoch = item["EnableEpoch"] | ||
|
|
||
| is_supernova_enabled = supernova_activation_epoch is not None and enable_epoch >= supernova_activation_epoch | ||
| if is_supernova_enabled: | ||
| item["RoundDuration"] = config.general.round_duration_milliseconds_in_supernova | ||
| item["RoundsPerEpoch"] = config.general.rounds_per_epoch_in_supernova | ||
|
Comment on lines
+54
to
+55
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once Supernova is active, we use the new localnet configuration entries: |
||
| item["MinRoundsBetweenEpochs"] = int( | ||
| config.general.rounds_per_epoch_in_supernova / ROUNDS_PER_EPOCH_TO_MIN_ROUNDS_BETWEEN_EPOCHS_RATIO | ||
| ) | ||
| else: | ||
| item["RoundDuration"] = config.general.round_duration_milliseconds | ||
| item["RoundsPerEpoch"] = config.general.rounds_per_epoch | ||
| item["MinRoundsBetweenEpochs"] = int( | ||
| config.general.rounds_per_epoch / ROUNDS_PER_EPOCH_TO_MIN_ROUNDS_BETWEEN_EPOCHS_RATIO | ||
| ) | ||
|
|
||
| item["ShardConsensusGroupSize"] = config.shards.consensus_size | ||
| item["ShardMinNumNodes"] = config.shards.num_validators_per_shard | ||
| item["MetachainConsensusGroupSize"] = config.metashard.consensus_size | ||
| item["MetachainMinNumNodes"] = config.metashard.num_validators | ||
|
|
||
| # ... and set the activation epoch to 0 | ||
| chain_parameters_by_epoch[0]["EnableEpoch"] = 0 | ||
| chain_parameters_by_epoch[0]["RoundDuration"] = config.general.round_duration_milliseconds | ||
| chain_parameters_by_epoch[0]["ShardConsensusGroupSize"] = config.shards.consensus_size | ||
| chain_parameters_by_epoch[0]["ShardMinNumNodes"] = config.shards.num_validators_per_shard | ||
| chain_parameters_by_epoch[0]["MetachainConsensusGroupSize"] = config.metashard.consensus_size | ||
| chain_parameters_by_epoch[0]["MetachainMinNumNodes"] = config.metashard.num_validators | ||
| # Adjust "Versions" (of blocks) | ||
| versions_by_epoch = data["Versions"].get("VersionsByEpochs", []) | ||
|
|
||
| for item in versions_by_epoch: | ||
| enable_epoch = item["StartEpoch"] | ||
|
|
||
| if enable_epoch == supernova_activation_epoch: | ||
popenta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| item["StartRound"] = _compute_supernova_activation_round(config, supernova_activation_epoch) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
|
|
||
| def patch_api(data: ConfigDict, config: ConfigRoot): | ||
|
|
@@ -55,10 +86,6 @@ def patch_api(data: ConfigDict, config: ConfigRoot): | |
|
|
||
| def patch_enable_epochs(data: ConfigDict, config: ConfigRoot): | ||
| enable_epochs = data["EnableEpochs"] | ||
| enable_epochs["SCDeployEnableEpoch"] = 0 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| enable_epochs["BuiltInFunctionsEnableEpoch"] = 0 | ||
| enable_epochs["RelayedTransactionsEnableEpoch"] = 0 | ||
| enable_epochs["PenalizedTooMuchGasEnableEpoch"] = 0 | ||
| enable_epochs["AheadOfTimeGasUsageEnableEpoch"] = 0 | ||
| enable_epochs["GasPriceModifierEnableEpoch"] = 0 | ||
| enable_epochs["RepairCallbackEnableEpoch"] = 0 | ||
|
|
@@ -69,15 +96,34 @@ def patch_enable_epochs(data: ConfigDict, config: ConfigRoot): | |
| enable_epochs["ESDTMultiTransferEnableEpoch"] = 0 | ||
| enable_epochs["GlobalMintBurnDisableEpoch"] = 0 | ||
| enable_epochs["ESDTTransferRoleEnableEpoch"] = 0 | ||
| enable_epochs["BuiltInFunctionOnMetaEnableEpoch"] = 0 | ||
| enable_epochs["MultiESDTTransferFixOnCallBackOnEnableEpoch"] = 0 | ||
| enable_epochs["ESDTNFTCreateOnMultiShard"] = 0 | ||
| enable_epochs["MetaESDTSetEnableEpoch"] = 0 | ||
| enable_epochs["DelegationManagerEnableEpoch"] = 0 | ||
|
|
||
| # Adjust "MaxNumNodes": | ||
| max_nodes_change_enable_epoch = enable_epochs["MaxNodesChangeEnableEpoch"] | ||
| last_entry = max_nodes_change_enable_epoch[-1] | ||
| penultimate_entry = max_nodes_change_enable_epoch[-2] | ||
| last_entry["MaxNumNodes"] = ( | ||
| penultimate_entry["MaxNumNodes"] - (config.shards.num_shards + 1) * penultimate_entry["NodesToShufflePerShard"] | ||
| ) | ||
|
|
||
|
|
||
| def patch_enable_rounds(data: ConfigDict, config: ConfigRoot, enable_epochs_config: ConfigDict): | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| supernova_activation_epoch = enable_epochs_config["EnableEpochs"].get("SupernovaEnableEpoch", None) | ||
|
|
||
| activations = data["RoundActivations"] | ||
| supernova_entry = activations.get("SupernovaEnableRound") | ||
|
|
||
| if supernova_entry and supernova_activation_epoch is not None: | ||
| supernova_computed_activation_round = _compute_supernova_activation_round(config, supernova_activation_epoch) | ||
| supernova_entry["Round"] = str(supernova_computed_activation_round) | ||
|
|
||
|
|
||
| def _compute_supernova_activation_round(config: ConfigRoot, supernova_activation_epoch: int) -> int: | ||
| # Epochs are zero-indexed. | ||
popenta marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return ( | ||
| config.general.rounds_per_epoch * supernova_activation_epoch | ||
| + NUM_ROUNDS_BETWEEN_SUPERNOVA_ACTIVATION_EPOCH_AND_ACTIVATION_ROUND | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,14 +26,5 @@ def build(config: ConfigRoot) -> Any: | |
|
|
||
| return { | ||
| "startTime": config.genesis_time(), | ||
| "roundDuration": config.general.round_duration_milliseconds, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dropped some time ago. https://github.com/multiversx/mx-chain-go/blob/master/cmd/node/config/nodesSetup.json |
||
| "consensusGroupSize": config.shards.consensus_size, | ||
| "minNodesPerShard": config.shards.consensus_size, | ||
| "metaChainConsensusGroupSize": config.metashard.consensus_size, | ||
| "metaChainMinNodes": config.metashard.num_validators, | ||
| "hysteresis": 0, | ||
| "adaptivity": False, | ||
| "chainID": CHAIN_ID, | ||
| "minTransactionVersion": 1, | ||
| "initialNodes": initial_nodes, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -101,24 +101,28 @@ def copy_validator_keys(config: ConfigRoot): | |
| def patch_node_config(config: ConfigRoot): | ||
| for node_config in config.all_nodes_config_folders(): | ||
| node_config_file = node_config / "config.toml" | ||
| data = utils.read_toml_file(node_config_file) | ||
| node_config_toml.patch_config(data, config) | ||
| utils.write_toml_file(node_config_file, data) | ||
|
|
||
| api_config_file = node_config / "api.toml" | ||
| data = utils.read_toml_file(api_config_file) | ||
| node_config_toml.patch_api(data, config) | ||
| utils.write_toml_file(api_config_file, data) | ||
|
|
||
| enable_epochs_config_file = node_config / "enableEpochs.toml" | ||
| data = utils.read_toml_file(enable_epochs_config_file) | ||
| node_config_toml.patch_enable_epochs(data, config) | ||
| utils.write_toml_file(enable_epochs_config_file, data) | ||
|
|
||
| enable_rounds_config_file = node_config / "enableRounds.toml" | ||
| genesis_smart_contracts_file = node_config / "genesisSmartContracts.json" | ||
| data = utils.read_json_file(genesis_smart_contracts_file) | ||
| genesis_smart_contracts_json.patch(data, config) | ||
| utils.write_json_file(genesis_smart_contracts_file, data) | ||
|
|
||
| node_config_data = utils.read_toml_file(node_config_file) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trivial refactoring, so that we can read & pass |
||
| api_config_data = utils.read_toml_file(api_config_file) | ||
| enable_epochs_config_data = utils.read_toml_file(enable_epochs_config_file) | ||
| enable_rounds_config_data = utils.read_toml_file(enable_rounds_config_file) | ||
| genesis_smart_contracts_data = utils.read_json_file(genesis_smart_contracts_file) | ||
|
|
||
| node_config_toml.patch_config(node_config_data, config, enable_epochs_config_data) | ||
| node_config_toml.patch_api(api_config_data, config) | ||
| node_config_toml.patch_enable_epochs(enable_epochs_config_data, config) | ||
| node_config_toml.patch_enable_rounds(enable_rounds_config_data, config, enable_epochs_config_data) | ||
| genesis_smart_contracts_json.patch(genesis_smart_contracts_data, config) | ||
|
|
||
| utils.write_toml_file(node_config_file, node_config_data) | ||
| utils.write_toml_file(api_config_file, api_config_data) | ||
| utils.write_toml_file(enable_epochs_config_file, enable_epochs_config_data) | ||
| utils.write_toml_file(enable_rounds_config_file, enable_rounds_config_data) | ||
| utils.write_json_file(genesis_smart_contracts_file, genesis_smart_contracts_data) | ||
|
|
||
|
|
||
| def copy_config_to_seednode(config: ConfigRoot): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we have the actual duration of the round (600ms)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question!
I've chosen 2 seconds by default in order to demand less resources from the host machine (development machine).
All good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me. We should at least document that the localnet starts with a roundtime of 2s and we should show people where to change in case they want to run a 600ms round, replicating mainnet config.