517 lines
14 KiB
Go
517 lines
14 KiB
Go
package netmap
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
)
|
|
|
|
// NetworkInfo groups information about the FrostFS network state. Mainly used to
|
|
// describe the current state of the network.
|
|
//
|
|
// NetworkInfo is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.NetworkInfo
|
|
// message. See ReadFromV2 / WriteToV2 methods.
|
|
//
|
|
// Instances can be created using built-in var declaration.
|
|
type NetworkInfo struct {
|
|
m netmap.NetworkInfo
|
|
}
|
|
|
|
// reads NetworkInfo from netmap.NetworkInfo message. If checkFieldPresence is set,
|
|
// returns an error on absence of any protocol-required field. Verifies format of any
|
|
// presented field according to FrostFS API V2 protocol.
|
|
func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) error {
|
|
c := m.GetNetworkConfig()
|
|
if checkFieldPresence && c == nil {
|
|
return errors.New("missing network config")
|
|
}
|
|
|
|
if checkFieldPresence && c.NumberOfParameters() <= 0 {
|
|
return errors.New("missing network parameters")
|
|
}
|
|
|
|
var err error
|
|
mNames := make(map[string]struct{}, c.NumberOfParameters())
|
|
|
|
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
|
|
name := string(prm.GetKey())
|
|
|
|
_, was := mNames[name]
|
|
if was {
|
|
err = fmt.Errorf("duplicated parameter name: %s", name)
|
|
return true
|
|
}
|
|
|
|
mNames[name] = struct{}{}
|
|
|
|
switch name {
|
|
default:
|
|
if len(prm.GetValue()) == 0 {
|
|
err = fmt.Errorf("empty attribute value %s", name)
|
|
return true
|
|
}
|
|
case
|
|
configAuditFee,
|
|
configStoragePrice,
|
|
configContainerFee,
|
|
configNamedContainerFee,
|
|
configEpochDuration,
|
|
configIRCandidateFee,
|
|
configMaxObjSize,
|
|
configMaxECDataCount,
|
|
configMaxECParityCount,
|
|
configWithdrawalFee:
|
|
_, err = decodeConfigValueUint64(prm.GetValue())
|
|
case configHomomorphicHashingDisabled,
|
|
configMaintenanceModeAllowed:
|
|
_, err = decodeConfigValueBool(prm.GetValue())
|
|
}
|
|
|
|
if err != nil {
|
|
err = fmt.Errorf("invalid %s parameter: %w", name, err)
|
|
}
|
|
|
|
return err != nil
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
x.m = m
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadFromV2 reads NetworkInfo from the netmap.NetworkInfo message. Checks if the
|
|
// message conforms to FrostFS API V2 protocol.
|
|
//
|
|
// See also WriteToV2.
|
|
func (x *NetworkInfo) ReadFromV2(m netmap.NetworkInfo) error {
|
|
return x.readFromV2(m, true)
|
|
}
|
|
|
|
// WriteToV2 writes NetworkInfo to the netmap.NetworkInfo message. The message
|
|
// MUST NOT be nil.
|
|
//
|
|
// See also ReadFromV2.
|
|
func (x NetworkInfo) WriteToV2(m *netmap.NetworkInfo) {
|
|
*m = x.m
|
|
}
|
|
|
|
// CurrentEpoch returns epoch set using SetCurrentEpoch.
|
|
//
|
|
// Zero NetworkInfo has zero current epoch.
|
|
func (x NetworkInfo) CurrentEpoch() uint64 {
|
|
return x.m.GetCurrentEpoch()
|
|
}
|
|
|
|
// SetCurrentEpoch sets current epoch of the FrostFS network.
|
|
func (x *NetworkInfo) SetCurrentEpoch(epoch uint64) {
|
|
x.m.SetCurrentEpoch(epoch)
|
|
}
|
|
|
|
// MagicNumber returns magic number set using SetMagicNumber.
|
|
//
|
|
// Zero NetworkInfo has zero magic.
|
|
func (x NetworkInfo) MagicNumber() uint64 {
|
|
return x.m.GetMagicNumber()
|
|
}
|
|
|
|
// SetMagicNumber sets magic number of the FrostFS Sidechain.
|
|
//
|
|
// See also MagicNumber.
|
|
func (x *NetworkInfo) SetMagicNumber(epoch uint64) {
|
|
x.m.SetMagicNumber(epoch)
|
|
}
|
|
|
|
// MsPerBlock returns network parameter set using SetMsPerBlock.
|
|
func (x NetworkInfo) MsPerBlock() int64 {
|
|
return x.m.GetMsPerBlock()
|
|
}
|
|
|
|
// SetMsPerBlock sets MillisecondsPerBlock network parameter of the FrostFS Sidechain.
|
|
//
|
|
// See also MsPerBlock.
|
|
func (x *NetworkInfo) SetMsPerBlock(v int64) {
|
|
x.m.SetMsPerBlock(v)
|
|
}
|
|
|
|
func (x *NetworkInfo) setConfig(name string, val []byte) {
|
|
c := x.m.GetNetworkConfig()
|
|
if c == nil {
|
|
c = new(netmap.NetworkConfig)
|
|
|
|
var prm netmap.NetworkParameter
|
|
prm.SetKey([]byte(name))
|
|
prm.SetValue(val)
|
|
|
|
c.SetParameters(prm)
|
|
|
|
x.m.SetNetworkConfig(c)
|
|
|
|
return
|
|
}
|
|
|
|
found := false
|
|
prms := make([]netmap.NetworkParameter, 0, c.NumberOfParameters())
|
|
|
|
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
|
|
found = bytes.Equal(prm.GetKey(), []byte(name))
|
|
if found {
|
|
prm.SetValue(val)
|
|
} else {
|
|
prms = append(prms, *prm)
|
|
}
|
|
|
|
return found
|
|
})
|
|
|
|
if !found {
|
|
prms = append(prms, netmap.NetworkParameter{})
|
|
prms[len(prms)-1].SetKey([]byte(name))
|
|
prms[len(prms)-1].SetValue(val)
|
|
|
|
c.SetParameters(prms...)
|
|
}
|
|
}
|
|
|
|
func (x NetworkInfo) configValue(name string) (res []byte) {
|
|
x.m.GetNetworkConfig().IterateParameters(func(prm *netmap.NetworkParameter) bool {
|
|
if string(prm.GetKey()) == name {
|
|
res = prm.GetValue()
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
})
|
|
|
|
return
|
|
}
|
|
|
|
// SetRawNetworkParameter sets named FrostFS network parameter whose value is
|
|
// transmitted but not interpreted by the FrostFS API protocol.
|
|
//
|
|
// Argument MUST NOT be mutated, make a copy first.
|
|
//
|
|
// See also RawNetworkParameter, IterateRawNetworkParameters.
|
|
func (x *NetworkInfo) SetRawNetworkParameter(name string, value []byte) {
|
|
x.setConfig(name, value)
|
|
}
|
|
|
|
// RawNetworkParameter reads raw network parameter set using SetRawNetworkParameter
|
|
// by its name. Returns nil if value is missing.
|
|
//
|
|
// Return value MUST NOT be mutated, make a copy first.
|
|
//
|
|
// Zero NetworkInfo has no network parameters.
|
|
func (x *NetworkInfo) RawNetworkParameter(name string) []byte {
|
|
return x.configValue(name)
|
|
}
|
|
|
|
// IterateRawNetworkParameters iterates over all raw networks parameters set
|
|
// using SetRawNetworkParameter and passes them into f.
|
|
//
|
|
// Handler MUST NOT be nil. Handler MUST NOT mutate value parameter.
|
|
//
|
|
// Zero NetworkInfo has no network parameters.
|
|
func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []byte)) {
|
|
c := x.m.GetNetworkConfig()
|
|
|
|
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
|
|
name := string(prm.GetKey())
|
|
switch name {
|
|
default:
|
|
f(name, prm.GetValue())
|
|
case
|
|
configAuditFee,
|
|
configStoragePrice,
|
|
configContainerFee,
|
|
configNamedContainerFee,
|
|
configEpochDuration,
|
|
configIRCandidateFee,
|
|
configMaxObjSize,
|
|
configMaxECDataCount,
|
|
configMaxECParityCount,
|
|
configWithdrawalFee,
|
|
configHomomorphicHashingDisabled,
|
|
configMaintenanceModeAllowed:
|
|
}
|
|
|
|
return false
|
|
})
|
|
}
|
|
|
|
func (x *NetworkInfo) setConfigUint64(name string, num uint64) {
|
|
val := make([]byte, 8)
|
|
binary.LittleEndian.PutUint64(val, num)
|
|
|
|
x.setConfig(name, val)
|
|
}
|
|
|
|
func (x *NetworkInfo) setConfigBool(name string, val bool) {
|
|
v := stackitem.NewBool(val)
|
|
x.setConfig(name, v.Bytes())
|
|
}
|
|
|
|
// decodeConfigValueUint64 parses val as little-endian uint64.
|
|
// val must be less than 8 bytes in size.
|
|
func decodeConfigValueUint64(val []byte) (uint64, error) {
|
|
if ln := len(val); ln > 8 {
|
|
return 0, fmt.Errorf("invalid uint64 parameter length %d", ln)
|
|
}
|
|
|
|
res := uint64(0)
|
|
for i := len(val) - 1; i >= 0; i-- {
|
|
res = res*256 + uint64(val[i])
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
// decodeConfigValueBool parses val as boolean contract storage value.
|
|
func decodeConfigValueBool(val []byte) (bool, error) {
|
|
arr := stackitem.NewByteArray(val)
|
|
|
|
res, err := arr.TryBool()
|
|
if err != nil {
|
|
return false, fmt.Errorf("invalid bool parameter contract format %s", err)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (x NetworkInfo) configUint64(name string) uint64 {
|
|
val := x.configValue(name)
|
|
if val == nil {
|
|
return 0
|
|
}
|
|
|
|
res, err := decodeConfigValueUint64(val)
|
|
if err != nil {
|
|
// potential panic is OK since value MUST be correct since it is
|
|
// verified in ReadFromV2 or set by provided method.
|
|
panic(err)
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
func (x NetworkInfo) configBool(name string) bool {
|
|
val := x.configValue(name)
|
|
if val == nil {
|
|
return false
|
|
}
|
|
|
|
res, err := decodeConfigValueBool(val)
|
|
if err != nil {
|
|
// potential panic is OK since value MUST be correct since it is
|
|
// verified in ReadFromV2 or set by provided method.
|
|
panic(err)
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
const configAuditFee = "AuditFee"
|
|
|
|
// SetAuditFee sets the configuration value of the audit fee for the Inner Ring.
|
|
//
|
|
// See also AuditFee.
|
|
func (x *NetworkInfo) SetAuditFee(fee uint64) {
|
|
x.setConfigUint64(configAuditFee, fee)
|
|
}
|
|
|
|
// AuditFee returns audit fee set using SetAuditFee.
|
|
//
|
|
// Zero NetworkInfo has zero audit fee.
|
|
func (x NetworkInfo) AuditFee() uint64 {
|
|
return x.configUint64(configAuditFee)
|
|
}
|
|
|
|
const configStoragePrice = "BasicIncomeRate"
|
|
|
|
// SetStoragePrice sets the price per gigabyte of data storage that data owners
|
|
// pay to storage nodes.
|
|
//
|
|
// See also StoragePrice.
|
|
func (x *NetworkInfo) SetStoragePrice(price uint64) {
|
|
x.setConfigUint64(configStoragePrice, price)
|
|
}
|
|
|
|
// StoragePrice returns storage price set using SetStoragePrice.
|
|
//
|
|
// Zero NetworkInfo has zero storage price.
|
|
func (x NetworkInfo) StoragePrice() uint64 {
|
|
return x.configUint64(configStoragePrice)
|
|
}
|
|
|
|
const configContainerFee = "ContainerFee"
|
|
|
|
// SetContainerFee sets fee for the container creation that creator pays to
|
|
// each Alphabet node.
|
|
//
|
|
// See also ContainerFee.
|
|
func (x *NetworkInfo) SetContainerFee(fee uint64) {
|
|
x.setConfigUint64(configContainerFee, fee)
|
|
}
|
|
|
|
// ContainerFee returns container fee set using SetContainerFee.
|
|
//
|
|
// Zero NetworkInfo has zero container fee.
|
|
func (x NetworkInfo) ContainerFee() uint64 {
|
|
return x.configUint64(configContainerFee)
|
|
}
|
|
|
|
const configNamedContainerFee = "ContainerAliasFee"
|
|
|
|
// SetNamedContainerFee sets fee for creation of the named container creation
|
|
// that creator pays to each Alphabet node.
|
|
//
|
|
// See also NamedContainerFee.
|
|
func (x *NetworkInfo) SetNamedContainerFee(fee uint64) {
|
|
x.setConfigUint64(configNamedContainerFee, fee)
|
|
}
|
|
|
|
// NamedContainerFee returns container fee set using SetNamedContainerFee.
|
|
//
|
|
// Zero NetworkInfo has zero container fee.
|
|
func (x NetworkInfo) NamedContainerFee() uint64 {
|
|
return x.configUint64(configNamedContainerFee)
|
|
}
|
|
|
|
const configEpochDuration = "EpochDuration"
|
|
|
|
// SetEpochDuration sets FrostFS epoch duration measured in number of blocks of
|
|
// the FrostFS Sidechain.
|
|
//
|
|
// See also EpochDuration.
|
|
func (x *NetworkInfo) SetEpochDuration(blocks uint64) {
|
|
x.setConfigUint64(configEpochDuration, blocks)
|
|
}
|
|
|
|
// EpochDuration returns epoch duration set using SetEpochDuration.
|
|
//
|
|
// Zero NetworkInfo has zero iteration number.
|
|
func (x NetworkInfo) EpochDuration() uint64 {
|
|
return x.configUint64(configEpochDuration)
|
|
}
|
|
|
|
const configIRCandidateFee = "InnerRingCandidateFee"
|
|
|
|
// SetIRCandidateFee sets fee for Inner Ring entrance paid by a new member.
|
|
//
|
|
// See also IRCandidateFee.
|
|
func (x *NetworkInfo) SetIRCandidateFee(fee uint64) {
|
|
x.setConfigUint64(configIRCandidateFee, fee)
|
|
}
|
|
|
|
// IRCandidateFee returns IR entrance fee set using SetIRCandidateFee.
|
|
//
|
|
// Zero NetworkInfo has zero fee.
|
|
func (x NetworkInfo) IRCandidateFee() uint64 {
|
|
return x.configUint64(configIRCandidateFee)
|
|
}
|
|
|
|
const configMaxObjSize = "MaxObjectSize"
|
|
|
|
// SetMaxObjectSize sets maximum size of the object stored locally on the
|
|
// storage nodes (physical objects). Binary representation of any physically
|
|
// stored object MUST NOT overflow the limit.
|
|
//
|
|
// See also MaxObjectSize.
|
|
func (x *NetworkInfo) SetMaxObjectSize(sz uint64) {
|
|
x.setConfigUint64(configMaxObjSize, sz)
|
|
}
|
|
|
|
// MaxObjectSize returns maximum object size set using SetMaxObjectSize.
|
|
//
|
|
// Zero NetworkInfo has zero maximum size.
|
|
func (x NetworkInfo) MaxObjectSize() uint64 {
|
|
return x.configUint64(configMaxObjSize)
|
|
}
|
|
|
|
const configMaxECDataCount = "MaxECDataCount"
|
|
|
|
// SetMaxECDataCount sets maximum number of data shards for erasure codes.
|
|
//
|
|
// Zero means no restrictions.
|
|
func (x *NetworkInfo) SetMaxECDataCount(dataCount uint64) {
|
|
x.setConfigUint64(configMaxECDataCount, dataCount)
|
|
}
|
|
|
|
// MaxECDataCount returns maximum number of data shards for erasure codes.
|
|
func (x NetworkInfo) MaxECDataCount() uint64 {
|
|
return x.configUint64(configMaxECDataCount)
|
|
}
|
|
|
|
const configMaxECParityCount = "MaxECParityCount"
|
|
|
|
// SetMaxECParityCount sets maximum number of parity shards for erasure codes.
|
|
//
|
|
// Zero means no restrictions.
|
|
func (x *NetworkInfo) SetMaxECParityCount(parityCount uint64) {
|
|
x.setConfigUint64(configMaxECParityCount, parityCount)
|
|
}
|
|
|
|
// MaxECParityCount returns maximum number of parity shards for erasure codes.
|
|
func (x NetworkInfo) MaxECParityCount() uint64 {
|
|
return x.configUint64(configMaxECParityCount)
|
|
}
|
|
|
|
const configWithdrawalFee = "WithdrawFee"
|
|
|
|
// SetWithdrawalFee sets fee for withdrawals from the FrostFS accounts that
|
|
// account owners pay to each Alphabet node.
|
|
//
|
|
// See also WithdrawalFee.
|
|
func (x *NetworkInfo) SetWithdrawalFee(sz uint64) {
|
|
x.setConfigUint64(configWithdrawalFee, sz)
|
|
}
|
|
|
|
// WithdrawalFee returns withdrawal fee set using SetWithdrawalFee.
|
|
//
|
|
// Zero NetworkInfo has zero fee.
|
|
func (x NetworkInfo) WithdrawalFee() uint64 {
|
|
return x.configUint64(configWithdrawalFee)
|
|
}
|
|
|
|
const configHomomorphicHashingDisabled = "HomomorphicHashingDisabled"
|
|
|
|
// DisableHomomorphicHashing sets flag requiring to disable homomorphic
|
|
// hashing of the containers in the network.
|
|
//
|
|
// See also HomomorphicHashingDisabled.
|
|
func (x *NetworkInfo) DisableHomomorphicHashing() {
|
|
x.setConfigBool(configHomomorphicHashingDisabled, true)
|
|
}
|
|
|
|
// HomomorphicHashingDisabled returns the state of the homomorphic
|
|
// hashing network setting.
|
|
//
|
|
// Zero NetworkInfo has enabled homomorphic hashing.
|
|
func (x NetworkInfo) HomomorphicHashingDisabled() bool {
|
|
return x.configBool(configHomomorphicHashingDisabled)
|
|
}
|
|
|
|
const configMaintenanceModeAllowed = "MaintenanceModeAllowed"
|
|
|
|
// AllowMaintenanceMode sets the flag allowing nodes to go into maintenance mode.
|
|
//
|
|
// See also MaintenanceModeAllowed.
|
|
func (x *NetworkInfo) AllowMaintenanceMode() {
|
|
x.setConfigBool(configMaintenanceModeAllowed, true)
|
|
}
|
|
|
|
// MaintenanceModeAllowed returns true iff network config allows
|
|
// maintenance mode for storage nodes.
|
|
//
|
|
// Zero NetworkInfo has disallows maintenance mode.
|
|
func (x NetworkInfo) MaintenanceModeAllowed() bool {
|
|
return x.configBool(configMaintenanceModeAllowed)
|
|
}
|