Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Merge branch 'rc/v1.6.0' into feat/pubkey_conv #5066

Merged
merged 2 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[![](https://img.shields.io/badge/project-MultiversX%20Mainnet-blue.svg)](https://explorer.multiversx.com/)
[![Go Report Card](https://goreportcard.com/badge/github.com/multiversx/mx-chain-go)](https://goreportcard.com/report/github.com/multiversx/mx-chain-go)
[![codecov](https://codecov.io/gh/multiversx/mx-chain-go/branch/master/graph/badge.svg?token=MYS5EDASOJ)](https://codecov.io/gh/multiversx/mx-chain-go)
[![Contributors](https://img.shields.io/github/contributors/multiversx/mx-chain-go)](https://github.com/multiversx/mx-chain-go/graphs/contributors)

# mx-chain-go

Expand Down
9 changes: 6 additions & 3 deletions cmd/keygenerator/converter/pidPubkeyConverter.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@ import (
crypto "github.com/multiversx/mx-chain-crypto-go"
"github.com/multiversx/mx-chain-crypto-go/signing"
"github.com/multiversx/mx-chain-crypto-go/signing/secp256k1"
"github.com/multiversx/mx-chain-go/p2p"
"github.com/multiversx/mx-chain-go/p2p/factory"
logger "github.com/multiversx/mx-chain-logger-go"
)

var log = logger.GetOrCreate("cmd/keygenerator/converter")

type pidPubkeyConverter struct {
keyGen crypto.KeyGenerator
keyGen crypto.KeyGenerator
p2PKeyConverter p2p.P2PKeyConverter
}

// NewPidPubkeyConverter creates a new instance of a public key converter that can handle conversions involving core.PeerID string representations
func NewPidPubkeyConverter() *pidPubkeyConverter {
return &pidPubkeyConverter{
keyGen: signing.NewKeyGenerator(secp256k1.NewSecp256k1()),
keyGen: signing.NewKeyGenerator(secp256k1.NewSecp256k1()),
p2PKeyConverter: factory.NewP2PKeyConverter(),
}
}

Expand Down Expand Up @@ -51,7 +54,7 @@ func (converter *pidPubkeyConverter) encode(pkBytes []byte) (string, error) {
return "", err
}

pid, err := factory.ConvertPublicKeyToPeerID(pk)
pid, err := converter.p2PKeyConverter.ConvertPublicKeyToPeerID(pk)
if err != nil {
return "", err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/node/config/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,6 @@
[StateTriesConfig]
CheckpointRoundsModulus = 100
CheckpointsEnabled = false
SnapshotsEnabled = true
AccountsStatePruningEnabled = false
PeerStatePruningEnabled = true
MaxStateTrieLevelInMemory = 5
Expand Down Expand Up @@ -933,6 +932,7 @@
HardforkTimeBetweenSendsInSec = 60 # 1min # time between hardfork messages
TimeBetweenConnectionsMetricsUpdateInSec = 30 # 30sec # time between consecutive connections metrics updates
TimeToReadDirectConnectionsInSec = 15 # 15sec # time between consecutive peer shard mapper updates with direct connections
PeerAuthenticationTimeBetweenChecksInSec = 6 # 6sec
[HeartbeatV2.HeartbeatPool]
Name = "HeartbeatPool"
Capacity = 50000
Expand Down
3 changes: 3 additions & 0 deletions cmd/node/config/enableEpochs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@
# AlwaysSaveTokenMetaDataEnableEpoch represents the epoch when the token metadata is always saved
AlwaysSaveTokenMetaDataEnableEpoch = 1

# RuntimeCodeSizeFixEnableEpoch represents the epoch when the code size fix in the VM is enabled
RuntimeCodeSizeFixEnableEpoch = 2

# BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers
BLSMultiSignerEnableEpoch = [
{ EnableEpoch = 0, Type = "no-KOSK"},
Expand Down
19 changes: 17 additions & 2 deletions cmd/node/config/prefs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
# if "disabled" is provided then the node will start in the corresponding shard for its public key or 0 otherwise
DestinationShardAsObserver = "disabled"

# NodeDisplayName represents the friendly name a user can pick for his node in the status monitor
# NodeDisplayName represents the friendly name a user can pick for his node in the status monitor when the node does not run in multikey mode
# In multikey mode, all bls keys not mentioned in NamedIdentity section will use this one as default
NodeDisplayName = ""

# Identity represents the keybase's identity
# Identity represents the keybase's identity when the node does not run in multikey mode
# In multikey mode, all bls keys not mentioned in NamedIdentity section will use this one as default
Identity = ""

# RedundancyLevel represents the level of redundancy used by the node (-1 = disabled, 0 = main instance (default),
Expand Down Expand Up @@ -47,3 +49,16 @@
# { File = "config.toml", Path = "MiniBlocksStorage.Cache.Name", Value = "MiniBlocksStorage" },
# { File = "external.toml", Path = "ElasticSearchConnector.Enabled", Value = "true" }
#]

# NamedIdentity represents an identity that runs nodes on the multikey
# There can be multiple identities set on the same node, each one of them having different bls keys, just by duplicating the NamedIdentity
[[NamedIdentity]]
# Identity represents the keybase identity for the current NamedIdentity
Identity = ""
# NodeName represents the name that will be given to the names of the current identity
NodeName = ""
# BLSKeys represents the BLS keys assigned to the current NamedIdentity
BLSKeys = [
"",
""
]
21 changes: 19 additions & 2 deletions cmd/node/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ var (
Usage: "The `filepath` for the PEM file which contains the secret keys for the validator key.",
Value: "./config/validatorKey.pem",
}
// allValidatorKeysPemFile defines a flag for the path to the file that hold all validator keys used in block signing
// managed by the current node
allValidatorKeysPemFile = cli.StringFlag{
Name: "all-validator-keys-pem-file",
Usage: "The `filepath` for the PEM file which contains all the secret keys managed by the current node.",
Value: "./config/allValidatorsKeys.pem",
}

// logLevel defines the logger level
logLevel = cli.StringFlag{
Expand Down Expand Up @@ -365,6 +372,12 @@ var (
Value: "./config/p2pKey.pem",
}

// snapshotsEnabled is used to enable snapshots, if it is not set it defaults to true, it will be set to false if it is set specifically
snapshotsEnabled = cli.BoolTFlag{
Name: "snapshots-enabled",
Usage: "Boolean option for enabling state snapshots. If it is not set it defaults to true, it will be set to false if it is set specifically as --snapshots-enabled=false",
}

// operationMode defines the flag for specifying how configs should be altered depending on the node's intent
operationMode = cli.StringFlag{
Name: "operation-mode",
Expand All @@ -391,6 +404,7 @@ func getFlags() []cli.Flag {
gasScheduleConfigurationDirectory,
validatorKeyIndex,
validatorKeyPemFile,
allValidatorKeysPemFile,
port,
profileMode,
useHealthService,
Expand Down Expand Up @@ -425,6 +439,7 @@ func getFlags() []cli.Flag {
serializeSnapshots,
noKey,
p2pKeyPemFile,
snapshotsEnabled,
dbDirectory,
logsDirectory,
operationMode,
Expand Down Expand Up @@ -455,6 +470,7 @@ func getFlagsConfig(ctx *cli.Context, log logger.Logger) *config.ContextFlagsCon
flagsConfig.DisableConsensusWatchdog = ctx.GlobalBool(disableConsensusWatchdog.Name)
flagsConfig.SerializeSnapshots = ctx.GlobalBool(serializeSnapshots.Name)
flagsConfig.NoKeyProvided = ctx.GlobalBool(noKey.Name)
flagsConfig.SnapshotsEnabled = ctx.GlobalBool(snapshotsEnabled.Name)
flagsConfig.OperationMode = ctx.GlobalString(operationMode.Name)

return flagsConfig
Expand All @@ -467,6 +483,7 @@ func applyFlags(ctx *cli.Context, cfgs *config.Configs, flagsConfig *config.Cont
cfgs.ConfigurationPathsHolder.GasScheduleDirectoryName = ctx.GlobalString(gasScheduleConfigurationDirectory.Name)
cfgs.ConfigurationPathsHolder.SmartContracts = ctx.GlobalString(smartContractsFile.Name)
cfgs.ConfigurationPathsHolder.ValidatorKey = ctx.GlobalString(validatorKeyPemFile.Name)
cfgs.ConfigurationPathsHolder.AllValidatorKeys = ctx.GlobalString(allValidatorKeysPemFile.Name)
cfgs.ConfigurationPathsHolder.P2pKey = ctx.GlobalString(p2pKeyPemFile.Name)

if ctx.IsSet(startInEpoch.Name) {
Expand Down Expand Up @@ -627,12 +644,12 @@ func processDbLookupExtensionMode(log logger.Logger, configs *config.Configs) {

func processLiteObserverMode(log logger.Logger, configs *config.Configs) {
configs.GeneralConfig.StoragePruning.ObserverCleanOldEpochsData = true
configs.GeneralConfig.StateTriesConfig.SnapshotsEnabled = false
configs.FlagsConfig.SnapshotsEnabled = false
configs.GeneralConfig.StateTriesConfig.AccountsStatePruningEnabled = true

log.Warn("the node is in snapshotless observer mode! Will auto-set some config values",
"StoragePruning.ObserverCleanOldEpochsData", configs.GeneralConfig.StoragePruning.ObserverCleanOldEpochsData,
"StateTriesConfig.SnapshotsEnabled", configs.GeneralConfig.StateTriesConfig.SnapshotsEnabled,
"FlagsConfig.SnapshotsEnabled", configs.FlagsConfig.SnapshotsEnabled,
"StateTriesConfig.AccountsStatePruningEnabled", configs.GeneralConfig.StateTriesConfig.AccountsStatePruningEnabled,
)
}
Expand Down
8 changes: 5 additions & 3 deletions cmd/node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ func main() {
app.Name = "MultiversX Node CLI App"
machineID := core.GetAnonymizedMachineID(app.Name)

app.Version = fmt.Sprintf("%s/%s/%s-%s/%s", appVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH, machineID)
baseVersion := fmt.Sprintf("%s/%s/%s-%s", appVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
app.Version = fmt.Sprintf("%s/%s", baseVersion, machineID)
app.Usage = "This is the entry point for starting a new MultiversX node - the app will start after the genesis timestamp"
app.Flags = getFlags()
app.Authors = []cli.Author{
Expand All @@ -74,7 +75,7 @@ func main() {
}

app.Action = func(c *cli.Context) error {
return startNodeRunner(c, log, app.Version)
return startNodeRunner(c, log, baseVersion, app.Version)
}

err := app.Run(os.Args)
Expand All @@ -84,7 +85,7 @@ func main() {
}
}

func startNodeRunner(c *cli.Context, log logger.Logger, version string) error {
func startNodeRunner(c *cli.Context, log logger.Logger, baseVersion string, version string) error {
flagsConfig := getFlagsConfig(c, log)

fileLogging, errLogger := attachFileLogger(log, flagsConfig)
Expand Down Expand Up @@ -125,6 +126,7 @@ func startNodeRunner(c *cli.Context, log logger.Logger, version string) error {
log.Debug("initialized memory ballast object", "size", core.ConvertBytes(uint64(len(memoryBallastObject))))
}

cfgs.FlagsConfig.BaseVersion = baseVersion
cfgs.FlagsConfig.Version = version

nodeRunner, errRunner := node.NewNodeRunner(cfgs)
Expand Down
2 changes: 1 addition & 1 deletion common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ const MetricRedundancyIsMainActive = "erd_redundancy_is_main_active"
// MetricValueNA represents the value to be used when a metric is not available/applicable
const MetricValueNA = "N/A"

//MetricProcessedProposedBlock is the metric that specify the percent of the block subround used for header and body
// MetricProcessedProposedBlock is the metric that specify the percent of the block subround used for header and body
// processing (0 meaning that the block was processed in no-time and 100 meaning that the block processing used all the
// subround spare duration)
const MetricProcessedProposedBlock = "erd_consensus_processed_proposed_block"
Expand Down
1 change: 1 addition & 0 deletions common/enablers/enableEpochsHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func (handler *enableEpochsHandler) EpochConfirmed(epoch uint32, _ uint64) {
handler.setFlagValue(epoch >= handler.enableEpochsConfig.FixAsyncCallBackArgsListEnableEpoch, handler.fixAsyncCallBackArgsList, "fixAsyncCallBackArgsList")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.FixOldTokenLiquidityEnableEpoch, handler.fixOldTokenLiquidity, "fixOldTokenLiquidity")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.RuntimeMemStoreLimitEnableEpoch, handler.runtimeMemStoreLimitFlag, "runtimeMemStoreLimitFlag")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.RuntimeCodeSizeFixEnableEpoch, handler.runtimeCodeSizeFixFlag, "runtimeCodeSizeFixFlag")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.MaxBlockchainHookCountersEnableEpoch, handler.maxBlockchainHookCountersFlag, "maxBlockchainHookCountersFlag")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.WipeSingleNFTLiquidityDecreaseEnableEpoch, handler.wipeSingleNFTLiquidityDecreaseFlag, "wipeSingleNFTLiquidityDecreaseFlag")
handler.setFlagValue(epoch >= handler.enableEpochsConfig.AlwaysSaveTokenMetaDataEnableEpoch, handler.alwaysSaveTokenMetaDataFlag, "alwaysSaveTokenMetaDataFlag")
Expand Down
8 changes: 6 additions & 2 deletions common/enablers/enableEpochsHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func createEnableEpochsConfig() config.EnableEpochs {
MaxBlockchainHookCountersEnableEpoch: 74,
WipeSingleNFTLiquidityDecreaseEnableEpoch: 75,
AlwaysSaveTokenMetaDataEnableEpoch: 76,
RuntimeCodeSizeFixEnableEpoch: 77,
}
}

Expand Down Expand Up @@ -128,7 +129,7 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
handler, _ := NewEnableEpochsHandler(cfg, &epochNotifier.EpochNotifierStub{})
require.False(t, check.IfNil(handler))

handler.EpochConfirmed(76, 0)
handler.EpochConfirmed(77, 0)

assert.Equal(t, cfg.BlockGasAndFeesReCheckEnableEpoch, handler.BlockGasAndFeesReCheckEnableEpoch())
assert.True(t, handler.IsSCDeployFlagEnabled())
Expand Down Expand Up @@ -211,11 +212,12 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.True(t, handler.IsRuntimeMemStoreLimitEnabled())
assert.True(t, handler.IsMaxBlockchainHookCountersFlagEnabled())
assert.True(t, handler.IsAlwaysSaveTokenMetaDataEnabled())
assert.True(t, handler.IsRuntimeCodeSizeFixEnabled())
})
t.Run("flags with == condition should be set, along with all >=", func(t *testing.T) {
t.Parallel()

epoch := uint32(77)
epoch := uint32(78)
cfg := createEnableEpochsConfig()
cfg.StakingV2EnableEpoch = epoch
cfg.ESDTEnableEpoch = epoch
Expand Down Expand Up @@ -310,6 +312,7 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.True(t, handler.IsMaxBlockchainHookCountersFlagEnabled())
assert.True(t, handler.IsWipeSingleNFTLiquidityDecreaseEnabled())
assert.True(t, handler.IsAlwaysSaveTokenMetaDataEnabled())
assert.True(t, handler.IsRuntimeCodeSizeFixEnabled())
})
t.Run("flags with < should be set", func(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -404,5 +407,6 @@ func TestNewEnableEpochsHandler_EpochConfirmed(t *testing.T) {
assert.False(t, handler.IsMaxBlockchainHookCountersFlagEnabled())
assert.False(t, handler.IsWipeSingleNFTLiquidityDecreaseEnabled())
assert.False(t, handler.IsAlwaysSaveTokenMetaDataEnabled())
assert.False(t, handler.IsRuntimeCodeSizeFixEnabled())
})
}
7 changes: 7 additions & 0 deletions common/enablers/epochFlags.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ type epochFlagsHolder struct {
fixAsyncCallBackArgsList *atomic.Flag
fixOldTokenLiquidity *atomic.Flag
runtimeMemStoreLimitFlag *atomic.Flag
runtimeCodeSizeFixFlag *atomic.Flag
maxBlockchainHookCountersFlag *atomic.Flag
wipeSingleNFTLiquidityDecreaseFlag *atomic.Flag
alwaysSaveTokenMetaDataFlag *atomic.Flag
Expand Down Expand Up @@ -174,6 +175,7 @@ func newEpochFlagsHolder() *epochFlagsHolder {
fixAsyncCallBackArgsList: &atomic.Flag{},
fixOldTokenLiquidity: &atomic.Flag{},
runtimeMemStoreLimitFlag: &atomic.Flag{},
runtimeCodeSizeFixFlag: &atomic.Flag{},
maxBlockchainHookCountersFlag: &atomic.Flag{},
wipeSingleNFTLiquidityDecreaseFlag: &atomic.Flag{},
alwaysSaveTokenMetaDataFlag: &atomic.Flag{},
Expand Down Expand Up @@ -638,6 +640,11 @@ func (holder *epochFlagsHolder) IsRuntimeMemStoreLimitEnabled() bool {
return holder.runtimeMemStoreLimitFlag.IsSet()
}

// IsRuntimeCodeSizeFixEnabled returns true if runtimeCodeSizeFixFlag is enabled
func (holder *epochFlagsHolder) IsRuntimeCodeSizeFixEnabled() bool {
return holder.runtimeCodeSizeFixFlag.IsSet()
}

// IsMaxBlockchainHookCountersFlagEnabled returns true if maxBlockchainHookCountersFlagEnabled is enabled
func (holder *epochFlagsHolder) IsMaxBlockchainHookCountersFlagEnabled() bool {
return holder.maxBlockchainHookCountersFlag.IsSet()
Expand Down
33 changes: 23 additions & 10 deletions common/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ import (
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/data"
"github.com/multiversx/mx-chain-core-go/data/block"
crypto "github.com/multiversx/mx-chain-crypto-go"
"github.com/multiversx/mx-chain-go/trie/statistics"
)

// NumNodesDTO represents the DTO structure that will hold the number of nodes split by category and other
// trie structure relevant data such as maximum number of trie levels including the roothash node and all leaves
type NumNodesDTO struct {
Leaves int
Extensions int
Branches int
MaxLevel int
}

// TrieIteratorChannels defines the channels that are being used when iterating the trie nodes
type TrieIteratorChannels struct {
LeavesChan chan core.KeyValueHolder
Expand All @@ -40,7 +32,6 @@ type Trie interface {
GetOldRoot() []byte
GetSerializedNodes([]byte, uint64) ([][]byte, uint64, error)
GetSerializedNode([]byte) ([]byte, error)
GetNumNodes() NumNodesDTO
GetAllLeavesOnChannel(allLeavesChan *TrieIteratorChannels, ctx context.Context, rootHash []byte, keyBuilder KeyBuilder) error
GetAllHashes() ([][]byte, error)
GetProof(key []byte) ([][]byte, []byte, error)
Expand Down Expand Up @@ -333,9 +324,31 @@ type EnableEpochsHandler interface {
IsFixAsyncCallBackArgsListFlagEnabled() bool
IsFixOldTokenLiquidityEnabled() bool
IsRuntimeMemStoreLimitEnabled() bool
IsRuntimeCodeSizeFixEnabled() bool
IsMaxBlockchainHookCountersFlagEnabled() bool
IsWipeSingleNFTLiquidityDecreaseEnabled() bool
IsAlwaysSaveTokenMetaDataEnabled() bool

IsInterfaceNil() bool
}

// ManagedPeersHolder defines the operations of an entity that holds managed identities for a node
type ManagedPeersHolder interface {
AddManagedPeer(privateKeyBytes []byte) error
GetPrivateKey(pkBytes []byte) (crypto.PrivateKey, error)
GetP2PIdentity(pkBytes []byte) ([]byte, core.PeerID, error)
GetMachineID(pkBytes []byte) (string, error)
GetNameAndIdentity(pkBytes []byte) (string, string, error)
IncrementRoundsWithoutReceivedMessages(pkBytes []byte)
ResetRoundsWithoutReceivedMessages(pkBytes []byte)
GetManagedKeysByCurrentNode() map[string]crypto.PrivateKey
IsKeyManagedByCurrentNode(pkBytes []byte) bool
IsKeyRegistered(pkBytes []byte) bool
IsPidManagedByCurrentNode(pid core.PeerID) bool
IsKeyValidator(pkBytes []byte) bool
SetValidatorState(pkBytes []byte, state bool)
GetNextPeerAuthenticationTime(pkBytes []byte) (time.Time, error)
SetNextPeerAuthenticationTime(pkBytes []byte, nextTime time.Time)
IsMultiKeyMode() bool
IsInterfaceNil() bool
}
3 changes: 2 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ type HeartbeatV2Config struct {
HardforkTimeBetweenSendsInSec int64
TimeBetweenConnectionsMetricsUpdateInSec int64
TimeToReadDirectConnectionsInSec int64
PeerAuthenticationTimeBetweenChecksInSec int64
}

// Config will hold the entire application configuration parameters
Expand Down Expand Up @@ -290,7 +291,6 @@ type FacadeConfig struct {
type StateTriesConfig struct {
CheckpointRoundsModulus uint
CheckpointsEnabled bool
SnapshotsEnabled bool
AccountsStatePruningEnabled bool
PeerStatePruningEnabled bool
MaxStateTrieLevelInMemory uint
Expand Down Expand Up @@ -587,6 +587,7 @@ type ConfigurationPathsHolder struct {
Genesis string
SmartContracts string
ValidatorKey string
AllValidatorKeys string
Epoch string
RoundActivation string
P2pKey string
Expand Down
2 changes: 2 additions & 0 deletions config/contextFlagsConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ type ContextFlagsConfig struct {
UseLogView bool
ValidatorKeyIndex int
EnableRestAPIServerDebugMode bool
BaseVersion string
Version string
ForceStartFromNetwork bool
DisableConsensusWatchdog bool
SerializeSnapshots bool
NoKeyProvided bool
SnapshotsEnabled bool
OperationMode string
}

Expand Down
Loading