frostfs-sdk-go/netmap/network_info.go
Airat Arifullin 6281a25556
All checks were successful
/ DCO (pull_request) Successful in 1m17s
/ Lint (pull_request) Successful in 2m7s
/ Tests (1.19) (pull_request) Successful in 5m56s
/ Tests (1.20) (pull_request) Successful in 6m37s
[#100] types: Make sdk types as protobuf wrappers
Signed-off-by: Airat Arifullin a.arifullin@yadro.com
2023-07-12 19:08:37 +03:00

496 lines
13 KiB
Go

package netmap
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"github.com/golang/protobuf/proto"
"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/netmapgrpc.NetworkInfo
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances must be created by NewNetworkInfo() constructor.
type NetworkInfo struct {
m *netmapgrpc.NetworkInfo
}
func NewNetworkInfo() NetworkInfo {
return NetworkInfo{
m: &netmapgrpc.NetworkInfo{},
}
}
// reads NetworkInfo from netmapgrpc.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 *netmapgrpc.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 *netmapgrpc.NetworkConfig_Parameter) 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,
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
}
if x.m == nil {
x.m = new(netmapgrpc.NetworkInfo)
}
proto.Merge(x.m, m)
return nil
}
// ReadFromV2 reads NetworkInfo from the netmapgrpc.NetworkInfo message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *NetworkInfo) ReadFromV2(m *netmapgrpc.NetworkInfo) error {
return x.readFromV2(m, true)
}
// WriteToV2 writes NetworkInfo to the netmapgrpc.NetworkInfo message. The message
// MUST NOT be nil.
//
// See also ReadFromV2.
func (x *NetworkInfo) WriteToV2(m *netmapgrpc.NetworkInfo) {
m.Reset()
proto.Merge(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(netmapgrpc.NetworkConfig)
var prm netmapgrpc.NetworkConfig_Parameter
prm.SetKey([]byte(name))
prm.SetValue(val)
c.SetParameters([]*netmapgrpc.NetworkConfig_Parameter{&prm})
x.m.SetNetworkConfig(c)
return
}
found := false
prms := make([]*netmapgrpc.NetworkConfig_Parameter, 0, c.NumberOfParameters())
c.IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) 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, &netmapgrpc.NetworkConfig_Parameter{})
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 *netmapgrpc.NetworkConfig_Parameter) 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 *netmapgrpc.NetworkConfig_Parameter) bool {
name := string(prm.GetKey())
switch name {
default:
f(name, prm.GetValue())
case
configAuditFee,
configStoragePrice,
configContainerFee,
configNamedContainerFee,
configEpochDuration,
configIRCandidateFee,
configMaxObjSize,
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 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)
}