From d0c5d837d204c28dbd6b4c447f7f7ddbd593aff9 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Mon, 17 Apr 2023 16:03:42 +0300 Subject: [PATCH] [#56] *: Drop reputation system Signed-off-by: Pavel Karpy --- client/common.go | 3 - client/reputation.go | 196 ----------------- netmap/network_info.go | 58 ----- netmap/network_info_test.go | 27 --- netmap/test/generate.go | 2 - reputation/doc.go | 35 --- reputation/peer.go | 103 --------- reputation/peer_test.go | 40 ---- reputation/test/generate.go | 58 ----- reputation/trust.go | 416 ------------------------------------ reputation/trust_test.go | 208 ------------------ 11 files changed, 1146 deletions(-) delete mode 100644 client/reputation.go delete mode 100644 reputation/doc.go delete mode 100644 reputation/peer.go delete mode 100644 reputation/peer_test.go delete mode 100644 reputation/test/generate.go delete mode 100644 reputation/trust.go delete mode 100644 reputation/trust_test.go diff --git a/client/common.go b/client/common.go index 5a50b28..1d56130 100644 --- a/client/common.go +++ b/client/common.go @@ -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. diff --git a/client/reputation.go b/client/reputation.go deleted file mode 100644 index f35cea3..0000000 --- a/client/reputation.go +++ /dev/null @@ -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 -} diff --git a/netmap/network_info.go b/netmap/network_info.go index 1381a8c..186d433 100644 --- a/netmap/network_info.go +++ b/netmap/network_info.go @@ -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 diff --git a/netmap/network_info_test.go b/netmap/network_info_test.go index 5104bdc..895a0a9 100644 --- a/netmap/network_info_test.go +++ b/netmap/network_info_test.go @@ -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() }, diff --git a/netmap/test/generate.go b/netmap/test/generate.go index f8792d0..3f5f26b 100644 --- a/netmap/test/generate.go +++ b/netmap/test/generate.go @@ -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) diff --git a/reputation/doc.go b/reputation/doc.go deleted file mode 100644 index a4dff88..0000000 --- a/reputation/doc.go +++ /dev/null @@ -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 diff --git a/reputation/peer.go b/reputation/peer.go deleted file mode 100644 index 38e8055..0000000 --- a/reputation/peer.go +++ /dev/null @@ -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() -} diff --git a/reputation/peer_test.go b/reputation/peer_test.go deleted file mode 100644 index 0a0ee96..0000000 --- a/reputation/peer_test.go +++ /dev/null @@ -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) -} diff --git a/reputation/test/generate.go b/reputation/test/generate.go deleted file mode 100644 index f70e7ef..0000000 --- a/reputation/test/generate.go +++ /dev/null @@ -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 -} diff --git a/reputation/trust.go b/reputation/trust.go deleted file mode 100644 index a0814cf..0000000 --- a/reputation/trust.go +++ /dev/null @@ -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) -} diff --git a/reputation/trust_test.go b/reputation/trust_test.go deleted file mode 100644 index 5e1185f..0000000 --- a/reputation/trust_test.go +++ /dev/null @@ -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) - }) -}