[#56] *: Drop reputation system

Signed-off-by: Pavel Karpy <p.karpy@yadro.com>
This commit is contained in:
Pavel Karpy 2023-04-17 16:03:42 +03:00 committed by fyrchik
parent 237b90f744
commit d0c5d837d2
11 changed files with 0 additions and 1146 deletions

View file

@ -82,9 +82,6 @@ var (
errorMissingAnnouncements = errors.New("missing announcements")
errorZeroRangeLength = errors.New("zero range length")
errorMissingRanges = errors.New("missing ranges")
errorZeroEpoch = errors.New("zero epoch")
errorMissingTrusts = errors.New("missing trusts")
errorTrustNotSet = errors.New("current trust value not set")
)
// groups all the details required to send a single request and process a response to it.

View file

@ -1,196 +0,0 @@
package client
import (
"context"
v2reputation "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
)
// PrmAnnounceLocalTrust groups parameters of AnnounceLocalTrust operation.
type PrmAnnounceLocalTrust struct {
prmCommonMeta
epoch uint64
trusts []reputation.Trust
}
// SetEpoch sets number of FrostFS epoch in which the trust was assessed.
// Required parameter, must not be zero.
func (x *PrmAnnounceLocalTrust) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// SetValues sets values describing trust of the client to the FrostFS network participants.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *PrmAnnounceLocalTrust) SetValues(trusts []reputation.Trust) {
x.trusts = trusts
}
// ResAnnounceLocalTrust groups results of AnnounceLocalTrust operation.
type ResAnnounceLocalTrust struct {
statusRes
}
// AnnounceLocalTrust sends client's trust values to the FrostFS network participants.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly (see PrmAnnounceLocalTrust docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) AnnounceLocalTrust(ctx context.Context, prm PrmAnnounceLocalTrust) (*ResAnnounceLocalTrust, error) {
// check parameters
switch {
case prm.epoch == 0:
return nil, errorZeroEpoch
case len(prm.trusts) == 0:
return nil, errorMissingTrusts
}
// form request body
reqBody := new(v2reputation.AnnounceLocalTrustRequestBody)
reqBody.SetEpoch(prm.epoch)
trusts := make([]v2reputation.Trust, len(prm.trusts))
for i := range prm.trusts {
prm.trusts[i].WriteToV2(&trusts[i])
}
reqBody.SetTrusts(trusts)
// form request
var req v2reputation.AnnounceLocalTrustRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResAnnounceLocalTrust
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceLocalTrust(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// PrmAnnounceIntermediateTrust groups parameters of AnnounceIntermediateTrust operation.
type PrmAnnounceIntermediateTrust struct {
prmCommonMeta
epoch uint64
iter uint32
trustSet bool
trust reputation.PeerToPeerTrust
}
// SetEpoch sets number of FrostFS epoch with which client's calculation algorithm is initialized.
// Required parameter, must not be zero.
func (x *PrmAnnounceIntermediateTrust) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// SetIteration sets current sequence number of the client's calculation algorithm.
// By default, corresponds to initial (zero) iteration.
func (x *PrmAnnounceIntermediateTrust) SetIteration(iter uint32) {
x.iter = iter
}
// SetCurrentValue sets current global trust value computed at the specified iteration
// of the client's calculation algorithm. Required parameter.
func (x *PrmAnnounceIntermediateTrust) SetCurrentValue(trust reputation.PeerToPeerTrust) {
x.trust = trust
x.trustSet = true
}
// ResAnnounceIntermediateTrust groups results of AnnounceIntermediateTrust operation.
type ResAnnounceIntermediateTrust struct {
statusRes
}
// AnnounceIntermediateTrust sends global trust values calculated for the specified FrostFS network participants
// at some stage of client's calculation algorithm.
//
// Exactly one return value is non-nil. By default, server status is returned in res structure.
// Any client's internal or transport errors are returned as `error`.
// If PrmInit.ResolveFrostFSFailures has been called, unsuccessful
// FrostFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
//
// Returns an error if parameters are set incorrectly (see PrmAnnounceIntermediateTrust docs).
// Context is required and must not be nil. It is used for network communication.
//
// Return statuses:
// - global (see Client docs).
func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm PrmAnnounceIntermediateTrust) (*ResAnnounceIntermediateTrust, error) {
// check parameters
switch {
case prm.epoch == 0:
return nil, errorZeroEpoch
case !prm.trustSet:
return nil, errorTrustNotSet
}
var trust v2reputation.PeerToPeerTrust
prm.trust.WriteToV2(&trust)
// form request body
reqBody := new(v2reputation.AnnounceIntermediateResultRequestBody)
reqBody.SetEpoch(prm.epoch)
reqBody.SetIteration(prm.iter)
reqBody.SetTrust(&trust)
// form request
var req v2reputation.AnnounceIntermediateResultRequest
req.SetBody(reqBody)
// init call context
var (
cc contextCall
res ResAnnounceIntermediateTrust
)
c.initCallContext(&cc)
cc.meta = prm.prmCommonMeta
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceIntermediateResult(&c.c, &req, client.WithContext(ctx))
}
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}

View file

@ -5,7 +5,6 @@ import (
"encoding/binary"
"errors"
"fmt"
"math"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -55,21 +54,11 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool)
err = fmt.Errorf("empty attribute value %s", name)
return true
}
case configEigenTrustAlpha:
var num uint64
num, err = decodeConfigValueUint64(prm.GetValue())
if err == nil {
if alpha := math.Float64frombits(num); alpha < 0 && alpha > 1 {
err = fmt.Errorf("EigenTrust alpha value %0.2f is out of range [0, 1]", alpha)
}
}
case
configAuditFee,
configStoragePrice,
configContainerFee,
configNamedContainerFee,
configEigenTrustNumberOfIterations,
configEpochDuration,
configIRCandidateFee,
configMaxObjSize,
@ -238,12 +227,10 @@ func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []by
default:
f(name, prm.GetValue())
case
configEigenTrustAlpha,
configAuditFee,
configStoragePrice,
configContainerFee,
configNamedContainerFee,
configEigenTrustNumberOfIterations,
configEpochDuration,
configIRCandidateFee,
configMaxObjSize,
@ -394,51 +381,6 @@ func (x NetworkInfo) NamedContainerFee() uint64 {
return x.configUint64(configNamedContainerFee)
}
const configEigenTrustAlpha = "EigenTrustAlpha"
// SetEigenTrustAlpha sets alpha parameter for EigenTrust algorithm used in
// reputation system of the storage nodes. Value MUST be in range [0, 1].
//
// See also EigenTrustAlpha.
func (x *NetworkInfo) SetEigenTrustAlpha(alpha float64) {
if alpha < 0 || alpha > 1 {
panic(fmt.Sprintf("EigenTrust alpha parameter MUST be in range [0, 1], got %.2f", alpha))
}
x.setConfigUint64(configEigenTrustAlpha, math.Float64bits(alpha))
}
// EigenTrustAlpha returns EigenTrust parameter set using SetEigenTrustAlpha.
//
// Zero NetworkInfo has zero alpha parameter.
func (x NetworkInfo) EigenTrustAlpha() float64 {
alpha := math.Float64frombits(x.configUint64(configEigenTrustAlpha))
if alpha < 0 || alpha > 1 {
panic(fmt.Sprintf("unexpected invalid %s parameter value %.2f", configEigenTrustAlpha, alpha))
}
return alpha
}
const configEigenTrustNumberOfIterations = "EigenTrustIterations"
// SetNumberOfEigenTrustIterations sets number of iterations of the EigenTrust
// algorithm to perform. The algorithm is used by the storage nodes for
// calculating the reputation values.
//
// See also NumberOfEigenTrustIterations.
func (x *NetworkInfo) SetNumberOfEigenTrustIterations(num uint64) {
x.setConfigUint64(configEigenTrustNumberOfIterations, num)
}
// NumberOfEigenTrustIterations returns number of EigenTrust iterations set
// using SetNumberOfEigenTrustIterations.
//
// Zero NetworkInfo has zero iteration number.
func (x NetworkInfo) NumberOfEigenTrustIterations() uint64 {
return x.configUint64(configEigenTrustNumberOfIterations)
}
const configEpochDuration = "EpochDuration"
// SetEpochDuration sets FrostFS epoch duration measured in number of blocks of

View file

@ -2,7 +2,6 @@ package netmap_test
import (
"encoding/binary"
"math"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
@ -148,32 +147,6 @@ func TestNetworkInfo_NamedContainerFee(t *testing.T) {
)
}
func TestNetworkInfo_EigenTrustAlpha(t *testing.T) {
testConfigValue(t,
func(x NetworkInfo) interface{} { return x.EigenTrustAlpha() },
func(info *NetworkInfo, val interface{}) { info.SetEigenTrustAlpha(val.(float64)) },
0.1, 0.2,
"EigenTrustAlpha", func(val interface{}) []byte {
data := make([]byte, 8)
binary.LittleEndian.PutUint64(data, math.Float64bits(val.(float64)))
return data
},
)
}
func TestNetworkInfo_NumberOfEigenTrustIterations(t *testing.T) {
testConfigValue(t,
func(x NetworkInfo) interface{} { return x.NumberOfEigenTrustIterations() },
func(info *NetworkInfo, val interface{}) { info.SetNumberOfEigenTrustIterations(val.(uint64)) },
uint64(1), uint64(2),
"EigenTrustIterations", func(val interface{}) []byte {
data := make([]byte, 8)
binary.LittleEndian.PutUint64(data, val.(uint64))
return data
},
)
}
func TestNetworkInfo_IRCandidateFee(t *testing.T) {
testConfigValue(t,
func(x NetworkInfo) interface{} { return x.IRCandidateFee() },

View file

@ -59,8 +59,6 @@ func NetworkInfo() (x netmap.NetworkInfo) {
x.SetAuditFee(1)
x.SetStoragePrice(2)
x.SetContainerFee(3)
x.SetEigenTrustAlpha(0.4)
x.SetNumberOfEigenTrustIterations(5)
x.SetEpochDuration(6)
x.SetIRCandidateFee(7)
x.SetMaxObjectSize(8)

View file

@ -1,35 +0,0 @@
/*
Package reputation collects functionality related to the FrostFS reputation system.
The functionality is based on the system described in the FrostFS specification.
Trust type represents simple instances of trust values. PeerToPeerTrust extends
Trust to support the direction of trust, i.e. from whom to whom. GlobalTrust
is designed as a global measure of trust in a network member. See the docs
for each type for details.
Instances can be also used to process FrostFS API V2 protocol messages
(see neo.fs.v2.reputation package in https://git.frostfs.info/TrueCloudLab/frostfs-api).
On client side:
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
var msg reputation.GlobalTrust
trust.WriteToV2(&msg)
// send trust
On server side:
// recv msg
var trust reputation.GlobalTrust
trust.ReadFromV2(msg)
// process trust
Using package types in an application is recommended to potentially work with
different protocol versions with which these types are compatible.
*/
package reputation

View file

@ -1,103 +0,0 @@
package reputation
import (
"bytes"
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
"github.com/mr-tron/base58"
)
// PeerID represents unique identifier of the peer participating in the FrostFS
// reputation system.
//
// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation.PeerID
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
type PeerID struct {
m reputation.PeerID
}
// ReadFromV2 reads PeerID from the reputation.PeerID message. Returns an
// error if the message is malformed according to the FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *PeerID) ReadFromV2(m reputation.PeerID) error {
val := m.GetPublicKey()
if len(val) == 0 {
return errors.New("missing ID bytes")
}
x.m = m
return nil
}
// WriteToV2 writes PeerID to the reputation.PeerID message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x PeerID) WriteToV2(m *reputation.PeerID) {
*m = x.m
}
// SetPublicKey sets PeerID as a binary-encoded public key which authenticates
// the participant of the FrostFS reputation system.
//
// Argument MUST NOT be mutated, make a copy first.
//
// See also CompareKey.
func (x *PeerID) SetPublicKey(key []byte) {
x.m.SetPublicKey(key)
}
// PublicKey return public key set using SetPublicKey.
//
// Zero PeerID has zero key which is incorrect according to FrostFS API
// protocol.
//
// Return value MUST NOT be mutated, make a copy first.
func (x PeerID) PublicKey() []byte {
return x.m.GetPublicKey()
}
// ComparePeerKey checks if the given PeerID corresponds to the party
// authenticated by the given binary public key.
func ComparePeerKey(peer PeerID, key []byte) bool {
return bytes.Equal(peer.PublicKey(), key)
}
// EncodeToString encodes ID into FrostFS API protocol string.
//
// Zero PeerID is base58 encoding of PeerIDSize zeros.
//
// See also DecodeString.
func (x PeerID) EncodeToString() string {
return base58.Encode(x.m.GetPublicKey())
}
// DecodeString decodes string into PeerID according to FrostFS API protocol.
// Returns an error if s is malformed.
//
// See also DecodeString.
func (x *PeerID) DecodeString(s string) error {
data, err := base58.Decode(s)
if err != nil {
return fmt.Errorf("decode base58: %w", err)
}
x.m.SetPublicKey(data)
return nil
}
// String implements fmt.Stringer.
//
// String is designed to be human-readable, and its format MAY differ between
// SDK versions. String MAY return same result as EncodeToString. String MUST NOT
// be used to encode ID into FrostFS protocol string.
func (x PeerID) String() string {
return x.EncodeToString()
}

View file

@ -1,40 +0,0 @@
package reputation_test
import (
"testing"
v2reputation "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
reputationtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation/test"
"github.com/stretchr/testify/require"
)
func TestPeerID_PublicKey(t *testing.T) {
var val reputation.PeerID
require.Zero(t, val.PublicKey())
key := []byte{3, 2, 1}
val.SetPublicKey(key)
var m v2reputation.PeerID
val.WriteToV2(&m)
require.Equal(t, key, m.GetPublicKey())
var val2 reputation.PeerID
require.NoError(t, val2.ReadFromV2(m))
require.Equal(t, key, val.PublicKey())
require.True(t, reputation.ComparePeerKey(val, key))
}
func TestPeerID_EncodeToString(t *testing.T) {
val := reputationtest.PeerID()
var val2 reputation.PeerID
require.NoError(t, val2.DecodeString(val.EncodeToString()))
require.Equal(t, val, val2)
}

View file

@ -1,58 +0,0 @@
package reputationtest
import (
"fmt"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)
func PeerID() (v reputation.PeerID) {
p, err := keys.NewPrivateKey()
if err != nil {
panic(err)
}
v.SetPublicKey(p.PublicKey().Bytes())
return
}
func Trust() (v reputation.Trust) {
v.SetPeer(PeerID())
v.SetValue(0.5)
return
}
func PeerToPeerTrust() (v reputation.PeerToPeerTrust) {
v.SetTrustingPeer(PeerID())
v.SetTrust(Trust())
return
}
func GlobalTrust() (v reputation.GlobalTrust) {
v.Init()
v.SetManager(PeerID())
v.SetTrust(Trust())
return
}
func SignedGlobalTrust() reputation.GlobalTrust {
gt := GlobalTrust()
p, err := keys.NewPrivateKey()
if err != nil {
panic(fmt.Sprintf("unexpected error from key creator: %v", err))
}
err = gt.Sign(frostfsecdsa.Signer(p.PrivateKey))
if err != nil {
panic(fmt.Sprintf("unexpected error from GlobalTrust.Sign: %v", err))
}
return gt
}

View file

@ -1,416 +0,0 @@
package reputation
import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
)
// Trust represents quantitative assessment of the trust of a participant in the
// FrostFS reputation system.
//
// Trust is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation.Trust
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
type Trust struct {
m reputation.Trust
}
// ReadFromV2 reads Trust from the reputation.Trust message. Returns an
// error if the message is malformed according to the FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *Trust) ReadFromV2(m reputation.Trust) error {
if val := m.GetValue(); val < 0 || val > 1 {
return fmt.Errorf("invalid trust value %v", val)
}
peerV2 := m.GetPeer()
if peerV2 == nil {
return errors.New("missing peer field")
}
var peer PeerID
err := peer.ReadFromV2(*peerV2)
if err != nil {
return fmt.Errorf("invalid peer field: %w", err)
}
x.m = m
return nil
}
// WriteToV2 writes Trust to the reputation.Trust message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x Trust) WriteToV2(m *reputation.Trust) {
*m = x.m
}
// SetPeer specifies identifier of the participant of the FrostFS reputation system
// to which the Trust relates.
//
// See also Peer.
func (x *Trust) SetPeer(id PeerID) {
var m reputation.PeerID
id.WriteToV2(&m)
x.m.SetPeer(&m)
}
// Peer returns peer identifier set using SetPeer.
//
// Zero Trust returns zero PeerID which is incorrect according to the FrostFS API
// protocol.
func (x Trust) Peer() (res PeerID) {
m := x.m.GetPeer()
if m != nil {
err := res.ReadFromV2(*m)
if err != nil {
panic(fmt.Sprintf("unexpected error from ReadFromV2: %v", err))
}
}
return
}
// SetValue sets the Trust value. Value MUST be in range [0;1].
//
// See also Value.
func (x *Trust) SetValue(val float64) {
if val < 0 || val > 1 {
panic(fmt.Sprintf("trust value is out-of-range %v", val))
}
x.m.SetValue(val)
}
// Value returns value set using SetValue.
//
// Zero Trust has zero value.
func (x Trust) Value() float64 {
return x.m.GetValue()
}
// PeerToPeerTrust represents trust of one participant of the FrostFS reputation
// system to another one.
//
// Trust is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation.PeerToPeerTrust
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
type PeerToPeerTrust struct {
m reputation.PeerToPeerTrust
}
// ReadFromV2 reads PeerToPeerTrust from the reputation.PeerToPeerTrust message.
// Returns an error if the message is malformed according to the FrostFS API V2
// protocol.
//
// See also WriteToV2.
func (x *PeerToPeerTrust) ReadFromV2(m reputation.PeerToPeerTrust) error {
trustingV2 := m.GetTrustingPeer()
if trustingV2 == nil {
return errors.New("missing trusting peer")
}
var trusting PeerID
err := trusting.ReadFromV2(*trustingV2)
if err != nil {
return fmt.Errorf("invalid trusting peer: %w", err)
}
trustV2 := m.GetTrust()
if trustV2 == nil {
return errors.New("missing trust")
}
var trust Trust
err = trust.ReadFromV2(*trustV2)
if err != nil {
return fmt.Errorf("invalid trust: %w", err)
}
x.m = m
return nil
}
// WriteToV2 writes PeerToPeerTrust to the reputation.PeerToPeerTrust message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x PeerToPeerTrust) WriteToV2(m *reputation.PeerToPeerTrust) {
*m = x.m
}
// SetTrustingPeer specifies the peer from which trust comes in terms of the
// FrostFS reputation system.
//
// See also TrustingPeer.
func (x *PeerToPeerTrust) SetTrustingPeer(id PeerID) {
var m reputation.PeerID
id.WriteToV2(&m)
x.m.SetTrustingPeer(&m)
}
// TrustingPeer returns peer set using SetTrustingPeer.
//
// Zero PeerToPeerTrust has no trusting peer which is incorrect according
// to the FrostFS API protocol.
func (x PeerToPeerTrust) TrustingPeer() (res PeerID) {
m := x.m.GetTrustingPeer()
if m != nil {
err := res.ReadFromV2(*m)
if err != nil {
panic(fmt.Sprintf("unexpected error from PeerID.ReadFromV2: %v", err))
}
}
return
}
// SetTrust sets trust value of the trusting peer to another participant
// of the FrostFS reputation system.
//
// See also Trust.
func (x *PeerToPeerTrust) SetTrust(t Trust) {
var tV2 reputation.Trust
t.WriteToV2(&tV2)
x.m.SetTrust(&tV2)
}
// Trust returns trust set using SetTrust.
//
// Zero PeerToPeerTrust returns zero Trust which is incorrect according to the
// FrostFS API protocol.
func (x PeerToPeerTrust) Trust() (res Trust) {
m := x.m.GetTrust()
if m != nil {
err := res.ReadFromV2(*m)
if err != nil {
panic(fmt.Sprintf("unexpected error from Trust.ReadFromV2: %v", err))
}
}
return
}
// GlobalTrust represents the final assessment of trust in the participant of
// the FrostFS reputation system obtained taking into account all other participants.
//
// GlobalTrust is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation.GlobalTrust
// message. See ReadFromV2 / WriteToV2 methods.
//
// To submit GlobalTrust value in FrostFS zero instance SHOULD be declared,
// initialized using Init method and filled using dedicated methods.
type GlobalTrust struct {
m reputation.GlobalTrust
}
// ReadFromV2 reads GlobalTrust from the reputation.GlobalTrust message.
// Returns an error if the message is malformed according to the FrostFS API V2
// protocol.
//
// See also WriteToV2.
func (x *GlobalTrust) ReadFromV2(m reputation.GlobalTrust) error {
if m.GetVersion() == nil {
return errors.New("missing version")
}
if m.GetSignature() == nil {
return errors.New("missing signature")
}
body := m.GetBody()
if body == nil {
return errors.New("missing body")
}
managerV2 := body.GetManager()
if managerV2 == nil {
return errors.New("missing manager")
}
var manager PeerID
err := manager.ReadFromV2(*managerV2)
if err != nil {
return fmt.Errorf("invalid manager: %w", err)
}
trustV2 := body.GetTrust()
if trustV2 == nil {
return errors.New("missing trust")
}
var trust Trust
err = trust.ReadFromV2(*trustV2)
if err != nil {
return fmt.Errorf("invalid trust: %w", err)
}
x.m = m
return nil
}
// WriteToV2 writes GlobalTrust to the reputation.GlobalTrust message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x GlobalTrust) WriteToV2(m *reputation.GlobalTrust) {
*m = x.m
}
// Init initializes all internal data of the GlobalTrust required by FrostFS API
// protocol. Init MUST be called when creating a new global trust instance.
// Init SHOULD NOT be called multiple times. Init SHOULD NOT be called if
// the GlobalTrust instance is used for decoding only.
func (x *GlobalTrust) Init() {
var ver refs.Version
version.Current().WriteToV2(&ver)
x.m.SetVersion(&ver)
}
func (x *GlobalTrust) setBodyField(setter func(*reputation.GlobalTrustBody)) {
if x != nil {
body := x.m.GetBody()
if body == nil {
body = new(reputation.GlobalTrustBody)
x.m.SetBody(body)
}
setter(body)
}
}
// SetManager sets identifier of the FrostFS reputation system's participant which
// performed trust estimation.
//
// See also Manager.
func (x *GlobalTrust) SetManager(id PeerID) {
var m reputation.PeerID
id.WriteToV2(&m)
x.setBodyField(func(body *reputation.GlobalTrustBody) {
body.SetManager(&m)
})
}
// Manager returns peer set using SetManager.
//
// Zero GlobalTrust has zero manager which is incorrect according to the
// FrostFS API protocol.
func (x GlobalTrust) Manager() (res PeerID) {
m := x.m.GetBody().GetManager()
if m != nil {
err := res.ReadFromV2(*m)
if err != nil {
panic(fmt.Sprintf("unexpected error from ReadFromV2: %v", err))
}
}
return
}
// SetTrust sets the global trust score of the network to a specific network
// member.
//
// See also Trust.
func (x *GlobalTrust) SetTrust(trust Trust) {
var m reputation.Trust
trust.WriteToV2(&m)
x.setBodyField(func(body *reputation.GlobalTrustBody) {
body.SetTrust(&m)
})
}
// Trust returns trust set using SetTrust.
//
// Zero GlobalTrust return zero Trust which is incorrect according to the
// FrostFS API protocol.
func (x GlobalTrust) Trust() (res Trust) {
m := x.m.GetBody().GetTrust()
if m != nil {
err := res.ReadFromV2(*m)
if err != nil {
panic(fmt.Sprintf("unexpected error from ReadFromV2: %v", err))
}
}
return
}
// Sign calculates and writes signature of the GlobalTrust data. Returns
// signature calculation errors.
//
// Zero GlobalTrust is unsigned.
//
// Note that any GlobalTrust mutation is likely to break the signature, so it is
// expected to be calculated as a final stage of GlobalTrust formation.
//
// See also VerifySignature.
func (x *GlobalTrust) Sign(signer frostfscrypto.Signer) error {
var sig frostfscrypto.Signature
err := sig.Calculate(signer, x.m.GetBody().StableMarshal(nil))
if err != nil {
return fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
x.m.SetSignature(&sigv2)
return nil
}
// VerifySignature checks if GlobalTrust signature is presented and valid.
//
// Zero GlobalTrust fails the check.
//
// See also Sign.
func (x GlobalTrust) VerifySignature() bool {
sigV2 := x.m.GetSignature()
if sigV2 == nil {
return false
}
var sig frostfscrypto.Signature
return sig.ReadFromV2(*sigV2) == nil && sig.Verify(x.m.GetBody().StableMarshal(nil))
}
// Marshal encodes GlobalTrust into a binary format of the FrostFS API protocol
// (Protocol Buffers with direct field order).
//
// See also Unmarshal.
func (x GlobalTrust) Marshal() []byte {
return x.m.StableMarshal(nil)
}
// Unmarshal decodes FrostFS API protocol binary format into the GlobalTrust
// (Protocol Buffers with direct field order). Returns an error describing
// a format violation.
//
// See also Marshal.
func (x *GlobalTrust) Unmarshal(data []byte) error {
return x.m.Unmarshal(data)
}

View file

@ -1,208 +0,0 @@
package reputation_test
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
v2reputation "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
reputationtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
func TestTrust_Peer(t *testing.T) {
var trust reputation.Trust
require.Zero(t, trust.Peer())
trust = reputationtest.Trust()
peer := reputationtest.PeerID()
trust.SetPeer(peer)
var peerV2 v2reputation.PeerID
peer.WriteToV2(&peerV2)
var trustV2 v2reputation.Trust
trust.WriteToV2(&trustV2)
require.Equal(t, &peerV2, trustV2.GetPeer())
var val2 reputation.Trust
require.NoError(t, val2.ReadFromV2(trustV2))
require.Equal(t, peer, val2.Peer())
}
func TestTrust_Value(t *testing.T) {
var val reputation.Trust
require.Zero(t, val.Value())
val = reputationtest.Trust()
const value = 0.75
val.SetValue(value)
var trustV2 v2reputation.Trust
val.WriteToV2(&trustV2)
require.EqualValues(t, value, trustV2.GetValue())
var val2 reputation.Trust
require.NoError(t, val2.ReadFromV2(trustV2))
require.EqualValues(t, value, val2.Value())
}
func TestPeerToPeerTrust_TrustingPeer(t *testing.T) {
var val reputation.PeerToPeerTrust
require.Zero(t, val.TrustingPeer())
val = reputationtest.PeerToPeerTrust()
peer := reputationtest.PeerID()
val.SetTrustingPeer(peer)
var peerV2 v2reputation.PeerID
peer.WriteToV2(&peerV2)
var trustV2 v2reputation.PeerToPeerTrust
val.WriteToV2(&trustV2)
require.Equal(t, &peerV2, trustV2.GetTrustingPeer())
var val2 reputation.PeerToPeerTrust
require.NoError(t, val2.ReadFromV2(trustV2))
require.Equal(t, peer, val2.TrustingPeer())
}
func TestPeerToPeerTrust_Trust(t *testing.T) {
var val reputation.PeerToPeerTrust
require.Zero(t, val.Trust())
val = reputationtest.PeerToPeerTrust()
trust := reputationtest.Trust()
val.SetTrust(trust)
var trustV2 v2reputation.Trust
trust.WriteToV2(&trustV2)
var valV2 v2reputation.PeerToPeerTrust
val.WriteToV2(&valV2)
require.Equal(t, &trustV2, valV2.GetTrust())
var val2 reputation.PeerToPeerTrust
require.NoError(t, val2.ReadFromV2(valV2))
require.Equal(t, trust, val2.Trust())
}
func TestGlobalTrust_Init(t *testing.T) {
var val reputation.GlobalTrust
val.Init()
var valV2 v2reputation.GlobalTrust
val.WriteToV2(&valV2)
var verV2 refs.Version
version.Current().WriteToV2(&verV2)
require.Equal(t, &verV2, valV2.GetVersion())
}
func TestGlobalTrust_Manager(t *testing.T) {
var val reputation.GlobalTrust
require.Zero(t, val.Manager())
val = reputationtest.SignedGlobalTrust()
peer := reputationtest.PeerID()
val.SetManager(peer)
var peerV2 v2reputation.PeerID
peer.WriteToV2(&peerV2)
var trustV2 v2reputation.GlobalTrust
val.WriteToV2(&trustV2)
require.Equal(t, &peerV2, trustV2.GetBody().GetManager())
var val2 reputation.GlobalTrust
require.NoError(t, val2.ReadFromV2(trustV2))
require.Equal(t, peer, val2.Manager())
}
func TestGlobalTrust_Trust(t *testing.T) {
var val reputation.GlobalTrust
require.Zero(t, val.Trust())
val = reputationtest.SignedGlobalTrust()
trust := reputationtest.Trust()
val.SetTrust(trust)
var trustV2 v2reputation.Trust
trust.WriteToV2(&trustV2)
var valV2 v2reputation.GlobalTrust
val.WriteToV2(&valV2)
require.Equal(t, &trustV2, valV2.GetBody().GetTrust())
var val2 reputation.GlobalTrust
require.NoError(t, val2.ReadFromV2(valV2))
require.Equal(t, trust, val2.Trust())
}
func TestGlobalTrust_Sign(t *testing.T) {
k, err := keys.NewPrivateKey()
require.NoError(t, err)
val := reputationtest.GlobalTrust()
require.False(t, val.VerifySignature())
require.NoError(t, val.Sign(frostfsecdsa.Signer(k.PrivateKey)))
var valV2 v2reputation.GlobalTrust
val.WriteToV2(&valV2)
require.NotZero(t, valV2.GetSignature())
var val2 reputation.GlobalTrust
require.NoError(t, val2.ReadFromV2(valV2))
require.True(t, val2.VerifySignature())
}
func TestGlobalTrustEncoding(t *testing.T) {
val := reputationtest.SignedGlobalTrust()
t.Run("binary", func(t *testing.T) {
data := val.Marshal()
var val2 reputation.GlobalTrust
require.NoError(t, val2.Unmarshal(data))
require.Equal(t, val, val2)
})
}