frostfs-sdk-go/netmap/network_info.go
Evgenii Stratonikov e9be3e6d94 [#205] netmap: Add well-known EC parameters to network config
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2024-03-22 10:14:12 +00:00

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)
}