fix/355-increase-tree-service-client-cache-size #359
65 changed files with 15 additions and 4956 deletions
|
@ -142,7 +142,6 @@ func setWorkersDefaults(cfg *viper.Viper) {
|
||||||
cfg.SetDefault("workers.frostfs", "10")
|
cfg.SetDefault("workers.frostfs", "10")
|
||||||
cfg.SetDefault("workers.container", "10")
|
cfg.SetDefault("workers.container", "10")
|
||||||
cfg.SetDefault("workers.alphabet", "10")
|
cfg.SetDefault("workers.alphabet", "10")
|
||||||
cfg.SetDefault("workers.reputation", "10")
|
|
||||||
cfg.SetDefault("workers.subnet", "10")
|
cfg.SetDefault("workers.subnet", "10")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/tombstone"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/tombstone"
|
||||||
tsourse "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/tombstone/source"
|
tsourse "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/tombstone/source"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/replicator"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/replicator"
|
||||||
trustcontroller "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/controller"
|
|
||||||
truststorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/storage"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/util/response"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/util/response"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
||||||
|
@ -414,7 +412,6 @@ type cfg struct {
|
||||||
cfgNodeInfo cfgNodeInfo
|
cfgNodeInfo cfgNodeInfo
|
||||||
cfgNetmap cfgNetmap
|
cfgNetmap cfgNetmap
|
||||||
cfgControlService cfgControlService
|
cfgControlService cfgControlService
|
||||||
cfgReputation cfgReputation
|
|
||||||
cfgObject cfgObject
|
cfgObject cfgObject
|
||||||
cfgNotifications cfgNotifications
|
cfgNotifications cfgNotifications
|
||||||
}
|
}
|
||||||
|
@ -452,8 +449,6 @@ type cfgMorph struct {
|
||||||
// TTL of Sidechain cached values. Non-positive value disables caching.
|
// TTL of Sidechain cached values. Non-positive value disables caching.
|
||||||
cacheTTL time.Duration
|
cacheTTL time.Duration
|
||||||
|
|
||||||
eigenTrustTicker *eigenTrustTickers // timers for EigenTrust iterations
|
|
||||||
|
|
||||||
proxyScriptHash neogoutil.Uint160
|
proxyScriptHash neogoutil.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,16 +527,6 @@ type cfgControlService struct {
|
||||||
server *grpc.Server
|
server *grpc.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
type cfgReputation struct {
|
|
||||||
workerPool util.WorkerPool // pool for EigenTrust algorithm's iterations
|
|
||||||
|
|
||||||
localTrustStorage *truststorage.Storage
|
|
||||||
|
|
||||||
localTrustCtrl *trustcontroller.Controller
|
|
||||||
|
|
||||||
scriptHash neogoutil.Uint160
|
|
||||||
}
|
|
||||||
|
|
||||||
var persistateSideChainLastBlockKey = []byte("side_chain_last_processed_block")
|
var persistateSideChainLastBlockKey = []byte("side_chain_last_processed_block")
|
||||||
|
|
||||||
func initCfg(appCfg *config.Config) *cfg {
|
func initCfg(appCfg *config.Config) *cfg {
|
||||||
|
@ -582,8 +567,6 @@ func initCfg(appCfg *config.Config) *cfg {
|
||||||
}
|
}
|
||||||
c.cfgObject = initCfgObject(appCfg)
|
c.cfgObject = initCfgObject(appCfg)
|
||||||
|
|
||||||
c.cfgReputation = initReputation(appCfg)
|
|
||||||
|
|
||||||
user.IDFromKey(&c.ownerIDFromKey, key.PrivateKey.PublicKey)
|
user.IDFromKey(&c.ownerIDFromKey, key.PrivateKey.PublicKey)
|
||||||
|
|
||||||
c.metricsCollector = metrics.NewNodeMetrics()
|
c.metricsCollector = metrics.NewNodeMetrics()
|
||||||
|
@ -662,16 +645,6 @@ func initContainer(appCfg *config.Config) cfgContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initReputation(appCfg *config.Config) cfgReputation {
|
|
||||||
reputationWorkerPool, err := ants.NewPool(notificationHandlerPoolSize)
|
|
||||||
fatalOnErr(err)
|
|
||||||
|
|
||||||
return cfgReputation{
|
|
||||||
scriptHash: contractsconfig.Reputation(appCfg),
|
|
||||||
workerPool: reputationWorkerPool,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCfgGRPC() cfgGRPC {
|
func initCfgGRPC() cfgGRPC {
|
||||||
maxChunkSize := uint64(maxMsgSize) * 3 / 4 // 25% to meta, 75% to payload
|
maxChunkSize := uint64(maxMsgSize) * 3 / 4 // 25% to meta, 75% to payload
|
||||||
maxAddrAmount := uint64(maxChunkSize) / addressSize // each address is about 72 bytes
|
maxAddrAmount := uint64(maxChunkSize) / addressSize // each address is about 72 bytes
|
||||||
|
|
|
@ -330,7 +330,7 @@ type remoteLoadAnnounceProvider struct {
|
||||||
netmapKeys netmapCore.AnnouncedKeys
|
netmapKeys netmapCore.AnnouncedKeys
|
||||||
|
|
||||||
clientCache interface {
|
clientCache interface {
|
||||||
Get(client.NodeInfo) (client.Client, error)
|
Get(client.NodeInfo) (client.MultiAddressClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
deadEndProvider loadcontroller.WriterProvider
|
deadEndProvider loadcontroller.WriterProvider
|
||||||
|
|
|
@ -102,7 +102,6 @@ func initApp(ctx context.Context, c *cfg) {
|
||||||
initAndLog(c, "accounting", func(c *cfg) { initAccountingService(ctx, c) })
|
initAndLog(c, "accounting", func(c *cfg) { initAccountingService(ctx, c) })
|
||||||
initAndLog(c, "container", func(c *cfg) { initContainerService(ctx, c) })
|
initAndLog(c, "container", func(c *cfg) { initContainerService(ctx, c) })
|
||||||
initAndLog(c, "session", initSessionService)
|
initAndLog(c, "session", initSessionService)
|
||||||
initAndLog(c, "reputation", func(c *cfg) { initReputationService(ctx, c) })
|
|
||||||
initAndLog(c, "notification", func(c *cfg) { initNotifications(ctx, c) })
|
initAndLog(c, "notification", func(c *cfg) { initNotifications(ctx, c) })
|
||||||
initAndLog(c, "object", initObjectService)
|
initAndLog(c, "object", initObjectService)
|
||||||
initAndLog(c, "tree", initTreeService)
|
initAndLog(c, "tree", initTreeService)
|
||||||
|
|
|
@ -235,8 +235,6 @@ func listenMorphNotifications(ctx context.Context, c *cfg) {
|
||||||
zap.String("chain", "side"),
|
zap.String("chain", "side"),
|
||||||
zap.Uint32("block_index", block.Index))
|
zap.Uint32("block_index", block.Index))
|
||||||
}
|
}
|
||||||
|
|
||||||
tickBlockTimers(c)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +283,6 @@ func lookupScriptHashesInNNS(c *cfg) {
|
||||||
{&c.cfgNetmap.scriptHash, client.NNSNetmapContractName},
|
{&c.cfgNetmap.scriptHash, client.NNSNetmapContractName},
|
||||||
{&c.cfgAccounting.scriptHash, client.NNSBalanceContractName},
|
{&c.cfgAccounting.scriptHash, client.NNSBalanceContractName},
|
||||||
{&c.cfgContainer.scriptHash, client.NNSContainerContractName},
|
{&c.cfgContainer.scriptHash, client.NNSContainerContractName},
|
||||||
{&c.cfgReputation.scriptHash, client.NNSReputationContractName},
|
|
||||||
{&c.cfgMorph.proxyScriptHash, client.NNSProxyContractName},
|
{&c.cfgMorph.proxyScriptHash, client.NNSProxyContractName},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -12,7 +11,6 @@ import (
|
||||||
policerconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/policer"
|
policerconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/policer"
|
||||||
replicatorconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/replicator"
|
replicatorconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/replicator"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
coreclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
||||||
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
||||||
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
||||||
|
@ -20,6 +18,7 @@ import (
|
||||||
morphClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
morphClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network/cache"
|
||||||
objectTransportGRPC "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network/transport/object/grpc"
|
objectTransportGRPC "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network/transport/object/grpc"
|
||||||
objectService "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object"
|
objectService "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/acl"
|
||||||
|
@ -37,15 +36,10 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/policer"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/policer"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/replicator"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/replicator"
|
||||||
truststorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/storage"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
eaclSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
eaclSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -153,39 +147,12 @@ func (f *innerRingFetcherWithoutNotary) InnerRingKeys() ([][]byte, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type coreClientConstructor reputationClientConstructor
|
|
||||||
|
|
||||||
func (x *coreClientConstructor) Get(info coreclient.NodeInfo) (coreclient.MultiAddressClient, error) {
|
|
||||||
c, err := (*reputationClientConstructor)(x).Get(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.(coreclient.MultiAddressClient), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initObjectService(c *cfg) {
|
func initObjectService(c *cfg) {
|
||||||
keyStorage := util.NewKeyStorage(&c.key.PrivateKey, c.privateTokenStore, c.cfgNetmap.state)
|
keyStorage := util.NewKeyStorage(&c.key.PrivateKey, c.privateTokenStore, c.cfgNetmap.state)
|
||||||
|
|
||||||
clientConstructor := &reputationClientConstructor{
|
c.replicator = createReplicator(c, keyStorage, c.bgClientCache)
|
||||||
log: c.log,
|
|
||||||
nmSrc: c.netMapSource,
|
|
||||||
netState: c.cfgNetmap.state,
|
|
||||||
trustStorage: c.cfgReputation.localTrustStorage,
|
|
||||||
basicConstructor: c.bgClientCache,
|
|
||||||
}
|
|
||||||
|
|
||||||
coreConstructor := &coreClientConstructor{
|
addPolicer(c, keyStorage, c.bgClientCache)
|
||||||
log: c.log,
|
|
||||||
nmSrc: c.netMapSource,
|
|
||||||
netState: c.cfgNetmap.state,
|
|
||||||
trustStorage: c.cfgReputation.localTrustStorage,
|
|
||||||
basicConstructor: c.clientCache,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.replicator = createReplicator(c, keyStorage, clientConstructor)
|
|
||||||
|
|
||||||
addPolicer(c, keyStorage, clientConstructor)
|
|
||||||
|
|
||||||
traverseGen := util.NewTraverserGenerator(c.netMapSource, c.cfgObject.cnrSource, c)
|
traverseGen := util.NewTraverserGenerator(c.netMapSource, c.cfgObject.cnrSource, c)
|
||||||
|
|
||||||
|
@ -193,11 +160,11 @@ func initObjectService(c *cfg) {
|
||||||
|
|
||||||
sPutV2 := createPutSvcV2(sPut, keyStorage)
|
sPutV2 := createPutSvcV2(sPut, keyStorage)
|
||||||
|
|
||||||
sSearch := createSearchSvc(c, keyStorage, traverseGen, coreConstructor)
|
sSearch := createSearchSvc(c, keyStorage, traverseGen, c.clientCache)
|
||||||
|
|
||||||
sSearchV2 := createSearchSvcV2(sSearch, keyStorage)
|
sSearchV2 := createSearchSvcV2(sSearch, keyStorage)
|
||||||
|
|
||||||
sGet := createGetService(c, keyStorage, traverseGen, coreConstructor)
|
sGet := createGetService(c, keyStorage, traverseGen, c.clientCache)
|
||||||
|
|
||||||
*c.cfgObject.getSvc = *sGet // need smth better
|
*c.cfgObject.getSvc = *sGet // need smth better
|
||||||
|
|
||||||
|
@ -236,7 +203,7 @@ func initObjectService(c *cfg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPolicer(c *cfg, keyStorage *util.KeyStorage, clientConstructor *reputationClientConstructor) {
|
func addPolicer(c *cfg, keyStorage *util.KeyStorage, clientConstructor *cache.ClientCache) {
|
||||||
ls := c.cfgObject.cfgLocalStorage.localStorage
|
ls := c.cfgObject.cfgLocalStorage.localStorage
|
||||||
|
|
||||||
pol := policer.New(
|
pol := policer.New(
|
||||||
|
@ -288,7 +255,7 @@ func createInnerRingFetcher(c *cfg) v2.InnerRingFetcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createReplicator(c *cfg, keyStorage *util.KeyStorage, clientConstructor *reputationClientConstructor) *replicator.Replicator {
|
func createReplicator(c *cfg, keyStorage *util.KeyStorage, cache *cache.ClientCache) *replicator.Replicator {
|
||||||
ls := c.cfgObject.cfgLocalStorage.localStorage
|
ls := c.cfgObject.cfgLocalStorage.localStorage
|
||||||
|
|
||||||
return replicator.New(
|
return replicator.New(
|
||||||
|
@ -298,7 +265,7 @@ func createReplicator(c *cfg, keyStorage *util.KeyStorage, clientConstructor *re
|
||||||
),
|
),
|
||||||
replicator.WithLocalStorage(ls),
|
replicator.WithLocalStorage(ls),
|
||||||
replicator.WithRemoteSender(
|
replicator.WithRemoteSender(
|
||||||
putsvc.NewRemoteSender(keyStorage, (*coreClientConstructor)(clientConstructor)),
|
putsvc.NewRemoteSender(keyStorage, cache),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -319,17 +286,9 @@ func createPutSvc(c *cfg, keyStorage *util.KeyStorage) *putsvc.Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
putConstructor := &coreClientConstructor{
|
|
||||||
log: c.log,
|
|
||||||
nmSrc: c.netMapSource,
|
|
||||||
netState: c.cfgNetmap.state,
|
|
||||||
trustStorage: c.cfgReputation.localTrustStorage,
|
|
||||||
basicConstructor: c.putClientCache,
|
|
||||||
}
|
|
||||||
|
|
||||||
return putsvc.NewService(
|
return putsvc.NewService(
|
||||||
putsvc.WithKeyStorage(keyStorage),
|
putsvc.WithKeyStorage(keyStorage),
|
||||||
putsvc.WithClientConstructor(putConstructor),
|
putsvc.WithClientConstructor(c.putClientCache),
|
||||||
putsvc.WithMaxSizeSource(newCachedMaxObjectSizeSource(c)),
|
putsvc.WithMaxSizeSource(newCachedMaxObjectSizeSource(c)),
|
||||||
putsvc.WithObjectStorage(os),
|
putsvc.WithObjectStorage(os),
|
||||||
putsvc.WithContainerSource(c.cfgObject.cnrSource),
|
putsvc.WithContainerSource(c.cfgObject.cnrSource),
|
||||||
|
@ -348,7 +307,7 @@ func createPutSvcV2(sPut *putsvc.Service, keyStorage *util.KeyStorage) *putsvcV2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSearchSvc(c *cfg, keyStorage *util.KeyStorage, traverseGen *util.TraverserGenerator, coreConstructor *coreClientConstructor) *searchsvc.Service {
|
func createSearchSvc(c *cfg, keyStorage *util.KeyStorage, traverseGen *util.TraverserGenerator, coreConstructor *cache.ClientCache) *searchsvc.Service {
|
||||||
ls := c.cfgObject.cfgLocalStorage.localStorage
|
ls := c.cfgObject.cfgLocalStorage.localStorage
|
||||||
|
|
||||||
return searchsvc.New(
|
return searchsvc.New(
|
||||||
|
@ -373,7 +332,7 @@ func createSearchSvcV2(sSearch *searchsvc.Service, keyStorage *util.KeyStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createGetService(c *cfg, keyStorage *util.KeyStorage, traverseGen *util.TraverserGenerator,
|
func createGetService(c *cfg, keyStorage *util.KeyStorage, traverseGen *util.TraverserGenerator,
|
||||||
coreConstructor *coreClientConstructor) *getsvc.Service {
|
coreConstructor *cache.ClientCache) *getsvc.Service {
|
||||||
ls := c.cfgObject.cfgLocalStorage.localStorage
|
ls := c.cfgObject.cfgLocalStorage.localStorage
|
||||||
|
|
||||||
return getsvc.New(
|
return getsvc.New(
|
||||||
|
@ -480,135 +439,6 @@ func (s *morphEACLFetcher) GetEACL(cnr cid.ID) (*containercore.EACL, error) {
|
||||||
return eaclInfo, nil
|
return eaclInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type reputationClientConstructor struct {
|
|
||||||
log *logger.Logger
|
|
||||||
|
|
||||||
nmSrc netmap.Source
|
|
||||||
|
|
||||||
netState netmap.State
|
|
||||||
|
|
||||||
trustStorage *truststorage.Storage
|
|
||||||
|
|
||||||
basicConstructor interface {
|
|
||||||
Get(coreclient.NodeInfo) (coreclient.Client, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type reputationClient struct {
|
|
||||||
coreclient.MultiAddressClient
|
|
||||||
|
|
||||||
prm truststorage.UpdatePrm
|
|
||||||
|
|
||||||
cons *reputationClientConstructor
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) submitResult(err error) {
|
|
||||||
currEpoch := c.cons.netState.CurrentEpoch()
|
|
||||||
sat := err == nil
|
|
||||||
|
|
||||||
c.cons.log.Debug(
|
|
||||||
"writing local reputation values",
|
|
||||||
zap.Uint64("epoch", currEpoch),
|
|
||||||
zap.Bool("satisfactory", sat),
|
|
||||||
)
|
|
||||||
|
|
||||||
prm := c.prm
|
|
||||||
prm.SetSatisfactory(sat)
|
|
||||||
prm.SetEpoch(currEpoch)
|
|
||||||
|
|
||||||
c.cons.trustStorage.Update(prm)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) ObjectPutInit(ctx context.Context, prm client.PrmObjectPutInit) (*client.ObjectWriter, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectPutInit(ctx, prm)
|
|
||||||
|
|
||||||
// FIXME: (neofs-node#1193) here we submit only initialization errors, writing errors are not processed
|
|
||||||
c.submitResult(err)
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) ObjectDelete(ctx context.Context, prm client.PrmObjectDelete) (*client.ResObjectDelete, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectDelete(ctx, prm)
|
|
||||||
if err != nil {
|
|
||||||
c.submitResult(err)
|
|
||||||
} else {
|
|
||||||
c.submitResult(apistatus.ErrFromStatus(res.Status()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) GetObjectInit(ctx context.Context, prm client.PrmObjectGet) (*client.ObjectReader, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectGetInit(ctx, prm)
|
|
||||||
|
|
||||||
// FIXME: (neofs-node#1193) here we submit only initialization errors, reading errors are not processed
|
|
||||||
c.submitResult(err)
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) ObjectHead(ctx context.Context, prm client.PrmObjectHead) (*client.ResObjectHead, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectHead(ctx, prm)
|
|
||||||
|
|
||||||
c.submitResult(err)
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) ObjectHash(ctx context.Context, prm client.PrmObjectHash) (*client.ResObjectHash, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectHash(ctx, prm)
|
|
||||||
|
|
||||||
c.submitResult(err)
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClient) ObjectSearchInit(ctx context.Context, prm client.PrmObjectSearch) (*client.ObjectListReader, error) {
|
|
||||||
res, err := c.MultiAddressClient.ObjectSearchInit(ctx, prm)
|
|
||||||
|
|
||||||
// FIXME: (neofs-node#1193) here we submit only initialization errors, reading errors are not processed
|
|
||||||
c.submitResult(err)
|
|
||||||
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reputationClientConstructor) Get(info coreclient.NodeInfo) (coreclient.Client, error) {
|
|
||||||
cl, err := c.basicConstructor.Get(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nm, err := netmap.GetLatestNetworkMap(c.nmSrc)
|
|
||||||
if err == nil {
|
|
||||||
key := info.PublicKey()
|
|
||||||
|
|
||||||
nmNodes := nm.Nodes()
|
|
||||||
var peer apireputation.PeerID
|
|
||||||
|
|
||||||
for i := range nmNodes {
|
|
||||||
if bytes.Equal(nmNodes[i].PublicKey(), key) {
|
|
||||||
peer.SetPublicKey(nmNodes[i].PublicKey())
|
|
||||||
|
|
||||||
prm := truststorage.UpdatePrm{}
|
|
||||||
prm.SetPeer(peer)
|
|
||||||
|
|
||||||
return &reputationClient{
|
|
||||||
MultiAddressClient: cl.(coreclient.MultiAddressClient),
|
|
||||||
prm: prm,
|
|
||||||
cons: c,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c.log.Warn(logs.FrostFSNodeCouldNotGetLatestNetworkMapToOverloadTheClient,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cl, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type engineWithNotifications struct {
|
type engineWithNotifications struct {
|
||||||
base putsvc.ObjectStorage
|
base putsvc.ObjectStorage
|
||||||
nw notificationWriter
|
nw notificationWriter
|
||||||
|
|
|
@ -1,386 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v2reputation "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
|
|
||||||
v2reputationgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation/grpc"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/common"
|
|
||||||
intermediatereputation "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/intermediate"
|
|
||||||
localreputation "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/local"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/ticker"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
repClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
|
||||||
grpcreputation "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network/transport/reputation/grpc"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
reputationrouter "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common/router"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
eigentrustctrl "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/controller"
|
|
||||||
intermediateroutes "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/routes"
|
|
||||||
consumerstorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/consumers"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/daughters"
|
|
||||||
localtrustcontroller "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/controller"
|
|
||||||
localroutes "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/routes"
|
|
||||||
truststorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/storage"
|
|
||||||
reputationrpc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/rpc"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func initReputationService(ctx context.Context, c *cfg) {
|
|
||||||
wrap, err := repClient.NewFromMorph(c.cfgMorph.client, c.cfgReputation.scriptHash, 0, repClient.TryNotary())
|
|
||||||
fatalOnErr(err)
|
|
||||||
|
|
||||||
localKey := c.key.PublicKey().Bytes()
|
|
||||||
|
|
||||||
nmSrc := c.netMapSource
|
|
||||||
|
|
||||||
// storing calculated trusts as a daughter
|
|
||||||
c.cfgReputation.localTrustStorage = truststorage.New(
|
|
||||||
truststorage.Prm{},
|
|
||||||
)
|
|
||||||
|
|
||||||
daughterStorage := daughters.New(daughters.Prm{})
|
|
||||||
consumerStorage := consumerstorage.New(consumerstorage.Prm{})
|
|
||||||
|
|
||||||
localTrustLogger := &logger.Logger{Logger: c.log.With(zap.String("trust_type", "local"))}
|
|
||||||
|
|
||||||
managerBuilder := reputationcommon.NewManagerBuilder(
|
|
||||||
reputationcommon.ManagersPrm{
|
|
||||||
NetMapSource: nmSrc,
|
|
||||||
},
|
|
||||||
reputationcommon.WithLogger(c.log),
|
|
||||||
)
|
|
||||||
|
|
||||||
localRouteBuilder := localroutes.New(
|
|
||||||
localroutes.Prm{
|
|
||||||
ManagerBuilder: managerBuilder,
|
|
||||||
Log: localTrustLogger,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
localTrustRouter := createLocalTrustRouter(c, localRouteBuilder, localTrustLogger, daughterStorage)
|
|
||||||
|
|
||||||
intermediateTrustRouter := createIntermediateTrustRouter(c, consumerStorage, managerBuilder)
|
|
||||||
|
|
||||||
eigenTrustController := createEigenTrustController(c, intermediateTrustRouter, localKey, wrap, daughterStorage, consumerStorage)
|
|
||||||
|
|
||||||
c.cfgReputation.localTrustCtrl = createLocalTrustController(c, localTrustLogger, localKey, localTrustRouter)
|
|
||||||
|
|
||||||
addReputationReportHandler(ctx, c)
|
|
||||||
|
|
||||||
server := grpcreputation.New(
|
|
||||||
reputationrpc.NewSignService(
|
|
||||||
&c.key.PrivateKey,
|
|
||||||
reputationrpc.NewResponseService(
|
|
||||||
&reputationServer{
|
|
||||||
cfg: c,
|
|
||||||
log: c.log,
|
|
||||||
localRouter: localTrustRouter,
|
|
||||||
intermediateRouter: intermediateTrustRouter,
|
|
||||||
routeBuilder: localRouteBuilder,
|
|
||||||
},
|
|
||||||
c.respSvc,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, srv := range c.cfgGRPC.servers {
|
|
||||||
v2reputationgrpc.RegisterReputationServiceServer(srv, server)
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize eigen trust block timer
|
|
||||||
newEigenTrustIterTimer(c)
|
|
||||||
|
|
||||||
addEigenTrustEpochHandler(ctx, c, eigenTrustController)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addReputationReportHandler(ctx context.Context, c *cfg) {
|
|
||||||
addNewEpochAsyncNotificationHandler(
|
|
||||||
c,
|
|
||||||
func(ev event.Event) {
|
|
||||||
c.log.Debug(logs.FrostFSNodeStartReportingReputationOnNewEpochEvent)
|
|
||||||
|
|
||||||
var reportPrm localtrustcontroller.ReportPrm
|
|
||||||
|
|
||||||
// report collected values from previous epoch
|
|
||||||
reportPrm.SetEpoch(ev.(netmap.NewEpoch).EpochNumber() - 1)
|
|
||||||
|
|
||||||
c.cfgReputation.localTrustCtrl.Report(ctx, reportPrm)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addEigenTrustEpochHandler(ctx context.Context, c *cfg, eigenTrustController *eigentrustctrl.Controller) {
|
|
||||||
addNewEpochAsyncNotificationHandler(
|
|
||||||
c,
|
|
||||||
func(e event.Event) {
|
|
||||||
epoch := e.(netmap.NewEpoch).EpochNumber()
|
|
||||||
|
|
||||||
log := c.log.With(zap.Uint64("epoch", epoch))
|
|
||||||
|
|
||||||
duration, err := c.cfgNetmap.wrapper.EpochDuration()
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.FrostFSNodeCouldNotFetchEpochDuration, zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
iterations, err := c.cfgNetmap.wrapper.EigenTrustIterations()
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.FrostFSNodeCouldNotFetchIterationNumber, zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
epochTimer, err := ticker.NewIterationsTicker(duration, iterations, func() {
|
|
||||||
eigenTrustController.Continue(ctx,
|
|
||||||
eigentrustctrl.ContinuePrm{
|
|
||||||
Epoch: epoch - 1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.FrostFSNodeCouldNotCreateFixedEpochTimer, zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cfgMorph.eigenTrustTicker.addEpochTimer(epoch, epochTimer)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createLocalTrustRouter(c *cfg, localRouteBuilder *localroutes.Builder, localTrustLogger *logger.Logger, daughterStorage *daughters.Storage) *reputationrouter.Router {
|
|
||||||
// storing received daughter(of current node) trusts as a manager
|
|
||||||
daughterStorageWriterProvider := &intermediatereputation.DaughterStorageWriterProvider{
|
|
||||||
Log: c.log,
|
|
||||||
Storage: daughterStorage,
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteLocalTrustProvider := common.NewRemoteTrustProvider(
|
|
||||||
common.RemoteProviderPrm{
|
|
||||||
NetmapKeys: c,
|
|
||||||
DeadEndProvider: daughterStorageWriterProvider,
|
|
||||||
ClientCache: c.bgClientCache,
|
|
||||||
WriterProvider: localreputation.NewRemoteProvider(
|
|
||||||
localreputation.RemoteProviderPrm{
|
|
||||||
Key: &c.key.PrivateKey,
|
|
||||||
Log: localTrustLogger,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Log: localTrustLogger,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
localTrustRouter := reputationrouter.New(
|
|
||||||
reputationrouter.Prm{
|
|
||||||
LocalServerInfo: c,
|
|
||||||
RemoteWriterProvider: remoteLocalTrustProvider,
|
|
||||||
Builder: localRouteBuilder,
|
|
||||||
},
|
|
||||||
reputationrouter.WithLogger(localTrustLogger))
|
|
||||||
return localTrustRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
func createIntermediateTrustRouter(c *cfg, consumerStorage *consumerstorage.Storage, managerBuilder reputationcommon.ManagerBuilder) *reputationrouter.Router {
|
|
||||||
intermediateTrustLogger := &logger.Logger{Logger: c.log.With(zap.String("trust_type", "intermediate"))}
|
|
||||||
|
|
||||||
consumerStorageWriterProvider := &intermediatereputation.ConsumerStorageWriterProvider{
|
|
||||||
Log: c.log,
|
|
||||||
Storage: consumerStorage,
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteIntermediateTrustProvider := common.NewRemoteTrustProvider(
|
|
||||||
common.RemoteProviderPrm{
|
|
||||||
NetmapKeys: c,
|
|
||||||
DeadEndProvider: consumerStorageWriterProvider,
|
|
||||||
ClientCache: c.bgClientCache,
|
|
||||||
WriterProvider: intermediatereputation.NewRemoteProvider(
|
|
||||||
intermediatereputation.RemoteProviderPrm{
|
|
||||||
Key: &c.key.PrivateKey,
|
|
||||||
Log: intermediateTrustLogger,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Log: intermediateTrustLogger,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
intermediateRouteBuilder := intermediateroutes.New(
|
|
||||||
intermediateroutes.Prm{
|
|
||||||
ManagerBuilder: managerBuilder,
|
|
||||||
Log: intermediateTrustLogger,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
intermediateTrustRouter := reputationrouter.New(
|
|
||||||
reputationrouter.Prm{
|
|
||||||
LocalServerInfo: c,
|
|
||||||
RemoteWriterProvider: remoteIntermediateTrustProvider,
|
|
||||||
Builder: intermediateRouteBuilder,
|
|
||||||
},
|
|
||||||
reputationrouter.WithLogger(intermediateTrustLogger),
|
|
||||||
)
|
|
||||||
return intermediateTrustRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
func createEigenTrustController(c *cfg, intermediateTrustRouter *reputationrouter.Router, localKey []byte, wrap *repClient.Client,
|
|
||||||
daughterStorage *daughters.Storage, consumerStorage *consumerstorage.Storage) *eigentrustctrl.Controller {
|
|
||||||
eigenTrustCalculator := eigentrustcalc.New(
|
|
||||||
eigentrustcalc.Prm{
|
|
||||||
AlphaProvider: c.cfgNetmap.wrapper,
|
|
||||||
InitialTrustSource: intermediatereputation.InitialTrustSource{
|
|
||||||
NetMap: c.netMapSource,
|
|
||||||
},
|
|
||||||
IntermediateValueTarget: intermediateTrustRouter,
|
|
||||||
WorkerPool: c.cfgReputation.workerPool,
|
|
||||||
FinalResultTarget: intermediatereputation.NewFinalWriterProvider(
|
|
||||||
intermediatereputation.FinalWriterProviderPrm{
|
|
||||||
PrivatKey: &c.key.PrivateKey,
|
|
||||||
PubKey: localKey,
|
|
||||||
Client: wrap,
|
|
||||||
},
|
|
||||||
intermediatereputation.FinalWriterWithLogger(c.log),
|
|
||||||
),
|
|
||||||
DaughterTrustSource: &intermediatereputation.DaughterTrustIteratorProvider{
|
|
||||||
DaughterStorage: daughterStorage,
|
|
||||||
ConsumerStorage: consumerStorage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
eigentrustcalc.WithLogger(c.log),
|
|
||||||
)
|
|
||||||
|
|
||||||
eigenTrustController := eigentrustctrl.New(
|
|
||||||
eigentrustctrl.Prm{
|
|
||||||
DaughtersTrustCalculator: &intermediatereputation.DaughtersTrustCalculator{
|
|
||||||
Calculator: eigenTrustCalculator,
|
|
||||||
},
|
|
||||||
IterationsProvider: c.cfgNetmap.wrapper,
|
|
||||||
WorkerPool: c.cfgReputation.workerPool,
|
|
||||||
},
|
|
||||||
eigentrustctrl.WithLogger(c.log),
|
|
||||||
)
|
|
||||||
return eigenTrustController
|
|
||||||
}
|
|
||||||
|
|
||||||
func createLocalTrustController(c *cfg, localTrustLogger *logger.Logger, localKey []byte, localTrustRouter *reputationrouter.Router) *localtrustcontroller.Controller {
|
|
||||||
localTrustStorage := &localreputation.TrustStorage{
|
|
||||||
Log: localTrustLogger,
|
|
||||||
Storage: c.cfgReputation.localTrustStorage,
|
|
||||||
NmSrc: c.netMapSource,
|
|
||||||
LocalKey: localKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
return localtrustcontroller.New(
|
|
||||||
localtrustcontroller.Prm{
|
|
||||||
LocalTrustSource: localTrustStorage,
|
|
||||||
LocalTrustTarget: localTrustRouter,
|
|
||||||
},
|
|
||||||
localtrustcontroller.WithLogger(c.log),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type reputationServer struct {
|
|
||||||
*cfg
|
|
||||||
log *logger.Logger
|
|
||||||
localRouter *reputationrouter.Router
|
|
||||||
intermediateRouter *reputationrouter.Router
|
|
||||||
routeBuilder reputationrouter.Builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *reputationServer) AnnounceLocalTrust(ctx context.Context, req *v2reputation.AnnounceLocalTrustRequest) (*v2reputation.AnnounceLocalTrustResponse, error) {
|
|
||||||
passedRoute := reverseRoute(req.GetVerificationHeader())
|
|
||||||
passedRoute = append(passedRoute, s)
|
|
||||||
|
|
||||||
body := req.GetBody()
|
|
||||||
|
|
||||||
ep := &common.EpochProvider{
|
|
||||||
E: body.GetEpoch(),
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := s.localRouter.InitWriter(reputationrouter.NewRouteInfo(ep, passedRoute))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not initialize local trust writer: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, trust := range body.GetTrusts() {
|
|
||||||
err = s.processLocalTrust(ctx, body.GetEpoch(), apiToLocalTrust(&trust, passedRoute[0].PublicKey()), passedRoute, w)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not write one of local trusts: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := new(v2reputation.AnnounceLocalTrustResponse)
|
|
||||||
resp.SetBody(new(v2reputation.AnnounceLocalTrustResponseBody))
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *reputationServer) AnnounceIntermediateResult(ctx context.Context, req *v2reputation.AnnounceIntermediateResultRequest) (*v2reputation.AnnounceIntermediateResultResponse, error) {
|
|
||||||
passedRoute := reverseRoute(req.GetVerificationHeader())
|
|
||||||
passedRoute = append(passedRoute, s)
|
|
||||||
|
|
||||||
body := req.GetBody()
|
|
||||||
|
|
||||||
ei := eigentrust.NewEpochIteration(body.GetEpoch(), body.GetIteration())
|
|
||||||
|
|
||||||
w, err := s.intermediateRouter.InitWriter(reputationrouter.NewRouteInfo(ei, passedRoute))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not initialize trust writer: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
v2Trust := body.GetTrust()
|
|
||||||
|
|
||||||
trust := apiToLocalTrust(v2Trust.GetTrust(), v2Trust.GetTrustingPeer().GetPublicKey())
|
|
||||||
|
|
||||||
err = w.Write(ctx, trust)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not write trust: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := new(v2reputation.AnnounceIntermediateResultResponse)
|
|
||||||
resp.SetBody(new(v2reputation.AnnounceIntermediateResultResponseBody))
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *reputationServer) processLocalTrust(ctx context.Context, epoch uint64, t reputation.Trust,
|
|
||||||
passedRoute []reputationcommon.ServerInfo, w reputationcommon.Writer) error {
|
|
||||||
err := reputationrouter.CheckRoute(s.routeBuilder, epoch, t, passedRoute)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("wrong route of reputation trust value: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Write(ctx, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// apiToLocalTrust converts v2 Trust to local reputation.Trust, adding trustingPeer.
|
|
||||||
func apiToLocalTrust(t *v2reputation.Trust, trustingPeer []byte) reputation.Trust {
|
|
||||||
var trusted, trusting apireputation.PeerID
|
|
||||||
trusted.SetPublicKey(t.GetPeer().GetPublicKey())
|
|
||||||
trusting.SetPublicKey(trustingPeer)
|
|
||||||
|
|
||||||
localTrust := reputation.Trust{}
|
|
||||||
|
|
||||||
localTrust.SetValue(reputation.TrustValueFromFloat64(t.GetValue()))
|
|
||||||
localTrust.SetPeer(trusted)
|
|
||||||
localTrust.SetTrustingPeer(trusting)
|
|
||||||
|
|
||||||
return localTrust
|
|
||||||
}
|
|
||||||
|
|
||||||
func reverseRoute(hdr *session.RequestVerificationHeader) (passedRoute []reputationcommon.ServerInfo) {
|
|
||||||
for hdr != nil {
|
|
||||||
passedRoute = append(passedRoute, &common.OnlyKeyRemoteServerInfo{
|
|
||||||
Key: hdr.GetBodySignature().GetKey(),
|
|
||||||
})
|
|
||||||
|
|
||||||
hdr = hdr.GetOrigin()
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
trustcontroller "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/controller"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clientCache interface {
|
|
||||||
Get(client.NodeInfo) (client.Client, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientKeyRemoteProvider must provide a remote writer and take into account
|
|
||||||
// that requests must be sent via the passed api client and must be signed with
|
|
||||||
// the passed private key.
|
|
||||||
type clientKeyRemoteProvider interface {
|
|
||||||
WithClient(client.Client) reputationcommon.WriterProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteTrustProvider is an implementation of reputation RemoteWriterProvider interface.
|
|
||||||
// It caches clients, checks if it is the end of the route and checks either the current
|
|
||||||
// node is a remote target or not.
|
|
||||||
//
|
|
||||||
// remoteTrustProvider requires to be provided with clientKeyRemoteProvider.
|
|
||||||
type RemoteTrustProvider struct {
|
|
||||||
netmapKeys netmap.AnnouncedKeys
|
|
||||||
deadEndProvider reputationcommon.WriterProvider
|
|
||||||
clientCache clientCache
|
|
||||||
remoteProvider clientKeyRemoteProvider
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteProviderPrm groups the required parameters of the remoteTrustProvider's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type RemoteProviderPrm struct {
|
|
||||||
NetmapKeys netmap.AnnouncedKeys
|
|
||||||
DeadEndProvider reputationcommon.WriterProvider
|
|
||||||
ClientCache clientCache
|
|
||||||
WriterProvider clientKeyRemoteProvider
|
|
||||||
Log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRemoteTrustProvider(prm RemoteProviderPrm) *RemoteTrustProvider {
|
|
||||||
switch {
|
|
||||||
case prm.NetmapKeys == nil:
|
|
||||||
PanicOnPrmValue("NetmapKeys", prm.NetmapKeys)
|
|
||||||
case prm.DeadEndProvider == nil:
|
|
||||||
PanicOnPrmValue("DeadEndProvider", prm.DeadEndProvider)
|
|
||||||
case prm.ClientCache == nil:
|
|
||||||
PanicOnPrmValue("ClientCache", prm.ClientCache)
|
|
||||||
case prm.WriterProvider == nil:
|
|
||||||
PanicOnPrmValue("WriterProvider", prm.WriterProvider)
|
|
||||||
case prm.Log == nil:
|
|
||||||
PanicOnPrmValue("Logger", prm.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RemoteTrustProvider{
|
|
||||||
netmapKeys: prm.NetmapKeys,
|
|
||||||
deadEndProvider: prm.DeadEndProvider,
|
|
||||||
clientCache: prm.ClientCache,
|
|
||||||
remoteProvider: prm.WriterProvider,
|
|
||||||
log: prm.Log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rtp *RemoteTrustProvider) InitRemote(srv reputationcommon.ServerInfo) (reputationcommon.WriterProvider, error) {
|
|
||||||
rtp.log.Debug(logs.CommonInitializingRemoteWriterProvider)
|
|
||||||
|
|
||||||
if srv == nil {
|
|
||||||
rtp.log.Debug(logs.CommonRouteHasReachedDeadendProvider)
|
|
||||||
return rtp.deadEndProvider, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if rtp.netmapKeys.IsLocalKey(srv.PublicKey()) {
|
|
||||||
// if local => return no-op writer
|
|
||||||
rtp.log.Debug(logs.CommonInitializingNoopWriterProvider)
|
|
||||||
return trustcontroller.SimpleWriterProvider(new(NopReputationWriter)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var info client.NodeInfo
|
|
||||||
|
|
||||||
err := client.NodeInfoFromRawNetmapElement(&info, srv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parse client node info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := rtp.clientCache.Get(info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not initialize API client: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtp.remoteProvider.WithClient(c), nil
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EpochProvider struct {
|
|
||||||
E uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ep *EpochProvider) Epoch() uint64 {
|
|
||||||
return ep.E
|
|
||||||
}
|
|
||||||
|
|
||||||
type NopReputationWriter struct{}
|
|
||||||
|
|
||||||
func (NopReputationWriter) Write(context.Context, reputation.Trust) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopReputationWriter) Close(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnlyKeyRemoteServerInfo is an implementation of reputation.ServerInfo
|
|
||||||
// interface but with only public key data.
|
|
||||||
type OnlyKeyRemoteServerInfo struct {
|
|
||||||
Key []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *OnlyKeyRemoteServerInfo) PublicKey() []byte {
|
|
||||||
return i.Key
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OnlyKeyRemoteServerInfo) IterateAddresses(func(string) bool) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OnlyKeyRemoteServerInfo) NumberOfAddresses() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*OnlyKeyRemoteServerInfo) ExternalAddresses() []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func PanicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
eigencalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
eigentrustctrl "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/controller"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitialTrustSource is an implementation of the
|
|
||||||
// reputation/eigentrust/calculator's InitialTrustSource interface.
|
|
||||||
type InitialTrustSource struct {
|
|
||||||
NetMap netmap.Source
|
|
||||||
}
|
|
||||||
|
|
||||||
var ErrEmptyNetMap = errors.New("empty NepMap")
|
|
||||||
|
|
||||||
// InitialTrust returns `initialTrust` as an initial trust value.
|
|
||||||
func (i InitialTrustSource) InitialTrust(apireputation.PeerID) (reputation.TrustValue, error) {
|
|
||||||
nm, err := i.NetMap.GetNetMap(1)
|
|
||||||
if err != nil {
|
|
||||||
return reputation.TrustZero, fmt.Errorf("failed to get NetMap: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeCount := reputation.TrustValueFromFloat64(float64(len(nm.Nodes())))
|
|
||||||
if nodeCount == 0 {
|
|
||||||
return reputation.TrustZero, ErrEmptyNetMap
|
|
||||||
}
|
|
||||||
|
|
||||||
return reputation.TrustOne.Div(nodeCount), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughtersTrustCalculator wraps EigenTrust calculator and implements the
|
|
||||||
// eigentrust/calculator's DaughtersTrustCalculator interface.
|
|
||||||
type DaughtersTrustCalculator struct {
|
|
||||||
Calculator *eigencalc.Calculator
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate converts and passes values to the wrapped calculator.
|
|
||||||
func (c *DaughtersTrustCalculator) Calculate(ctx context.Context, iterCtx eigentrustctrl.IterationContext) {
|
|
||||||
calcPrm := eigencalc.CalculatePrm{}
|
|
||||||
epochIteration := eigentrust.EpochIteration{}
|
|
||||||
|
|
||||||
epochIteration.SetEpoch(iterCtx.Epoch())
|
|
||||||
epochIteration.SetI(iterCtx.I())
|
|
||||||
|
|
||||||
calcPrm.SetLast(iterCtx.Last())
|
|
||||||
calcPrm.SetEpochIteration(epochIteration)
|
|
||||||
|
|
||||||
c.Calculator.Calculate(ctx, calcPrm)
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
eigencalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
consumerstorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/consumers"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrIncorrectContextPanicMsg = "could not write intermediate trust: passed context incorrect"
|
|
||||||
|
|
||||||
// ConsumerStorageWriterProvider is an implementation of the reputation.WriterProvider
|
|
||||||
// interface that provides ConsumerTrustWriter writer.
|
|
||||||
type ConsumerStorageWriterProvider struct {
|
|
||||||
Log *logger.Logger
|
|
||||||
Storage *consumerstorage.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConsumerTrustWriter is an implementation of the reputation.Writer interface
|
|
||||||
// that writes passed consumer's Trust values to the Consumer storage. After writing
|
|
||||||
// that, values can be used in eigenTrust algorithm's iterations.
|
|
||||||
type ConsumerTrustWriter struct {
|
|
||||||
log *logger.Logger
|
|
||||||
storage *consumerstorage.Storage
|
|
||||||
iterInfo eigencalc.EpochIterationInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ConsumerTrustWriter) Write(_ context.Context, t reputation.Trust) error {
|
|
||||||
w.log.Debug(logs.IntermediateWritingReceivedConsumersTrusts,
|
|
||||||
zap.Uint64("epoch", w.iterInfo.Epoch()),
|
|
||||||
zap.Uint32("iteration", w.iterInfo.I()),
|
|
||||||
zap.Stringer("trusting_peer", t.TrustingPeer()),
|
|
||||||
zap.Stringer("trusted_peer", t.Peer()),
|
|
||||||
)
|
|
||||||
|
|
||||||
trust := eigentrust.IterationTrust{Trust: t}
|
|
||||||
|
|
||||||
trust.SetEpoch(w.iterInfo.Epoch())
|
|
||||||
trust.SetI(w.iterInfo.I())
|
|
||||||
|
|
||||||
w.storage.Put(trust)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ConsumerTrustWriter) Close(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsumerStorageWriterProvider) InitWriter(ep reputationcommon.EpochProvider) (reputationcommon.Writer, error) {
|
|
||||||
iterInfo, ok := ep.(eigencalc.EpochIterationInfo)
|
|
||||||
if !ok {
|
|
||||||
panic(ErrIncorrectContextPanicMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ConsumerTrustWriter{
|
|
||||||
log: s.Log,
|
|
||||||
storage: s.Storage,
|
|
||||||
iterInfo: iterInfo,
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
repClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FinalWriterProviderPrm groups the required parameters of the FinalWriterProvider's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type FinalWriterProviderPrm struct {
|
|
||||||
PrivatKey *ecdsa.PrivateKey
|
|
||||||
PubKey []byte
|
|
||||||
Client *repClient.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFinalWriterProvider creates a new instance of the FinalWriterProvider.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created FinalWriterProvider does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func NewFinalWriterProvider(prm FinalWriterProviderPrm, opts ...FinalWriterOption) *FinalWriterProvider {
|
|
||||||
o := defaultFinalWriterOptionsOpts()
|
|
||||||
|
|
||||||
for i := range opts {
|
|
||||||
opts[i](o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &FinalWriterProvider{
|
|
||||||
prm: prm,
|
|
||||||
opts: o,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FinalWriterProvider is an implementation of the reputation.eigentrust.calculator
|
|
||||||
// IntermediateWriterProvider interface. It inits FinalWriter.
|
|
||||||
type FinalWriterProvider struct {
|
|
||||||
prm FinalWriterProviderPrm
|
|
||||||
opts *finalWriterOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fwp FinalWriterProvider) InitIntermediateWriter(
|
|
||||||
_ eigentrustcalc.EpochIterationInfo) (eigentrustcalc.IntermediateWriter, error) {
|
|
||||||
return &FinalWriter{
|
|
||||||
privatKey: fwp.prm.PrivatKey,
|
|
||||||
pubKey: fwp.prm.PubKey,
|
|
||||||
client: fwp.prm.Client,
|
|
||||||
l: fwp.opts.log,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FinalWriter is an implementation of the reputation.eigentrust.calculator IntermediateWriter
|
|
||||||
// interface that writes GlobalTrust to contract directly.
|
|
||||||
type FinalWriter struct {
|
|
||||||
privatKey *ecdsa.PrivateKey
|
|
||||||
pubKey []byte
|
|
||||||
client *repClient.Client
|
|
||||||
|
|
||||||
l *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fw FinalWriter) WriteIntermediateTrust(t eigentrust.IterationTrust) error {
|
|
||||||
fw.l.Debug(logs.IntermediateStartWritingGlobalTrustsToContract)
|
|
||||||
|
|
||||||
args := repClient.PutPrm{}
|
|
||||||
|
|
||||||
apiTrustedPeerID := t.Peer()
|
|
||||||
|
|
||||||
var apiTrust apireputation.Trust
|
|
||||||
apiTrust.SetValue(t.Value().Float64())
|
|
||||||
apiTrust.SetPeer(t.Peer())
|
|
||||||
|
|
||||||
var managerPublicKey [33]byte
|
|
||||||
copy(managerPublicKey[:], fw.pubKey)
|
|
||||||
|
|
||||||
var apiMangerPeerID apireputation.PeerID
|
|
||||||
apiMangerPeerID.SetPublicKey(managerPublicKey[:])
|
|
||||||
|
|
||||||
var gTrust apireputation.GlobalTrust
|
|
||||||
gTrust.SetTrust(apiTrust)
|
|
||||||
gTrust.SetManager(apiMangerPeerID)
|
|
||||||
|
|
||||||
err := gTrust.Sign(frostfsecdsa.Signer(*fw.privatKey))
|
|
||||||
if err != nil {
|
|
||||||
fw.l.Debug(
|
|
||||||
"failed to sign global trust",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return fmt.Errorf("failed to sign global trust: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
args.SetEpoch(t.Epoch())
|
|
||||||
args.SetValue(gTrust)
|
|
||||||
args.SetPeerID(apiTrustedPeerID)
|
|
||||||
|
|
||||||
err = fw.client.Put(
|
|
||||||
args,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
fw.l.Debug(
|
|
||||||
"failed to write global trust to contract",
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return fmt.Errorf("failed to write global trust to contract: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fw.l.Debug(
|
|
||||||
"sent global trust to contract",
|
|
||||||
zap.Uint64("epoch", t.Epoch()),
|
|
||||||
zap.Float64("value", t.Value().Float64()),
|
|
||||||
zap.Stringer("peer", t.Peer()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type finalWriterOptions struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type FinalWriterOption func(*finalWriterOptions)
|
|
||||||
|
|
||||||
func defaultFinalWriterOptionsOpts() *finalWriterOptions {
|
|
||||||
return &finalWriterOptions{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FinalWriterWithLogger(l *logger.Logger) FinalWriterOption {
|
|
||||||
return func(o *finalWriterOptions) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/daughters"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DaughterStorageWriterProvider is an implementation of the reputation.WriterProvider
|
|
||||||
// interface that provides DaughterTrustWriter writer.
|
|
||||||
type DaughterStorageWriterProvider struct {
|
|
||||||
Log *logger.Logger
|
|
||||||
Storage *daughters.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughterTrustWriter is an implementation of the reputation.Writer interface
|
|
||||||
// that writes passed daughter's Trust values to Daughter storage. After writing
|
|
||||||
// that, values can be used in eigenTrust algorithm's iterations.
|
|
||||||
type DaughterTrustWriter struct {
|
|
||||||
log *logger.Logger
|
|
||||||
storage *daughters.Storage
|
|
||||||
ep reputationcommon.EpochProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *DaughterTrustWriter) Write(_ context.Context, t reputation.Trust) error {
|
|
||||||
w.log.Debug(logs.IntermediateWritingReceivedDaughtersTrusts,
|
|
||||||
zap.Uint64("epoch", w.ep.Epoch()),
|
|
||||||
zap.Stringer("trusting_peer", t.TrustingPeer()),
|
|
||||||
zap.Stringer("trusted_peer", t.Peer()),
|
|
||||||
)
|
|
||||||
|
|
||||||
w.storage.Put(w.ep.Epoch(), t)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *DaughterTrustWriter) Close(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DaughterStorageWriterProvider) InitWriter(ep reputationcommon.EpochProvider) (reputationcommon.Writer, error) {
|
|
||||||
return &DaughterTrustWriter{
|
|
||||||
log: s.Log,
|
|
||||||
storage: s.Storage,
|
|
||||||
ep: ep,
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/common"
|
|
||||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/internal/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
coreclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
reputationapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RemoteProviderPrm groups the required parameters of the RemoteProvider's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type RemoteProviderPrm struct {
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
Log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRemoteProvider creates a new instance of the RemoteProvider.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created RemoteProvider does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func NewRemoteProvider(prm RemoteProviderPrm) *RemoteProvider {
|
|
||||||
switch {
|
|
||||||
case prm.Key == nil:
|
|
||||||
common.PanicOnPrmValue("NetMapSource", prm.Key)
|
|
||||||
case prm.Log == nil:
|
|
||||||
common.PanicOnPrmValue("Logger", prm.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RemoteProvider{
|
|
||||||
key: prm.Key,
|
|
||||||
log: prm.Log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteProvider is an implementation of the clientKeyRemoteProvider interface.
|
|
||||||
type RemoteProvider struct {
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp RemoteProvider) WithClient(c coreclient.Client) reputationcommon.WriterProvider {
|
|
||||||
return &TrustWriterProvider{
|
|
||||||
client: c,
|
|
||||||
key: rp.key,
|
|
||||||
log: rp.log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TrustWriterProvider struct {
|
|
||||||
client coreclient.Client
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (twp *TrustWriterProvider) InitWriter(ep reputationcommon.EpochProvider) (reputationcommon.Writer, error) {
|
|
||||||
iterInfo, ok := ep.(eigentrustcalc.EpochIterationInfo)
|
|
||||||
if !ok {
|
|
||||||
// TODO: #1164 think if this can be done without such limitation
|
|
||||||
panic(ErrIncorrectContextPanicMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RemoteTrustWriter{
|
|
||||||
iterInfo: iterInfo,
|
|
||||||
client: twp.client,
|
|
||||||
key: twp.key,
|
|
||||||
log: twp.log,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RemoteTrustWriter struct {
|
|
||||||
iterInfo eigentrustcalc.EpochIterationInfo
|
|
||||||
client coreclient.Client
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write sends a trust value to a remote node via ReputationService.AnnounceIntermediateResult RPC.
|
|
||||||
func (rtp *RemoteTrustWriter) Write(ctx context.Context, t reputation.Trust) error {
|
|
||||||
epoch := rtp.iterInfo.Epoch()
|
|
||||||
i := rtp.iterInfo.I()
|
|
||||||
|
|
||||||
rtp.log.Debug(logs.IntermediateAnnouncingTrust,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
zap.Uint32("iteration", i),
|
|
||||||
zap.Stringer("trusting_peer", t.TrustingPeer()),
|
|
||||||
zap.Stringer("trusted_peer", t.Peer()),
|
|
||||||
)
|
|
||||||
|
|
||||||
var apiTrust reputationapi.Trust
|
|
||||||
apiTrust.SetValue(t.Value().Float64())
|
|
||||||
apiTrust.SetPeer(t.Peer())
|
|
||||||
|
|
||||||
var apiPeerToPeerTrust reputationapi.PeerToPeerTrust
|
|
||||||
apiPeerToPeerTrust.SetTrustingPeer(t.TrustingPeer())
|
|
||||||
apiPeerToPeerTrust.SetTrust(apiTrust)
|
|
||||||
|
|
||||||
var p internalclient.AnnounceIntermediatePrm
|
|
||||||
|
|
||||||
p.SetClient(rtp.client)
|
|
||||||
p.SetEpoch(epoch)
|
|
||||||
p.SetIteration(i)
|
|
||||||
p.SetTrust(apiPeerToPeerTrust)
|
|
||||||
|
|
||||||
_, err := internalclient.AnnounceIntermediate(ctx, p)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rtp *RemoteTrustWriter) Close(context.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package intermediate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
consumerstorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/consumers"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/storage/daughters"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DaughterTrustIteratorProvider is an implementation of the
|
|
||||||
// reputation/eigentrust/calculator's DaughterTrustIteratorProvider interface.
|
|
||||||
type DaughterTrustIteratorProvider struct {
|
|
||||||
DaughterStorage *daughters.Storage
|
|
||||||
ConsumerStorage *consumerstorage.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitDaughterIterator returns an iterator over the received
|
|
||||||
// local trusts for ctx.Epoch() epoch from daughter p.
|
|
||||||
func (ip *DaughterTrustIteratorProvider) InitDaughterIterator(ctx eigentrustcalc.EpochIterationInfo,
|
|
||||||
p apireputation.PeerID) (eigentrustcalc.TrustIterator, error) {
|
|
||||||
epoch := ctx.Epoch()
|
|
||||||
|
|
||||||
daughterIterator, ok := ip.DaughterStorage.DaughterTrusts(epoch, p)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no data in %d epoch for daughter: %s", epoch, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
return daughterIterator, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitAllDaughtersIterator returns an iterator over all
|
|
||||||
// daughters of the current node(manager) and all local
|
|
||||||
// trusts received from them for ctx.Epoch() epoch.
|
|
||||||
func (ip *DaughterTrustIteratorProvider) InitAllDaughtersIterator(
|
|
||||||
ctx eigentrustcalc.EpochIterationInfo) (eigentrustcalc.PeerTrustsIterator, error) {
|
|
||||||
epoch := ctx.Epoch()
|
|
||||||
|
|
||||||
iter, ok := ip.DaughterStorage.AllDaughterTrusts(epoch)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no data in %d epoch for daughters", epoch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return iter, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitConsumersIterator returns an iterator over all daughters
|
|
||||||
// of the current node(manager) and all their consumers' local
|
|
||||||
// trusts for ctx.Epoch() epoch and ctx.I() iteration.
|
|
||||||
func (ip *DaughterTrustIteratorProvider) InitConsumersIterator(
|
|
||||||
ctx eigentrustcalc.EpochIterationInfo) (eigentrustcalc.PeerTrustsIterator, error) {
|
|
||||||
epoch, iter := ctx.Epoch(), ctx.I()
|
|
||||||
|
|
||||||
consumerIterator, ok := ip.ConsumerStorage.Consumers(epoch, iter)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no data for %d iteration in %d epoch for consumers's trusts",
|
|
||||||
iter,
|
|
||||||
epoch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumerIterator, nil
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
coreclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type commonPrm struct {
|
|
||||||
cli coreclient.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetClient sets the base client for FrostFS API communication.
|
|
||||||
//
|
|
||||||
// Required parameter.
|
|
||||||
func (x *commonPrm) SetClient(cli coreclient.Client) {
|
|
||||||
x.cli = cli
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnnounceLocalPrm groups parameters of AnnounceLocal operation.
|
|
||||||
type AnnounceLocalPrm struct {
|
|
||||||
commonPrm
|
|
||||||
|
|
||||||
cliPrm client.PrmAnnounceLocalTrust
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEpoch sets the epoch in which the trust was assessed.
|
|
||||||
func (x *AnnounceLocalPrm) SetEpoch(epoch uint64) {
|
|
||||||
x.cliPrm.SetEpoch(epoch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTrusts sets a list of local trust values.
|
|
||||||
func (x *AnnounceLocalPrm) SetTrusts(ts []reputation.Trust) {
|
|
||||||
x.cliPrm.SetValues(ts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnnounceLocalRes groups the resulting values of AnnounceLocal operation.
|
|
||||||
type AnnounceLocalRes struct{}
|
|
||||||
|
|
||||||
// AnnounceLocal sends estimations of local trust to the remote node.
|
|
||||||
//
|
|
||||||
// Client, context and key must be set.
|
|
||||||
//
|
|
||||||
// Returns any error which prevented the operation from completing correctly in error return.
|
|
||||||
func AnnounceLocal(ctx context.Context, prm AnnounceLocalPrm) (res AnnounceLocalRes, err error) {
|
|
||||||
var cliRes *client.ResAnnounceLocalTrust
|
|
||||||
|
|
||||||
cliRes, err = prm.cli.AnnounceLocalTrust(ctx, prm.cliPrm)
|
|
||||||
if err == nil {
|
|
||||||
// pull out an error from status
|
|
||||||
err = apistatus.ErrFromStatus(cliRes.Status())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnnounceIntermediatePrm groups parameters of AnnounceIntermediate operation.
|
|
||||||
type AnnounceIntermediatePrm struct {
|
|
||||||
commonPrm
|
|
||||||
|
|
||||||
cliPrm client.PrmAnnounceIntermediateTrust
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEpoch sets the number of the epoch when the trust calculation's iteration was executed.
|
|
||||||
func (x *AnnounceIntermediatePrm) SetEpoch(epoch uint64) {
|
|
||||||
x.cliPrm.SetEpoch(epoch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetIteration sets the number of the iteration of the trust calculation algorithm.
|
|
||||||
func (x *AnnounceIntermediatePrm) SetIteration(iter uint32) {
|
|
||||||
x.cliPrm.SetIteration(iter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTrust sets the current global trust value computed at the iteration.
|
|
||||||
func (x *AnnounceIntermediatePrm) SetTrust(t reputation.PeerToPeerTrust) {
|
|
||||||
x.cliPrm.SetCurrentValue(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnnounceIntermediateRes groups the resulting values of AnnounceIntermediate operation.
|
|
||||||
type AnnounceIntermediateRes struct{}
|
|
||||||
|
|
||||||
// AnnounceIntermediate sends the global trust value calculated at the specified iteration
|
|
||||||
// and epoch to to the remote node.
|
|
||||||
//
|
|
||||||
// Client, context and key must be set.
|
|
||||||
//
|
|
||||||
// Returns any error which prevented the operation from completing correctly in error return.
|
|
||||||
func AnnounceIntermediate(ctx context.Context, prm AnnounceIntermediatePrm) (res AnnounceIntermediateRes, err error) {
|
|
||||||
var cliRes *client.ResAnnounceIntermediateTrust
|
|
||||||
|
|
||||||
cliRes, err = prm.cli.AnnounceIntermediateTrust(ctx, prm.cliPrm)
|
|
||||||
if err == nil {
|
|
||||||
// pull out an error from status
|
|
||||||
err = apistatus.ErrFromStatus(cliRes.Status())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Package internal provides functionality for FrostFS Node Reputation system communication with FrostFS network.
|
|
||||||
// The base client for accessing remote nodes via FrostFS API is a FrostFS SDK Go API client.
|
|
||||||
// However, although it encapsulates a useful piece of business logic (e.g. the signature mechanism),
|
|
||||||
// the Reputation service does not fully use the client's flexible interface.
|
|
||||||
//
|
|
||||||
// In this regard, this package provides functions over base API client necessary for the application.
|
|
||||||
// This allows you to concentrate the entire spectrum of the client's use in one place (this will be convenient
|
|
||||||
// both when updating the base client and for evaluating the UX of SDK library). So, it is expected that all
|
|
||||||
// Reputation service packages will be limited to this package for the development of functionality requiring
|
|
||||||
// FrostFS API communication.
|
|
||||||
package internal
|
|
|
@ -1,113 +0,0 @@
|
||||||
package local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/common"
|
|
||||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/internal/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
coreclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
reputationapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RemoteProviderPrm groups the required parameters of the RemoteProvider's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type RemoteProviderPrm struct {
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
Log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRemoteProvider creates a new instance of the RemoteProvider.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created RemoteProvider does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func NewRemoteProvider(prm RemoteProviderPrm) *RemoteProvider {
|
|
||||||
switch {
|
|
||||||
case prm.Key == nil:
|
|
||||||
common.PanicOnPrmValue("NetMapSource", prm.Key)
|
|
||||||
case prm.Log == nil:
|
|
||||||
common.PanicOnPrmValue("Logger", prm.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RemoteProvider{
|
|
||||||
key: prm.Key,
|
|
||||||
log: prm.Log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteProvider is an implementation of the clientKeyRemoteProvider interface.
|
|
||||||
type RemoteProvider struct {
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp RemoteProvider) WithClient(c coreclient.Client) reputationcommon.WriterProvider {
|
|
||||||
return &TrustWriterProvider{
|
|
||||||
client: c,
|
|
||||||
key: rp.key,
|
|
||||||
log: rp.log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TrustWriterProvider struct {
|
|
||||||
client coreclient.Client
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (twp *TrustWriterProvider) InitWriter(ep reputationcommon.EpochProvider) (reputationcommon.Writer, error) {
|
|
||||||
return &RemoteTrustWriter{
|
|
||||||
ep: ep,
|
|
||||||
client: twp.client,
|
|
||||||
key: twp.key,
|
|
||||||
log: twp.log,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RemoteTrustWriter struct {
|
|
||||||
ep reputationcommon.EpochProvider
|
|
||||||
client coreclient.Client
|
|
||||||
key *ecdsa.PrivateKey
|
|
||||||
log *logger.Logger
|
|
||||||
|
|
||||||
buf []reputationapi.Trust
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rtp *RemoteTrustWriter) Write(_ context.Context, t reputation.Trust) error {
|
|
||||||
var apiTrust reputationapi.Trust
|
|
||||||
|
|
||||||
apiTrust.SetValue(t.Value().Float64())
|
|
||||||
apiTrust.SetPeer(t.Peer())
|
|
||||||
|
|
||||||
rtp.buf = append(rtp.buf, apiTrust)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rtp *RemoteTrustWriter) Close(ctx context.Context) error {
|
|
||||||
epoch := rtp.ep.Epoch()
|
|
||||||
|
|
||||||
rtp.log.Debug(logs.LocalAnnouncingTrusts,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
)
|
|
||||||
|
|
||||||
var prm internalclient.AnnounceLocalPrm
|
|
||||||
|
|
||||||
prm.SetClient(rtp.client)
|
|
||||||
prm.SetEpoch(epoch)
|
|
||||||
prm.SetTrusts(rtp.buf)
|
|
||||||
|
|
||||||
_, err := internalclient.AnnounceLocal(ctx, prm)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
package local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
netmapcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
trustcontroller "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/controller"
|
|
||||||
truststorage "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/local/storage"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TrustStorage struct {
|
|
||||||
Log *logger.Logger
|
|
||||||
|
|
||||||
Storage *truststorage.Storage
|
|
||||||
|
|
||||||
NmSrc netmapcore.Source
|
|
||||||
|
|
||||||
LocalKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TrustStorage) InitIterator(ep reputationcommon.EpochProvider) (trustcontroller.Iterator, error) {
|
|
||||||
epoch := ep.Epoch()
|
|
||||||
|
|
||||||
s.Log.Debug(logs.LocalInitializingIteratorOverTrusts,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
)
|
|
||||||
|
|
||||||
epochStorage, err := s.Storage.DataForEpoch(epoch)
|
|
||||||
if err != nil && !errors.Is(err, truststorage.ErrNoPositiveTrust) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &TrustIterator{
|
|
||||||
ep: ep,
|
|
||||||
storage: s,
|
|
||||||
epochStorage: epochStorage,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TrustIterator struct {
|
|
||||||
ep reputationcommon.EpochProvider
|
|
||||||
|
|
||||||
storage *TrustStorage
|
|
||||||
|
|
||||||
epochStorage *truststorage.EpochTrustValueStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (it *TrustIterator) Iterate(h reputation.TrustHandler) error {
|
|
||||||
if it.epochStorage != nil {
|
|
||||||
err := it.epochStorage.Iterate(h)
|
|
||||||
if !errors.Is(err, truststorage.ErrNoPositiveTrust) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nm, err := it.storage.NmSrc.GetNetMapByEpoch(it.ep.Epoch())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// find out if local node is presented in netmap
|
|
||||||
localIndex := -1
|
|
||||||
|
|
||||||
nmNodes := nm.Nodes()
|
|
||||||
for i := range nmNodes {
|
|
||||||
if bytes.Equal(nmNodes[i].PublicKey(), it.storage.LocalKey) {
|
|
||||||
localIndex = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ln := len(nmNodes)
|
|
||||||
if localIndex >= 0 && ln > 0 {
|
|
||||||
ln--
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate Pj http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Chapter 4.5.
|
|
||||||
p := reputation.TrustOne.Div(reputation.TrustValueFromInt(ln))
|
|
||||||
|
|
||||||
for i := range nmNodes {
|
|
||||||
if i == localIndex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var trusted, trusting apireputation.PeerID
|
|
||||||
|
|
||||||
trusted.SetPublicKey(nmNodes[i].PublicKey())
|
|
||||||
trusting.SetPublicKey(it.storage.LocalKey)
|
|
||||||
|
|
||||||
trust := reputation.Trust{}
|
|
||||||
trust.SetPeer(trusted)
|
|
||||||
trust.SetValue(p)
|
|
||||||
trust.SetTrustingPeer(trusting)
|
|
||||||
|
|
||||||
if err := h(trust); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package ticker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IterationHandler is a callback of a certain block advance.
|
|
||||||
type IterationHandler func()
|
|
||||||
|
|
||||||
// IterationsTicker represents a fixed tick number block timer.
|
|
||||||
//
|
|
||||||
// It can tick the blocks and perform certain actions
|
|
||||||
// on block time intervals.
|
|
||||||
type IterationsTicker struct {
|
|
||||||
m sync.Mutex
|
|
||||||
|
|
||||||
curr uint64
|
|
||||||
period uint64
|
|
||||||
|
|
||||||
times uint64
|
|
||||||
|
|
||||||
h IterationHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewIterationsTicker creates a new IterationsTicker.
|
|
||||||
//
|
|
||||||
// It guaranties that a handler would be called the
|
|
||||||
// specified amount of times in the specified amount
|
|
||||||
// of blocks. After the last meaningful Tick, IterationsTicker
|
|
||||||
// becomes no-op timer.
|
|
||||||
//
|
|
||||||
// Returns an error only if times is greater than totalBlocks.
|
|
||||||
func NewIterationsTicker(totalBlocks uint64, times uint64, h IterationHandler) (*IterationsTicker, error) {
|
|
||||||
period := totalBlocks / times
|
|
||||||
|
|
||||||
if period == 0 {
|
|
||||||
return nil, fmt.Errorf("impossible to tick %d times in %d blocks",
|
|
||||||
times, totalBlocks,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
var curr uint64
|
|
||||||
|
|
||||||
// try to make handler calls as rare as possible
|
|
||||||
if totalBlocks%times != 0 {
|
|
||||||
extraBlocks := (period+1)*times - totalBlocks
|
|
||||||
|
|
||||||
if period >= extraBlocks {
|
|
||||||
curr = extraBlocks + (period-extraBlocks)/2
|
|
||||||
period++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &IterationsTicker{
|
|
||||||
curr: curr,
|
|
||||||
period: period,
|
|
||||||
times: times,
|
|
||||||
h: h,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tick ticks one block in the IterationsTicker.
|
|
||||||
//
|
|
||||||
// Returns `false` if the timer has finished its operations
|
|
||||||
// and there will be no more handler calls.
|
|
||||||
// Calling Tick after the returned `false` is safe, no-op
|
|
||||||
// and also returns `false`.
|
|
||||||
func (ft *IterationsTicker) Tick() bool {
|
|
||||||
ft.m.Lock()
|
|
||||||
defer ft.m.Unlock()
|
|
||||||
|
|
||||||
if ft.times == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ft.curr++
|
|
||||||
|
|
||||||
if ft.curr%ft.period == 0 {
|
|
||||||
ft.h()
|
|
||||||
|
|
||||||
ft.times--
|
|
||||||
|
|
||||||
if ft.times == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
package ticker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFixedTimer_Tick(t *testing.T) {
|
|
||||||
tests := [...]struct {
|
|
||||||
duration uint64
|
|
||||||
times uint64
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
duration: 20,
|
|
||||||
times: 4,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 6,
|
|
||||||
times: 6,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 10,
|
|
||||||
times: 6,
|
|
||||||
err: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 5,
|
|
||||||
times: 6,
|
|
||||||
err: errors.New("impossible to tick 6 times in 5 blocks"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(fmt.Sprintf("duration:%d,times:%d", test.duration, test.times), func(t *testing.T) {
|
|
||||||
counter := uint64(0)
|
|
||||||
|
|
||||||
timer, err := NewIterationsTicker(test.duration, test.times, func() {
|
|
||||||
counter++
|
|
||||||
})
|
|
||||||
if test.err != nil {
|
|
||||||
require.EqualError(t, err, test.err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
for i := 0; i < int(test.duration); i++ {
|
|
||||||
if !timer.Tick() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, false, timer.Tick())
|
|
||||||
require.Equal(t, test.times, counter)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFixedTimer_RareCalls(t *testing.T) {
|
|
||||||
tests := [...]struct {
|
|
||||||
duration uint64
|
|
||||||
times uint64
|
|
||||||
firstCall uint64
|
|
||||||
period uint64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
duration: 11,
|
|
||||||
times: 6,
|
|
||||||
firstCall: 1,
|
|
||||||
period: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 11,
|
|
||||||
times: 4,
|
|
||||||
firstCall: 2,
|
|
||||||
period: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 20,
|
|
||||||
times: 3,
|
|
||||||
firstCall: 4,
|
|
||||||
period: 7,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(fmt.Sprintf("duration:%d,times:%d", test.duration, test.times), func(t *testing.T) {
|
|
||||||
var counter uint64
|
|
||||||
|
|
||||||
timer, err := NewIterationsTicker(test.duration, test.times, func() {
|
|
||||||
counter++
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
checked := false
|
|
||||||
|
|
||||||
for i := 1; i <= int(test.duration); i++ {
|
|
||||||
if !timer.Tick() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if !checked && counter == 1 {
|
|
||||||
require.Equal(t, test.firstCall, uint64(i))
|
|
||||||
checked = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, false, timer.Tick())
|
|
||||||
require.Equal(t, test.times, counter)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/reputation/ticker"
|
|
||||||
)
|
|
||||||
|
|
||||||
type eigenTrustTickers struct {
|
|
||||||
m sync.Mutex
|
|
||||||
|
|
||||||
timers map[uint64]*ticker.IterationsTicker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *eigenTrustTickers) addEpochTimer(epoch uint64, timer *ticker.IterationsTicker) {
|
|
||||||
e.m.Lock()
|
|
||||||
defer e.m.Unlock()
|
|
||||||
|
|
||||||
e.timers[epoch] = timer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *eigenTrustTickers) tick() {
|
|
||||||
e.m.Lock()
|
|
||||||
defer e.m.Unlock()
|
|
||||||
|
|
||||||
for epoch, t := range e.timers {
|
|
||||||
if !t.Tick() {
|
|
||||||
delete(e.timers, epoch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func tickBlockTimers(c *cfg) {
|
|
||||||
c.cfgMorph.eigenTrustTicker.tick()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEigenTrustIterTimer(c *cfg) {
|
|
||||||
c.cfgMorph.eigenTrustTicker = &eigenTrustTickers{
|
|
||||||
// it is expected to have max 2 concurrent epoch
|
|
||||||
// in normal mode work
|
|
||||||
timers: make(map[uint64]*ticker.IterationsTicker, 2),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
addrvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/maddress"
|
addrvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/maddress"
|
||||||
statevalidation "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/state"
|
statevalidation "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/state"
|
||||||
subnetvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/subnet"
|
subnetvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/subnet"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement"
|
||||||
auditSettlement "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement/audit"
|
auditSettlement "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement/audit"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
||||||
|
@ -29,13 +28,11 @@ import (
|
||||||
frostfsClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
frostfsClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
repClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/reputation"
|
|
||||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
audittask "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/audit/taskmanager"
|
audittask "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/audit/taskmanager"
|
||||||
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
||||||
controlsrv "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir/server"
|
controlsrv "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir/server"
|
||||||
reputationcommon "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
util2 "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
util2 "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
||||||
utilConfig "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/config"
|
utilConfig "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
@ -467,33 +464,6 @@ func (s *Server) initFrostFSMainnetProcessor(cfg *viper.Viper, frostfsIDClient *
|
||||||
return bindMainnetProcessor(frostfsProcessor, s)
|
return bindMainnetProcessor(frostfsProcessor, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) initReputationProcessor(cfg *viper.Viper, sidechainFee fixedn.Fixed8) error {
|
|
||||||
repClient, err := repClient.NewFromMorph(s.morphClient, s.contracts.reputation, sidechainFee, repClient.TryNotary(), repClient.AsAlphabet())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create reputation processor
|
|
||||||
reputationProcessor, err := reputation.New(&reputation.Params{
|
|
||||||
Log: s.log,
|
|
||||||
PoolSize: cfg.GetInt("workers.reputation"),
|
|
||||||
EpochState: s,
|
|
||||||
AlphabetState: s,
|
|
||||||
ReputationWrapper: repClient,
|
|
||||||
ManagerBuilder: reputationcommon.NewManagerBuilder(
|
|
||||||
reputationcommon.ManagersPrm{
|
|
||||||
NetMapSource: s.netmapClient,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
NotaryDisabled: s.sideNotaryConfig.disabled,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return bindMorphProcessor(reputationProcessor, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) initGRPCServer(cfg *viper.Viper) error {
|
func (s *Server) initGRPCServer(cfg *viper.Viper) error {
|
||||||
controlSvcEndpoint := cfg.GetString("control.grpc.endpoint")
|
controlSvcEndpoint := cfg.GetString("control.grpc.endpoint")
|
||||||
if controlSvcEndpoint == "" {
|
if controlSvcEndpoint == "" {
|
||||||
|
@ -620,8 +590,6 @@ type serverProcessors struct {
|
||||||
func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClients) (*serverProcessors, error) {
|
func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClients) (*serverProcessors, error) {
|
||||||
result := &serverProcessors{}
|
result := &serverProcessors{}
|
||||||
|
|
||||||
fee := s.feeConfig.SideChainFee()
|
|
||||||
|
|
||||||
irf := s.createIRFetcher()
|
irf := s.createIRFetcher()
|
||||||
|
|
||||||
s.statusIndex = newInnerRingIndexer(
|
s.statusIndex = newInnerRingIndexer(
|
||||||
|
@ -681,11 +649,6 @@ func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClien
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.initReputationProcessor(cfg, fee)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package reputation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
|
||||||
reputationEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (rp *Processor) handlePutReputation(ev event.Event) {
|
|
||||||
put := ev.(reputationEvent.Put)
|
|
||||||
peerID := put.PeerID()
|
|
||||||
|
|
||||||
// FIXME: #1147 do not use `ToV2` method outside frostfs-api-go library
|
|
||||||
rp.log.Info(logs.Notification,
|
|
||||||
zap.String("type", "reputation put"),
|
|
||||||
zap.String("peer_id", hex.EncodeToString(peerID.PublicKey())))
|
|
||||||
|
|
||||||
// send event to the worker pool
|
|
||||||
|
|
||||||
err := rp.pool.Submit(func() { rp.processPut(&put) })
|
|
||||||
if err != nil {
|
|
||||||
// there system can be moved into controlled degradation stage
|
|
||||||
rp.log.Warn(logs.ReputationReputationWorkerPoolDrained,
|
|
||||||
zap.Int("capacity", rp.pool.Cap()))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
package reputation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
repClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/reputation"
|
|
||||||
reputationEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/reputation"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var errWrongManager = errors.New("got manager that is incorrect for peer")
|
|
||||||
|
|
||||||
func (rp *Processor) processPut(e *reputationEvent.Put) {
|
|
||||||
if !rp.alphabetState.IsAlphabet() {
|
|
||||||
rp.log.Info(logs.ReputationNonAlphabetModeIgnoreReputationPutNotification)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
epoch := e.Epoch()
|
|
||||||
id := e.PeerID()
|
|
||||||
value := e.Value()
|
|
||||||
|
|
||||||
// check if epoch is valid
|
|
||||||
currentEpoch := rp.epochState.EpochCounter()
|
|
||||||
if epoch >= currentEpoch {
|
|
||||||
rp.log.Info(logs.ReputationIgnoreReputationValue,
|
|
||||||
zap.String("reason", "invalid epoch number"),
|
|
||||||
zap.Uint64("trust_epoch", epoch),
|
|
||||||
zap.Uint64("local_epoch", currentEpoch))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check signature
|
|
||||||
if !value.VerifySignature() {
|
|
||||||
rp.log.Info(logs.ReputationIgnoreReputationValue,
|
|
||||||
zap.String("reason", "invalid signature"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if manager is correct
|
|
||||||
if err := rp.checkManagers(epoch, value.Manager(), id); err != nil {
|
|
||||||
rp.log.Info(logs.ReputationIgnoreReputationValue,
|
|
||||||
zap.String("reason", "wrong manager"),
|
|
||||||
zap.String("error", err.Error()))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rp.approvePutReputation(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp *Processor) checkManagers(e uint64, mng apireputation.PeerID, peer apireputation.PeerID) error {
|
|
||||||
mm, err := rp.mngBuilder.BuildManagers(e, peer)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not build managers: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range mm {
|
|
||||||
// FIXME: #1147 do not use `ToV2` method outside frostfs-api-go library
|
|
||||||
if bytes.Equal(mng.PublicKey(), m.PublicKey()) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errWrongManager
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rp *Processor) approvePutReputation(e *reputationEvent.Put) {
|
|
||||||
var (
|
|
||||||
id = e.PeerID()
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
if nr := e.NotaryRequest(); nr != nil {
|
|
||||||
// put event was received via Notary service
|
|
||||||
err = rp.reputationWrp.Morph().NotarySignAndInvokeTX(nr.MainTransaction)
|
|
||||||
} else {
|
|
||||||
args := repClient.PutPrm{}
|
|
||||||
args.SetEpoch(e.Epoch())
|
|
||||||
args.SetPeerID(id)
|
|
||||||
args.SetValue(e.Value())
|
|
||||||
|
|
||||||
err = rp.reputationWrp.Put(args)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
// FIXME: #1147 do not use `ToV2` method outside frostfs-api-go library
|
|
||||||
rp.log.Warn(logs.ReputationCantSendApprovalTxForReputationValue,
|
|
||||||
zap.String("peer_id", hex.EncodeToString(id.PublicKey())),
|
|
||||||
zap.String("error", err.Error()))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
package reputation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
repClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
|
||||||
reputationEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
|
||||||
"github.com/panjf2000/ants/v2"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// EpochState is a callback interface for inner ring global state.
|
|
||||||
EpochState interface {
|
|
||||||
EpochCounter() uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// AlphabetState is a callback interface for inner ring global state.
|
|
||||||
AlphabetState interface {
|
|
||||||
IsAlphabet() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processor of events produced by reputation contract.
|
|
||||||
Processor struct {
|
|
||||||
log *logger.Logger
|
|
||||||
pool *ants.Pool
|
|
||||||
|
|
||||||
epochState EpochState
|
|
||||||
alphabetState AlphabetState
|
|
||||||
|
|
||||||
reputationWrp *repClient.Client
|
|
||||||
|
|
||||||
mngBuilder common.ManagerBuilder
|
|
||||||
|
|
||||||
notaryDisabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params of the processor constructor.
|
|
||||||
Params struct {
|
|
||||||
Log *logger.Logger
|
|
||||||
PoolSize int
|
|
||||||
EpochState EpochState
|
|
||||||
AlphabetState AlphabetState
|
|
||||||
ReputationWrapper *repClient.Client
|
|
||||||
ManagerBuilder common.ManagerBuilder
|
|
||||||
NotaryDisabled bool
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
putReputationNotification = "reputationPut"
|
|
||||||
)
|
|
||||||
|
|
||||||
// New creates reputation contract processor instance.
|
|
||||||
func New(p *Params) (*Processor, error) {
|
|
||||||
switch {
|
|
||||||
case p.Log == nil:
|
|
||||||
return nil, errors.New("ir/reputation: logger is not set")
|
|
||||||
case p.EpochState == nil:
|
|
||||||
return nil, errors.New("ir/reputation: global state is not set")
|
|
||||||
case p.AlphabetState == nil:
|
|
||||||
return nil, errors.New("ir/reputation: global state is not set")
|
|
||||||
case p.ReputationWrapper == nil:
|
|
||||||
return nil, errors.New("ir/reputation: reputation contract wrapper is not set")
|
|
||||||
case p.ManagerBuilder == nil:
|
|
||||||
return nil, errors.New("ir/reputation: manager builder is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Log.Debug(logs.ReputationReputationWorkerPool, zap.Int("size", p.PoolSize))
|
|
||||||
|
|
||||||
pool, err := ants.NewPool(p.PoolSize, ants.WithNonblocking(true))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("ir/reputation: can't create worker pool: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Processor{
|
|
||||||
log: p.Log,
|
|
||||||
pool: pool,
|
|
||||||
epochState: p.EpochState,
|
|
||||||
alphabetState: p.AlphabetState,
|
|
||||||
reputationWrp: p.ReputationWrapper,
|
|
||||||
mngBuilder: p.ManagerBuilder,
|
|
||||||
notaryDisabled: p.NotaryDisabled,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenerNotificationParsers for the 'event.Listener' event producer.
|
|
||||||
func (rp *Processor) ListenerNotificationParsers() []event.NotificationParserInfo {
|
|
||||||
if !rp.notaryDisabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var parsers []event.NotificationParserInfo
|
|
||||||
|
|
||||||
// put reputation event
|
|
||||||
put := event.NotificationParserInfo{}
|
|
||||||
put.SetType(putReputationNotification)
|
|
||||||
put.SetScriptHash(rp.reputationWrp.ContractAddress())
|
|
||||||
put.SetParser(reputationEvent.ParsePut)
|
|
||||||
parsers = append(parsers, put)
|
|
||||||
|
|
||||||
return parsers
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenerNotificationHandlers for the 'event.Listener' event producer.
|
|
||||||
func (rp *Processor) ListenerNotificationHandlers() []event.NotificationHandlerInfo {
|
|
||||||
if !rp.notaryDisabled {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var handlers []event.NotificationHandlerInfo
|
|
||||||
|
|
||||||
// put reputation handler
|
|
||||||
put := event.NotificationHandlerInfo{}
|
|
||||||
put.SetType(putReputationNotification)
|
|
||||||
put.SetScriptHash(rp.reputationWrp.ContractAddress())
|
|
||||||
put.SetHandler(rp.handlePutReputation)
|
|
||||||
handlers = append(handlers, put)
|
|
||||||
|
|
||||||
return handlers
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenerNotaryParsers for the 'event.Listener' notary event producer.
|
|
||||||
func (rp *Processor) ListenerNotaryParsers() []event.NotaryParserInfo {
|
|
||||||
var p event.NotaryParserInfo
|
|
||||||
|
|
||||||
p.SetMempoolType(mempoolevent.TransactionAdded)
|
|
||||||
p.SetRequestType(reputationEvent.PutNotaryEvent)
|
|
||||||
p.SetScriptHash(rp.reputationWrp.ContractAddress())
|
|
||||||
p.SetParser(reputationEvent.ParsePutNotary)
|
|
||||||
|
|
||||||
return []event.NotaryParserInfo{p}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenerNotaryHandlers for the 'event.Listener' notary event producer.
|
|
||||||
func (rp *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo {
|
|
||||||
var h event.NotaryHandlerInfo
|
|
||||||
|
|
||||||
h.SetMempoolType(mempoolevent.TransactionAdded)
|
|
||||||
h.SetRequestType(reputationEvent.PutNotaryEvent)
|
|
||||||
h.SetScriptHash(rp.reputationWrp.ContractAddress())
|
|
||||||
h.SetHandler(rp.handlePutReputation)
|
|
||||||
|
|
||||||
return []event.NotaryHandlerInfo{h}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimersHandlers for the 'Timers' event producer.
|
|
||||||
func (rp *Processor) TimersHandlers() []event.NotificationHandlerInfo {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ type (
|
||||||
ClientCache struct {
|
ClientCache struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
cache interface {
|
cache interface {
|
||||||
Get(clientcore.NodeInfo) (clientcore.Client, error)
|
Get(clientcore.NodeInfo) (clientcore.MultiAddressClient, error)
|
||||||
CloseAll()
|
CloseAll()
|
||||||
}
|
}
|
||||||
key *ecdsa.PrivateKey
|
key *ecdsa.PrivateKey
|
||||||
|
|
2
pkg/network/cache/client.go
vendored
2
pkg/network/cache/client.go
vendored
|
@ -38,7 +38,7 @@ func NewSDKClientCache(opts ClientCacheOpts) *ClientCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get function returns existing client or creates a new one.
|
// Get function returns existing client or creates a new one.
|
||||||
func (c *ClientCache) Get(info clientcore.NodeInfo) (clientcore.Client, error) {
|
func (c *ClientCache) Get(info clientcore.NodeInfo) (clientcore.MultiAddressClient, error) {
|
||||||
netAddr := info.AddressGroup()
|
netAddr := info.AddressGroup()
|
||||||
if c.opts.AllowExternal {
|
if c.opts.AllowExternal {
|
||||||
netAddr = append(netAddr, info.ExternalAddressGroup()...)
|
netAddr = append(netAddr, info.ExternalAddressGroup()...)
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package grpcreputation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
|
|
||||||
reputation2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation/grpc"
|
|
||||||
reputationrpc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/rpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Server wraps FrostFS API v2 Reputation service server
|
|
||||||
// and provides gRPC Reputation service server interface.
|
|
||||||
type Server struct {
|
|
||||||
srv reputationrpc.Server
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates, initializes and returns Server instance.
|
|
||||||
func New(srv reputationrpc.Server) *Server {
|
|
||||||
return &Server{
|
|
||||||
srv: srv,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) AnnounceLocalTrust(ctx context.Context, r *reputation2.AnnounceLocalTrustRequest) (*reputation2.AnnounceLocalTrustResponse, error) {
|
|
||||||
req := new(reputation.AnnounceLocalTrustRequest)
|
|
||||||
if err := req.FromGRPCMessage(r); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := s.srv.AnnounceLocalTrust(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.ToGRPCMessage().(*reputation2.AnnounceLocalTrustResponse), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) AnnounceIntermediateResult(ctx context.Context, r *reputation2.AnnounceIntermediateResultRequest) (*reputation2.AnnounceIntermediateResultResponse, error) {
|
|
||||||
req := new(reputation.AnnounceIntermediateResultRequest)
|
|
||||||
if err := req.FromGRPCMessage(r); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := s.srv.AnnounceIntermediateResult(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.ToGRPCMessage().(*reputation2.AnnounceIntermediateResultResponse), nil
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClientConstructor interface {
|
type ClientConstructor interface {
|
||||||
Get(clientcore.NodeInfo) (clientcore.Client, error)
|
Get(clientcore.NodeInfo) (clientcore.MultiAddressClient, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteHeader represents utility for getting
|
// RemoteHeader represents utility for getting
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EpochProvider interface {
|
|
||||||
// Must return epoch number to select the values.
|
|
||||||
Epoch() uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer describes the interface for storing reputation.Trust values.
|
|
||||||
//
|
|
||||||
// This interface is provided by both local storage
|
|
||||||
// of values and remote (wrappers over the RPC).
|
|
||||||
type Writer interface {
|
|
||||||
// Write performs a write operation of reputation.Trust value
|
|
||||||
// and returns any error encountered.
|
|
||||||
//
|
|
||||||
// All values after the Close call must be flushed to the
|
|
||||||
// physical target. Implementations can cache values before
|
|
||||||
// Close operation.
|
|
||||||
//
|
|
||||||
// Write must not be called after Close.
|
|
||||||
Write(context.Context, reputation.Trust) error
|
|
||||||
|
|
||||||
// Close exits with method-providing Writer.
|
|
||||||
//
|
|
||||||
// All cached values must be flushed before
|
|
||||||
// the Close's return.
|
|
||||||
//
|
|
||||||
// Methods must not be called after Close.
|
|
||||||
Close(context.Context) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriterProvider is a group of methods provided
|
|
||||||
// by entity which generates keepers of
|
|
||||||
// reputation.Trust values.
|
|
||||||
type WriterProvider interface {
|
|
||||||
// InitWriter should return an initialized Writer.
|
|
||||||
//
|
|
||||||
// Initialization problems are reported via error.
|
|
||||||
// If no error was returned, then the Writer must not be nil.
|
|
||||||
//
|
|
||||||
// Implementations can have different logic for different
|
|
||||||
// contexts, so specific ones may document their own behavior.
|
|
||||||
InitWriter(EpochProvider) (Writer, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ManagerBuilder defines an interface for providing a list
|
|
||||||
// of Managers for specific epoch. Implementation depends on trust value.
|
|
||||||
type ManagerBuilder interface {
|
|
||||||
// BuildManagers must compose list of managers. It depends on
|
|
||||||
// particular epoch and PeerID of the current route point.
|
|
||||||
BuildManagers(epoch uint64, p apireputation.PeerID) ([]ServerInfo, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerInfo describes a set of
|
|
||||||
// characteristics of a point in a route.
|
|
||||||
type ServerInfo interface {
|
|
||||||
// PublicKey returns public key of the node
|
|
||||||
// from the route in a binary representation.
|
|
||||||
PublicKey() []byte
|
|
||||||
|
|
||||||
// Iterates over network addresses of the node
|
|
||||||
// in the route. Breaks iterating on true return
|
|
||||||
// of the handler.
|
|
||||||
IterateAddresses(func(string) bool)
|
|
||||||
|
|
||||||
// Returns number of server's network addresses.
|
|
||||||
NumberOfAddresses() int
|
|
||||||
|
|
||||||
// ExternalAddresses returns external addresses of a node.
|
|
||||||
ExternalAddresses() []string
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
netmapcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
apiNetmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/hrw"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// managerBuilder is implementation of reputation ManagerBuilder interface.
|
|
||||||
// It sorts nodes in NetMap with HRW algorithms and
|
|
||||||
// takes the next node after the current one as the only manager.
|
|
||||||
type managerBuilder struct {
|
|
||||||
log *logger.Logger
|
|
||||||
nmSrc netmapcore.Source
|
|
||||||
opts *mngOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
// ManagersPrm groups the required parameters of the managerBuilder's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type ManagersPrm struct {
|
|
||||||
NetMapSource netmapcore.Source
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewManagerBuilder creates a new instance of the managerBuilder.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created managerBuilder does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func NewManagerBuilder(prm ManagersPrm, opts ...MngOption) ManagerBuilder {
|
|
||||||
switch {
|
|
||||||
case prm.NetMapSource == nil:
|
|
||||||
panic(fmt.Sprintf("invalid NetMapSource (%T):%v", prm.NetMapSource, prm.NetMapSource))
|
|
||||||
}
|
|
||||||
|
|
||||||
o := defaultMngOpts()
|
|
||||||
|
|
||||||
for i := range opts {
|
|
||||||
opts[i](o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &managerBuilder{
|
|
||||||
log: o.log,
|
|
||||||
nmSrc: prm.NetMapSource,
|
|
||||||
opts: o,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// implements Server on apiNetmap.NodeInfo.
|
|
||||||
type nodeServer apiNetmap.NodeInfo
|
|
||||||
|
|
||||||
func (x nodeServer) PublicKey() []byte {
|
|
||||||
return (apiNetmap.NodeInfo)(x).PublicKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x nodeServer) IterateAddresses(f func(string) bool) {
|
|
||||||
(apiNetmap.NodeInfo)(x).IterateNetworkEndpoints(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x nodeServer) NumberOfAddresses() int {
|
|
||||||
return (apiNetmap.NodeInfo)(x).NumberOfNetworkEndpoints()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x nodeServer) ExternalAddresses() []string {
|
|
||||||
return (apiNetmap.NodeInfo)(x).ExternalAddresses()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildManagers sorts nodes in NetMap with HRW algorithms and
|
|
||||||
// takes the next node after the current one as the only manager.
|
|
||||||
func (mb *managerBuilder) BuildManagers(epoch uint64, p apireputation.PeerID) ([]ServerInfo, error) {
|
|
||||||
mb.log.Debug(logs.CommonStartBuildingManagers,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
zap.Stringer("peer", p),
|
|
||||||
)
|
|
||||||
|
|
||||||
nm, err := mb.nmSrc.GetNetMapByEpoch(epoch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nmNodes := nm.Nodes()
|
|
||||||
|
|
||||||
// make a copy to keep order consistency of the origin netmap after sorting
|
|
||||||
nodes := make([]apiNetmap.NodeInfo, len(nmNodes))
|
|
||||||
|
|
||||||
copy(nodes, nmNodes)
|
|
||||||
|
|
||||||
hrw.SortHasherSliceByValue(nodes, epoch)
|
|
||||||
|
|
||||||
for i := range nodes {
|
|
||||||
if apireputation.ComparePeerKey(p, nodes[i].PublicKey()) {
|
|
||||||
managerIndex := i + 1
|
|
||||||
|
|
||||||
if managerIndex == len(nodes) {
|
|
||||||
managerIndex = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return []ServerInfo{nodeServer(nodes[managerIndex])}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type mngOptions struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type MngOption func(*mngOptions)
|
|
||||||
|
|
||||||
func defaultMngOpts() *mngOptions {
|
|
||||||
return &mngOptions{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns MngOption to specify logging component.
|
|
||||||
func WithLogger(l *logger.Logger) MngOption {
|
|
||||||
return func(o *mngOptions) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RouteInfo wraps epoch provider with additional passed
|
|
||||||
// route data. It is only used inside Router and is
|
|
||||||
// not passed in any external methods.
|
|
||||||
type RouteInfo struct {
|
|
||||||
common.EpochProvider
|
|
||||||
|
|
||||||
passedRoute []common.ServerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRouteInfo wraps the main context of value passing with its traversal route and epoch.
|
|
||||||
func NewRouteInfo(ep common.EpochProvider, passed []common.ServerInfo) *RouteInfo {
|
|
||||||
return &RouteInfo{
|
|
||||||
EpochProvider: ep,
|
|
||||||
passedRoute: passed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type trustWriter struct {
|
|
||||||
router *Router
|
|
||||||
|
|
||||||
routeInfo *RouteInfo
|
|
||||||
|
|
||||||
routeMtx sync.RWMutex
|
|
||||||
mServers map[string]common.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitWriter initializes and returns Writer that sends each value to its next route point.
|
|
||||||
//
|
|
||||||
// If ep was created by NewRouteInfo, then the traversed route is taken into account,
|
|
||||||
// and the value will be sent to its continuation. Otherwise, the route will be laid
|
|
||||||
// from scratch and the value will be sent to its primary point.
|
|
||||||
//
|
|
||||||
// After building a list of remote points of the next leg of the route, the value is sent
|
|
||||||
// sequentially to all of them. If any transmissions (even all) fail, an error will not
|
|
||||||
// be returned.
|
|
||||||
//
|
|
||||||
// Close of the composed Writer calls Close method on each internal Writer generated in
|
|
||||||
// runtime and never returns an error.
|
|
||||||
//
|
|
||||||
// Always returns nil error.
|
|
||||||
func (r *Router) InitWriter(ep common.EpochProvider) (common.Writer, error) {
|
|
||||||
var (
|
|
||||||
routeInfo *RouteInfo
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if routeInfo, ok = ep.(*RouteInfo); !ok {
|
|
||||||
routeInfo = &RouteInfo{
|
|
||||||
EpochProvider: ep,
|
|
||||||
passedRoute: []common.ServerInfo{r.localSrvInfo},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &trustWriter{
|
|
||||||
router: r,
|
|
||||||
routeInfo: routeInfo,
|
|
||||||
mServers: make(map[string]common.Writer),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *trustWriter) Write(ctx context.Context, t reputation.Trust) error {
|
|
||||||
w.routeMtx.Lock()
|
|
||||||
defer w.routeMtx.Unlock()
|
|
||||||
|
|
||||||
route, err := w.router.routeBuilder.NextStage(w.routeInfo.Epoch(), t, w.routeInfo.passedRoute)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if len(route) == 0 {
|
|
||||||
route = []common.ServerInfo{nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, remoteInfo := range route {
|
|
||||||
var key string
|
|
||||||
|
|
||||||
if remoteInfo != nil {
|
|
||||||
key = hex.EncodeToString(remoteInfo.PublicKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteWriter, ok := w.mServers[key]
|
|
||||||
if !ok {
|
|
||||||
provider, err := w.router.remoteProvider.InitRemote(remoteInfo)
|
|
||||||
if err != nil {
|
|
||||||
w.router.log.Debug(logs.RouterCouldNotInitializeWriterProvider,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// init writer with original context wrapped in routeContext
|
|
||||||
remoteWriter, err = provider.InitWriter(w.routeInfo.EpochProvider)
|
|
||||||
if err != nil {
|
|
||||||
w.router.log.Debug(logs.RouterCouldNotInitializeWriter,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
w.mServers[key] = remoteWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
err := remoteWriter.Write(ctx, t)
|
|
||||||
if err != nil {
|
|
||||||
w.router.log.Debug(logs.RouterCouldNotWriteTheValue,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *trustWriter) Close(ctx context.Context) error {
|
|
||||||
for key, wRemote := range w.mServers {
|
|
||||||
err := wRemote.Close(ctx)
|
|
||||||
if err != nil {
|
|
||||||
w.router.log.Debug(logs.RouterCouldNotCloseRemoteServerWriter,
|
|
||||||
zap.String("key", key),
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Builder groups methods to route values in the network.
|
|
||||||
type Builder interface {
|
|
||||||
// NextStage must return next group of route points
|
|
||||||
// for passed epoch and trust values.
|
|
||||||
// Implementation must take into account already passed route points.
|
|
||||||
//
|
|
||||||
// Empty passed list means being at the starting point of the route.
|
|
||||||
//
|
|
||||||
// Must return empty list and no error if the endpoint of the route is reached.
|
|
||||||
NextStage(epoch uint64, t reputation.Trust, passed []common.ServerInfo) ([]common.ServerInfo, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteWriterProvider describes the component
|
|
||||||
// for sending values to a fixed route point.
|
|
||||||
type RemoteWriterProvider interface {
|
|
||||||
// InitRemote must return WriterProvider to the route point
|
|
||||||
// corresponding to info.
|
|
||||||
//
|
|
||||||
// Nil info matches the end of the route.
|
|
||||||
InitRemote(info common.ServerInfo) (common.WriterProvider, error)
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option sets an optional parameter of Router.
|
|
||||||
type Option func(*options)
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultOpts() *options {
|
|
||||||
return &options{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns Option to specify logging component.
|
|
||||||
func WithLogger(l *logger.Logger) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Router's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Characteristics of the local node's server.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
LocalServerInfo common.ServerInfo
|
|
||||||
|
|
||||||
// Component for sending values to a fixed route point.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
RemoteWriterProvider RemoteWriterProvider
|
|
||||||
|
|
||||||
// Route planner.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
Builder Builder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Router represents component responsible for routing
|
|
||||||
// local trust values over the network.
|
|
||||||
//
|
|
||||||
// For each fixed pair (node peer, epoch) there is a
|
|
||||||
// single value route on the network. Router provides the
|
|
||||||
// interface for writing values to the next point of the route.
|
|
||||||
//
|
|
||||||
// For correct operation, Router must be created using
|
|
||||||
// the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the Router is immediately ready to work through API.
|
|
||||||
type Router struct {
|
|
||||||
log *logger.Logger
|
|
||||||
|
|
||||||
remoteProvider RemoteWriterProvider
|
|
||||||
|
|
||||||
routeBuilder Builder
|
|
||||||
|
|
||||||
localSrvInfo common.ServerInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(prm Prm, opts ...Option) *Router {
|
|
||||||
switch {
|
|
||||||
case prm.RemoteWriterProvider == nil:
|
|
||||||
panicOnPrmValue("RemoteWriterProvider", prm.RemoteWriterProvider)
|
|
||||||
case prm.Builder == nil:
|
|
||||||
panicOnPrmValue("Builder", prm.Builder)
|
|
||||||
case prm.LocalServerInfo == nil:
|
|
||||||
panicOnPrmValue("LocalServerInfo", prm.LocalServerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
o := defaultOpts()
|
|
||||||
|
|
||||||
for i := range opts {
|
|
||||||
opts[i](o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Router{
|
|
||||||
log: o.log,
|
|
||||||
remoteProvider: prm.RemoteWriterProvider,
|
|
||||||
routeBuilder: prm.Builder,
|
|
||||||
localSrvInfo: prm.LocalServerInfo,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
var errWrongRoute = errors.New("wrong route")
|
|
||||||
|
|
||||||
// CheckRoute checks if the route is a route correctly constructed by the builder for value a.
|
|
||||||
//
|
|
||||||
// Returns nil if route is correct, otherwise an error clarifying the inconsistency.
|
|
||||||
func CheckRoute(builder Builder, epoch uint64, t reputation.Trust, route []common.ServerInfo) error {
|
|
||||||
for i := 1; i < len(route); i++ {
|
|
||||||
servers, err := builder.NextStage(epoch, t, route[:i])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if len(servers) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
|
|
||||||
for j := range servers {
|
|
||||||
if bytes.Equal(servers[j].PublicKey(), route[i].PublicKey()) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return errWrongRoute
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package eigentrustcalc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Calculator's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Alpha parameter from origin EigenTrust algorithm
|
|
||||||
// http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Ch.5.1.
|
|
||||||
//
|
|
||||||
// Must be in range (0, 1).
|
|
||||||
AlphaProvider AlphaProvider
|
|
||||||
|
|
||||||
// Source of initial node trust values
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
InitialTrustSource InitialTrustSource
|
|
||||||
|
|
||||||
DaughterTrustSource DaughterTrustIteratorProvider
|
|
||||||
|
|
||||||
IntermediateValueTarget common.WriterProvider
|
|
||||||
|
|
||||||
FinalResultTarget IntermediateWriterProvider
|
|
||||||
|
|
||||||
WorkerPool util.WorkerPool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculator is a processor of a single iteration of EigenTrust algorithm.
|
|
||||||
//
|
|
||||||
// For correct operation, the Calculator must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the Calculator is immediately ready to work through
|
|
||||||
// API of external control of calculations and data transfer.
|
|
||||||
type Calculator struct {
|
|
||||||
alpha, beta reputation.TrustValue // beta = 1 - alpha
|
|
||||||
|
|
||||||
prm Prm
|
|
||||||
|
|
||||||
opts *options
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Calculator.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created Calculator does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm, opts ...Option) *Calculator {
|
|
||||||
switch {
|
|
||||||
case prm.AlphaProvider == nil:
|
|
||||||
panicOnPrmValue("AlphaProvider", prm.AlphaProvider)
|
|
||||||
case prm.InitialTrustSource == nil:
|
|
||||||
panicOnPrmValue("InitialTrustSource", prm.InitialTrustSource)
|
|
||||||
case prm.DaughterTrustSource == nil:
|
|
||||||
panicOnPrmValue("DaughterTrustSource", prm.DaughterTrustSource)
|
|
||||||
case prm.IntermediateValueTarget == nil:
|
|
||||||
panicOnPrmValue("IntermediateValueTarget", prm.IntermediateValueTarget)
|
|
||||||
case prm.FinalResultTarget == nil:
|
|
||||||
panicOnPrmValue("FinalResultTarget", prm.FinalResultTarget)
|
|
||||||
case prm.WorkerPool == nil:
|
|
||||||
panicOnPrmValue("WorkerPool", prm.WorkerPool)
|
|
||||||
}
|
|
||||||
|
|
||||||
o := defaultOpts()
|
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Calculator{
|
|
||||||
prm: prm,
|
|
||||||
opts: o,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,295 +0,0 @@
|
||||||
package eigentrustcalc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CalculatePrm struct {
|
|
||||||
last bool
|
|
||||||
|
|
||||||
ei eigentrust.EpochIteration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *CalculatePrm) SetLast(last bool) {
|
|
||||||
p.last = last
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *CalculatePrm) SetEpochIteration(ei eigentrust.EpochIteration) {
|
|
||||||
p.ei = ei
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Calculator) Calculate(ctx context.Context, prm CalculatePrm) {
|
|
||||||
alpha, err := c.prm.AlphaProvider.EigenTrustAlpha()
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(
|
|
||||||
logs.CalculatorFailedToGetAlphaParam,
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.alpha = reputation.TrustValueFromFloat64(alpha)
|
|
||||||
c.beta = reputation.TrustValueFromFloat64(1 - alpha)
|
|
||||||
|
|
||||||
epochIteration := prm.ei
|
|
||||||
|
|
||||||
iter := epochIteration.I()
|
|
||||||
|
|
||||||
log := c.opts.log.With(
|
|
||||||
zap.Uint64("epoch", epochIteration.Epoch()),
|
|
||||||
zap.Uint32("iteration", iter),
|
|
||||||
)
|
|
||||||
|
|
||||||
if iter == 0 {
|
|
||||||
c.sendInitialValues(ctx, epochIteration)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrement iteration number to select the values collected
|
|
||||||
// on the previous stage
|
|
||||||
epochIteration.SetI(iter - 1)
|
|
||||||
|
|
||||||
consumersIter, err := c.prm.DaughterTrustSource.InitConsumersIterator(epochIteration)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.CalculatorConsumersTrustIteratorsInitFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue with initial iteration number
|
|
||||||
epochIteration.SetI(iter)
|
|
||||||
|
|
||||||
err = consumersIter.Iterate(func(daughter apireputation.PeerID, iter TrustIterator) error {
|
|
||||||
err := c.prm.WorkerPool.Submit(func() {
|
|
||||||
c.iterateDaughter(ctx, iterDaughterPrm{
|
|
||||||
lastIter: prm.last,
|
|
||||||
ei: epochIteration,
|
|
||||||
id: daughter,
|
|
||||||
consumersIter: iter,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.CalculatorWorkerPoolSubmitFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't stop trying
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(logs.CalculatorIterateDaughtersConsumersFailed,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type iterDaughterPrm struct {
|
|
||||||
lastIter bool
|
|
||||||
|
|
||||||
ei EpochIterationInfo
|
|
||||||
|
|
||||||
id apireputation.PeerID
|
|
||||||
|
|
||||||
consumersIter TrustIterator
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Calculator) iterateDaughter(ctx context.Context, p iterDaughterPrm) {
|
|
||||||
initTrust, err := c.prm.InitialTrustSource.InitialTrust(p.id)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorGetInitialTrustFailure,
|
|
||||||
zap.Stringer("daughter", p.id),
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
daughterIter, err := c.prm.DaughterTrustSource.InitDaughterIterator(p.ei, p.id)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorDaughterTrustIteratorsInitFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sum := reputation.TrustZero
|
|
||||||
|
|
||||||
err = p.consumersIter.Iterate(func(trust reputation.Trust) error {
|
|
||||||
if !p.lastIter {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sum.Add(trust.Value())
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorIterateOverDaughtersTrustsFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alpha * Pd
|
|
||||||
initTrust.Mul(c.alpha)
|
|
||||||
|
|
||||||
sum.Mul(c.beta)
|
|
||||||
sum.Add(initTrust)
|
|
||||||
|
|
||||||
var intermediateTrust eigentrust.IterationTrust
|
|
||||||
|
|
||||||
intermediateTrust.SetEpoch(p.ei.Epoch())
|
|
||||||
intermediateTrust.SetPeer(p.id)
|
|
||||||
intermediateTrust.SetI(p.ei.I())
|
|
||||||
|
|
||||||
if p.lastIter {
|
|
||||||
c.processLastIteration(p, intermediateTrust, sum)
|
|
||||||
} else {
|
|
||||||
c.processIntermediateIteration(ctx, p, daughterIter, sum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Calculator) processLastIteration(p iterDaughterPrm, intermediateTrust eigentrust.IterationTrust, sum reputation.TrustValue) {
|
|
||||||
finalWriter, err := c.prm.FinalResultTarget.InitIntermediateWriter(p.ei)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorInitWriterFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
intermediateTrust.SetValue(sum)
|
|
||||||
|
|
||||||
err = finalWriter.WriteIntermediateTrust(intermediateTrust)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorWriteFinalResultFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Calculator) processIntermediateIteration(ctx context.Context, p iterDaughterPrm, daughterIter TrustIterator, sum reputation.TrustValue) {
|
|
||||||
intermediateWriter, err := c.prm.IntermediateValueTarget.InitWriter(p.ei)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorInitWriterFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = daughterIter.Iterate(func(trust reputation.Trust) error {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
val := trust.Value()
|
|
||||||
val.Mul(sum)
|
|
||||||
|
|
||||||
trust.SetValue(val)
|
|
||||||
|
|
||||||
err := intermediateWriter.Write(ctx, trust)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorWriteValueFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorIterateDaughterTrustsFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = intermediateWriter.Close(ctx)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Error(
|
|
||||||
"could not close writer",
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Calculator) sendInitialValues(ctx context.Context, epochInfo EpochIterationInfo) {
|
|
||||||
daughterIter, err := c.prm.DaughterTrustSource.InitAllDaughtersIterator(epochInfo)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorAllDaughtersTrustIteratorsInitFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
intermediateWriter, err := c.prm.IntermediateValueTarget.InitWriter(epochInfo)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorInitWriterFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = daughterIter.Iterate(func(daughter apireputation.PeerID, iterator TrustIterator) error {
|
|
||||||
return iterator.Iterate(func(trust reputation.Trust) error {
|
|
||||||
trusted := trust.Peer()
|
|
||||||
|
|
||||||
initTrust, err := c.prm.InitialTrustSource.InitialTrust(trusted)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorGetInitialTrustFailure,
|
|
||||||
zap.Stringer("peer", trusted),
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
// don't stop on single failure
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
initTrust.Mul(trust.Value())
|
|
||||||
trust.SetValue(initTrust)
|
|
||||||
|
|
||||||
err = intermediateWriter.Write(ctx, trust)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorWriteValueFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
// don't stop on single failure
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorIterateOverAllDaughtersFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = intermediateWriter.Close(ctx)
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.CalculatorCouldNotCloseWriter,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package eigentrustcalc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EpochIterationInfo interface {
|
|
||||||
// Must return epoch number to select the values
|
|
||||||
// for global trust calculation.
|
|
||||||
Epoch() uint64
|
|
||||||
|
|
||||||
// Must return the sequence number of the iteration.
|
|
||||||
I() uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitialTrustSource must provide initial(non-calculated)
|
|
||||||
// trusts to current node's daughter. Realization may depends
|
|
||||||
// on daughter.
|
|
||||||
type InitialTrustSource interface {
|
|
||||||
InitialTrust(apireputation.PeerID) (reputation.TrustValue, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustIterator must iterate over all retrieved(or calculated) trusts
|
|
||||||
// and call passed TrustHandler on them.
|
|
||||||
type TrustIterator interface {
|
|
||||||
Iterate(reputation.TrustHandler) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type PeerTrustsHandler func(apireputation.PeerID, TrustIterator) error
|
|
||||||
|
|
||||||
// PeerTrustsIterator must iterate over all nodes(PeerIDs) and provide
|
|
||||||
// TrustIterator for iteration over node's Trusts to others peers.
|
|
||||||
type PeerTrustsIterator interface {
|
|
||||||
Iterate(PeerTrustsHandler) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type DaughterTrustIteratorProvider interface {
|
|
||||||
// InitDaughterIterator must init TrustIterator
|
|
||||||
// that iterates over received local trusts from
|
|
||||||
// daughter p for epochInfo.Epoch() epoch.
|
|
||||||
InitDaughterIterator(epochInfo EpochIterationInfo, p apireputation.PeerID) (TrustIterator, error)
|
|
||||||
// InitAllDaughtersIterator must init PeerTrustsIterator
|
|
||||||
// that must iterate over all daughters of the current
|
|
||||||
// node(manager) and all trusts received from them for
|
|
||||||
// epochInfo.Epoch() epoch.
|
|
||||||
InitAllDaughtersIterator(epochInfo EpochIterationInfo) (PeerTrustsIterator, error)
|
|
||||||
// InitConsumersIterator must init PeerTrustsIterator
|
|
||||||
// that must iterate over all daughters of the current
|
|
||||||
// node(manager) and their consumers' trusts received
|
|
||||||
// from other managers for epochInfo.Epoch() epoch and
|
|
||||||
// epochInfo.I() iteration.
|
|
||||||
InitConsumersIterator(EpochIterationInfo) (PeerTrustsIterator, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntermediateWriter must write intermediate result to contract.
|
|
||||||
// It may depends on realization either trust is sent directly to contract
|
|
||||||
// or via redirecting to other node.
|
|
||||||
type IntermediateWriter interface {
|
|
||||||
WriteIntermediateTrust(eigentrust.IterationTrust) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntermediateWriterProvider must provide ready-to-work
|
|
||||||
// IntermediateWriter.
|
|
||||||
type IntermediateWriterProvider interface {
|
|
||||||
InitIntermediateWriter(EpochIterationInfo) (IntermediateWriter, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AlphaProvider must provide information about required
|
|
||||||
// alpha parameter for eigen trust algorithm.
|
|
||||||
type AlphaProvider interface {
|
|
||||||
EigenTrustAlpha() (float64, error)
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package eigentrustcalc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option sets an optional parameter of Controller.
|
|
||||||
type Option func(*options)
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultOpts() *options {
|
|
||||||
return &options{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns option to specify logging component.
|
|
||||||
//
|
|
||||||
// Ignores nil values.
|
|
||||||
func WithLogger(l *logger.Logger) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package eigentrustctrl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContinuePrm groups the required parameters of Continue operation.
|
|
||||||
type ContinuePrm struct {
|
|
||||||
Epoch uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type iterContext struct {
|
|
||||||
eigentrust.EpochIteration
|
|
||||||
|
|
||||||
iterationNumber uint32
|
|
||||||
last bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x iterContext) Last() bool {
|
|
||||||
return x.last
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue moves the global reputation calculator to the next iteration.
|
|
||||||
func (c *Controller) Continue(ctx context.Context, prm ContinuePrm) {
|
|
||||||
c.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
iterCtx, ok := c.mCtx[prm.Epoch]
|
|
||||||
if !ok {
|
|
||||||
iterCtx = new(iterContext)
|
|
||||||
c.mCtx[prm.Epoch] = iterCtx
|
|
||||||
|
|
||||||
iterCtx.EpochIteration.SetEpoch(prm.Epoch)
|
|
||||||
|
|
||||||
iterations, err := c.prm.IterationsProvider.EigenTrustIterations()
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Error(logs.ControllerCouldNotGetEigenTrustIterationNumber,
|
|
||||||
zap.Error(err),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
iterCtx.iterationNumber = uint32(iterations)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
iterCtx.last = iterCtx.I() == iterCtx.iterationNumber-1
|
|
||||||
|
|
||||||
err := c.prm.WorkerPool.Submit(func() {
|
|
||||||
c.prm.DaughtersTrustCalculator.Calculate(ctx, iterCtx)
|
|
||||||
|
|
||||||
// iteration++
|
|
||||||
iterCtx.Increment()
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.opts.log.Debug(logs.ControllerIterationSubmitFailure,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if iterCtx.last {
|
|
||||||
// will only live while the application is alive.
|
|
||||||
// during normal operation of the system. Also, such information
|
|
||||||
// number as already processed, but in any case it grows up
|
|
||||||
// In this case and worker pool failure we can mark epoch
|
|
||||||
delete(c.mCtx, prm.Epoch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.mtx.Unlock()
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
package eigentrustctrl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Controller's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Component of computing iteration of EigenTrust algorithm.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
DaughtersTrustCalculator DaughtersTrustCalculator
|
|
||||||
|
|
||||||
// IterationsProvider provides information about numbers
|
|
||||||
// of iterations for algorithm.
|
|
||||||
IterationsProvider IterationsProvider
|
|
||||||
|
|
||||||
// Routine execution pool for single epoch iteration.
|
|
||||||
WorkerPool util.WorkerPool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controller represents EigenTrust algorithm transient controller.
|
|
||||||
//
|
|
||||||
// Controller's main goal is to separate the two main stages of
|
|
||||||
// the calculation:
|
|
||||||
// 1. reporting local values to manager nodes
|
|
||||||
// 2. calculating global trusts of child nodes
|
|
||||||
//
|
|
||||||
// Calculation stages are controlled based on external signals
|
|
||||||
// that come from the application through the Controller's API.
|
|
||||||
//
|
|
||||||
// For correct operation, the controller must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the constructor is immediately ready to work through
|
|
||||||
// API of external control of calculations and data transfer.
|
|
||||||
type Controller struct {
|
|
||||||
prm Prm
|
|
||||||
|
|
||||||
opts *options
|
|
||||||
|
|
||||||
mtx sync.Mutex
|
|
||||||
mCtx map[uint64]*iterContext
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Controller.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created Controller does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm, opts ...Option) *Controller {
|
|
||||||
switch {
|
|
||||||
case prm.IterationsProvider == nil:
|
|
||||||
panicOnPrmValue("IterationNumber", prm.IterationsProvider)
|
|
||||||
case prm.WorkerPool == nil:
|
|
||||||
panicOnPrmValue("WorkerPool", prm.WorkerPool)
|
|
||||||
case prm.DaughtersTrustCalculator == nil:
|
|
||||||
panicOnPrmValue("DaughtersTrustCalculator", prm.DaughtersTrustCalculator)
|
|
||||||
}
|
|
||||||
|
|
||||||
o := defaultOpts()
|
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Controller{
|
|
||||||
prm: prm,
|
|
||||||
opts: o,
|
|
||||||
mCtx: make(map[uint64]*iterContext),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package eigentrustctrl
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
// IterationContext is a context of the i-th
|
|
||||||
// stage of iterative EigenTrust algorithm.
|
|
||||||
type IterationContext interface {
|
|
||||||
// Must return epoch number to select the values
|
|
||||||
// for global trust calculation.
|
|
||||||
Epoch() uint64
|
|
||||||
|
|
||||||
// Must return the sequence number of the iteration.
|
|
||||||
I() uint32
|
|
||||||
|
|
||||||
// Must return true if I() is the last iteration.
|
|
||||||
Last() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughtersTrustCalculator is an interface of entity
|
|
||||||
// responsible for calculating the global trust of
|
|
||||||
// daughter nodes in terms of EigenTrust algorithm.
|
|
||||||
type DaughtersTrustCalculator interface {
|
|
||||||
// Must perform the iteration step of the loop
|
|
||||||
// for computing the global trust of all daughter
|
|
||||||
// nodes and sending intermediate values
|
|
||||||
// according to EigenTrust description
|
|
||||||
// http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Ch.5.1.
|
|
||||||
//
|
|
||||||
// Execution should be interrupted if ctx.Last().
|
|
||||||
Calculate(ctx context.Context, iter IterationContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IterationsProvider must provide information about numbers
|
|
||||||
// of iterations for algorithm.
|
|
||||||
type IterationsProvider interface {
|
|
||||||
EigenTrustIterations() (uint64, error)
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package eigentrustctrl
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option sets an optional parameter of Controller.
|
|
||||||
type Option func(*options)
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultOpts() *options {
|
|
||||||
return &options{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns option to specify logging component.
|
|
||||||
//
|
|
||||||
// Ignores nil values.
|
|
||||||
func WithLogger(l *logger.Logger) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package eigentrust
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EpochIteration struct {
|
|
||||||
e uint64
|
|
||||||
i uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x EpochIteration) Epoch() uint64 {
|
|
||||||
return x.e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *EpochIteration) SetEpoch(e uint64) {
|
|
||||||
x.e = e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x EpochIteration) I() uint32 {
|
|
||||||
return x.i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *EpochIteration) SetI(i uint32) {
|
|
||||||
x.i = i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *EpochIteration) Increment() {
|
|
||||||
x.i++
|
|
||||||
}
|
|
||||||
|
|
||||||
type IterationTrust struct {
|
|
||||||
EpochIteration
|
|
||||||
reputation.Trust
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEpochIteration(epoch uint64, iter uint32) *EpochIteration {
|
|
||||||
ei := EpochIteration{}
|
|
||||||
|
|
||||||
ei.SetI(iter)
|
|
||||||
ei.SetEpoch(epoch)
|
|
||||||
|
|
||||||
return &ei
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package routes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Builder's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Manager builder for current node.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
ManagerBuilder common.ManagerBuilder
|
|
||||||
|
|
||||||
Log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builder represents component that routes node to its managers.
|
|
||||||
//
|
|
||||||
// For correct operation, Builder must be created using
|
|
||||||
// the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the Builder is immediately ready to work through API.
|
|
||||||
type Builder struct {
|
|
||||||
managerBuilder common.ManagerBuilder
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Builder.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created Builder does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm) *Builder {
|
|
||||||
switch {
|
|
||||||
case prm.ManagerBuilder == nil:
|
|
||||||
panicOnPrmValue("ManagerBuilder", prm.ManagerBuilder)
|
|
||||||
case prm.Log == nil:
|
|
||||||
panicOnPrmValue("Logger", prm.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Builder{
|
|
||||||
managerBuilder: prm.ManagerBuilder,
|
|
||||||
log: prm.Log,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package routes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NextStage builds Manager list for trusted node and returns it directly.
|
|
||||||
//
|
|
||||||
// If passed route has more than one point, then endpoint of the route is reached.
|
|
||||||
func (b *Builder) NextStage(epoch uint64, t reputation.Trust, passed []common.ServerInfo) ([]common.ServerInfo, error) {
|
|
||||||
passedLen := len(passed)
|
|
||||||
|
|
||||||
b.log.Debug(logs.RoutesBuildingNextStageForTrustRoute,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
zap.Int("passed_length", passedLen),
|
|
||||||
)
|
|
||||||
|
|
||||||
if passedLen > 1 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
route, err := b.managerBuilder.BuildManagers(epoch, t.Peer())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not build managers for epoch: %d: %w", epoch, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return route, nil
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
package consumerstorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust"
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Put saves intermediate trust of the consumer to daughter peer.
|
|
||||||
func (x *Storage) Put(trust eigentrust.IterationTrust) {
|
|
||||||
var s *iterationConsumersStorage
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
epoch := trust.Epoch()
|
|
||||||
|
|
||||||
s = x.mItems[epoch]
|
|
||||||
if s == nil {
|
|
||||||
s = &iterationConsumersStorage{
|
|
||||||
mItems: make(map[uint32]*ConsumersStorage, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mItems[epoch] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
s.put(trust)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consumers returns the storage of trusts of the consumers of the daughter peers
|
|
||||||
// for particular iteration of EigenTrust calculation for particular epoch.
|
|
||||||
//
|
|
||||||
// Returns false if there is no data for the epoch and iter.
|
|
||||||
func (x *Storage) Consumers(epoch uint64, iter uint32) (*ConsumersStorage, bool) {
|
|
||||||
var (
|
|
||||||
s *iterationConsumersStorage
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
s, ok = x.mItems[epoch]
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.consumers(iter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// maps iteration numbers of EigenTrust algorithm to repositories
|
|
||||||
// of the trusts of the consumers of the daughter peers.
|
|
||||||
type iterationConsumersStorage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[uint32]*ConsumersStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *iterationConsumersStorage) put(trust eigentrust.IterationTrust) {
|
|
||||||
var s *ConsumersStorage
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
iter := trust.I()
|
|
||||||
|
|
||||||
s = x.mItems[iter]
|
|
||||||
if s == nil {
|
|
||||||
s = &ConsumersStorage{
|
|
||||||
mItems: make(map[string]*ConsumersTrusts, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mItems[iter] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
s.put(trust)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *iterationConsumersStorage) consumers(iter uint32) (s *ConsumersStorage, ok bool) {
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
s, ok = x.mItems[iter]
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConsumersStorage represents in-memory storage of intermediate trusts
|
|
||||||
// of the peer consumers.
|
|
||||||
//
|
|
||||||
// Maps daughter peers to repositories of the trusts of their consumers.
|
|
||||||
type ConsumersStorage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[string]*ConsumersTrusts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ConsumersStorage) put(trust eigentrust.IterationTrust) {
|
|
||||||
var s *ConsumersTrusts
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
daughter := trust.Peer().EncodeToString()
|
|
||||||
|
|
||||||
s = x.mItems[daughter]
|
|
||||||
if s == nil {
|
|
||||||
s = &ConsumersTrusts{
|
|
||||||
mItems: make(map[string]reputation.Trust, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mItems[daughter] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
s.put(trust)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate passes IDs of the daughter peers with the trusts of their consumers to h.
|
|
||||||
//
|
|
||||||
// Returns errors from h directly.
|
|
||||||
func (x *ConsumersStorage) Iterate(h eigentrustcalc.PeerTrustsHandler) (err error) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
for strTrusted, trusts := range x.mItems {
|
|
||||||
var trusted apireputation.PeerID
|
|
||||||
|
|
||||||
if strTrusted != "" {
|
|
||||||
err = trusted.DecodeString(strTrusted)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("decode peer ID string %s: %v", strTrusted, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h(trusted, trusts); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConsumersTrusts represents in-memory storage of the trusts
|
|
||||||
// of the consumer peers to some other peer.
|
|
||||||
type ConsumersTrusts struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[string]reputation.Trust
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ConsumersTrusts) put(trust eigentrust.IterationTrust) {
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
x.mItems[trust.TrustingPeer().EncodeToString()] = trust.Trust
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate passes all stored trusts to h.
|
|
||||||
//
|
|
||||||
// Returns errors from h directly.
|
|
||||||
func (x *ConsumersTrusts) Iterate(h reputation.TrustHandler) (err error) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
for _, trust := range x.mItems {
|
|
||||||
if err = h(trust); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package consumerstorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Storage's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
//
|
|
||||||
// The component is not parameterizable at the moment.
|
|
||||||
type Prm struct{}
|
|
||||||
|
|
||||||
// Storage represents in-memory storage of the trusts
|
|
||||||
// of the consumer peers.
|
|
||||||
//
|
|
||||||
// It maps epoch numbers to the repositories of intermediate
|
|
||||||
// trusts of the consumers of the daughter peers.
|
|
||||||
//
|
|
||||||
// For correct operation, Storage must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// Storage is immediately ready to work through API.
|
|
||||||
type Storage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[uint64]*iterationConsumersStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Storage.
|
|
||||||
//
|
|
||||||
// The created Storage does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(_ Prm) *Storage {
|
|
||||||
return &Storage{
|
|
||||||
mItems: make(map[uint64]*iterationConsumersStorage),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
package daughters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
eigentrustcalc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/eigentrust/calculator"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Put saves daughter peer's trust to its provider for the epoch.
|
|
||||||
func (x *Storage) Put(epoch uint64, trust reputation.Trust) {
|
|
||||||
var s *DaughterStorage
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
s = x.mItems[epoch]
|
|
||||||
if s == nil {
|
|
||||||
s = &DaughterStorage{
|
|
||||||
mItems: make(map[string]*DaughterTrusts, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mItems[epoch] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
s.put(trust)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughterTrusts returns daughter trusts for the epoch.
|
|
||||||
//
|
|
||||||
// Returns false if there is no data for the epoch and daughter.
|
|
||||||
func (x *Storage) DaughterTrusts(epoch uint64, daughter apireputation.PeerID) (*DaughterTrusts, bool) {
|
|
||||||
var (
|
|
||||||
s *DaughterStorage
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
s, ok = x.mItems[epoch]
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.daughterTrusts(daughter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllDaughterTrusts returns daughter iterator for the epoch.
|
|
||||||
//
|
|
||||||
// Returns false if there is no data for the epoch and daughter.
|
|
||||||
func (x *Storage) AllDaughterTrusts(epoch uint64) (*DaughterStorage, bool) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
defer x.mtx.RUnlock()
|
|
||||||
|
|
||||||
s, ok := x.mItems[epoch]
|
|
||||||
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughterStorage maps IDs of daughter peers to repositories of the local trusts to their providers.
|
|
||||||
type DaughterStorage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[string]*DaughterTrusts
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate passes IDs of the daughter peers with their trusts to h.
|
|
||||||
//
|
|
||||||
// Returns errors from h directly.
|
|
||||||
func (x *DaughterStorage) Iterate(h eigentrustcalc.PeerTrustsHandler) (err error) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
for strDaughter, daughterTrusts := range x.mItems {
|
|
||||||
var daughter apireputation.PeerID
|
|
||||||
|
|
||||||
if strDaughter != "" {
|
|
||||||
err = daughter.DecodeString(strDaughter)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("decode peer ID string %s: %v", strDaughter, err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = h(daughter, daughterTrusts); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DaughterStorage) put(trust reputation.Trust) {
|
|
||||||
var dt *DaughterTrusts
|
|
||||||
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
trusting := trust.TrustingPeer().EncodeToString()
|
|
||||||
|
|
||||||
dt = x.mItems[trusting]
|
|
||||||
if dt == nil {
|
|
||||||
dt = &DaughterTrusts{
|
|
||||||
mItems: make(map[string]reputation.Trust, 1),
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mItems[trusting] = dt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
|
|
||||||
dt.put(trust)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DaughterStorage) daughterTrusts(id apireputation.PeerID) (dt *DaughterTrusts, ok bool) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
dt, ok = x.mItems[id.EncodeToString()]
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DaughterTrusts represents in-memory storage of local trusts
|
|
||||||
// of the daughter peer to its providers.
|
|
||||||
//
|
|
||||||
// Maps IDs of daughter's providers to the local trusts to them.
|
|
||||||
type DaughterTrusts struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[string]reputation.Trust
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DaughterTrusts) put(trust reputation.Trust) {
|
|
||||||
x.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
x.mItems[trust.Peer().EncodeToString()] = trust
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate passes all stored trusts to h.
|
|
||||||
//
|
|
||||||
// Returns errors from h directly.
|
|
||||||
func (x *DaughterTrusts) Iterate(h reputation.TrustHandler) (err error) {
|
|
||||||
x.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
for _, trust := range x.mItems {
|
|
||||||
if err = h(trust); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package daughters
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Storage's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
//
|
|
||||||
// The component is not parameterizable at the moment.
|
|
||||||
type Prm struct{}
|
|
||||||
|
|
||||||
// Storage represents in-memory storage of local trust
|
|
||||||
// values of the daughter peers.
|
|
||||||
//
|
|
||||||
// It maps epoch numbers to the repositories of local trusts
|
|
||||||
// of the daughter peers.
|
|
||||||
//
|
|
||||||
// For correct operation, Storage must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// Storage is immediately ready to work through API.
|
|
||||||
type Storage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[uint64]*DaughterStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Storage.
|
|
||||||
//
|
|
||||||
// The created Storage does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(_ Prm) *Storage {
|
|
||||||
return &Storage{
|
|
||||||
mItems: make(map[uint64]*DaughterStorage),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
package trustcontroller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReportPrm groups the required parameters of the Controller.Report method.
|
|
||||||
type ReportPrm struct {
|
|
||||||
epoch uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEpoch sets epoch number to select reputation values.
|
|
||||||
func (p *ReportPrm) SetEpoch(e uint64) {
|
|
||||||
p.epoch = e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report reports local reputation values.
|
|
||||||
//
|
|
||||||
// Single Report operation overtakes all data from LocalTrustSource
|
|
||||||
// to LocalTrustTarget (Controller's parameters).
|
|
||||||
//
|
|
||||||
// Each call acquires a report context for an Epoch parameter.
|
|
||||||
// At the very end of the operation, the context is released.
|
|
||||||
func (c *Controller) Report(ctx context.Context, prm ReportPrm) {
|
|
||||||
// acquire report
|
|
||||||
rCtx, reporter := c.acquireReporter(ctx, prm.epoch)
|
|
||||||
if reporter == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// report local trust values
|
|
||||||
reporter.report(rCtx)
|
|
||||||
|
|
||||||
// finally stop and free the report
|
|
||||||
c.freeReport(prm.epoch, reporter.log)
|
|
||||||
}
|
|
||||||
|
|
||||||
type reporter struct {
|
|
||||||
epoch uint64
|
|
||||||
|
|
||||||
ctrl *Controller
|
|
||||||
|
|
||||||
log *logger.Logger
|
|
||||||
|
|
||||||
ep common.EpochProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
type epochProvider struct {
|
|
||||||
epoch uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c epochProvider) Epoch() uint64 {
|
|
||||||
return c.epoch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) acquireReporter(ctx context.Context, epoch uint64) (context.Context, *reporter) {
|
|
||||||
started := true
|
|
||||||
|
|
||||||
c.mtx.Lock()
|
|
||||||
{
|
|
||||||
if cancel := c.mCtx[epoch]; cancel == nil {
|
|
||||||
ctx, cancel = context.WithCancel(ctx)
|
|
||||||
c.mCtx[epoch] = cancel
|
|
||||||
started = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.mtx.Unlock()
|
|
||||||
|
|
||||||
log := &logger.Logger{Logger: c.opts.log.With(
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
)}
|
|
||||||
|
|
||||||
if started {
|
|
||||||
log.Debug(logs.ControllerReportIsAlreadyStarted)
|
|
||||||
return ctx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, &reporter{
|
|
||||||
epoch: epoch,
|
|
||||||
ctrl: c,
|
|
||||||
log: log,
|
|
||||||
ep: &epochProvider{
|
|
||||||
epoch: epoch,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *reporter) report(ctx context.Context) {
|
|
||||||
c.log.Debug(logs.ControllerStartingToReportLocalTrustValues)
|
|
||||||
|
|
||||||
// initialize iterator over locally collected values
|
|
||||||
iterator, err := c.ctrl.prm.LocalTrustSource.InitIterator(c.ep)
|
|
||||||
if err != nil {
|
|
||||||
c.log.Debug(logs.ControllerCouldNotInitializeIteratorOverLocalTrustValues,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize target of local trust values
|
|
||||||
targetWriter, err := c.ctrl.prm.LocalTrustTarget.InitWriter(c.ep)
|
|
||||||
if err != nil {
|
|
||||||
c.log.Debug(logs.ControllerCouldNotInitializeLocalTrustTarget,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate over all values and write them to the target
|
|
||||||
err = iterator.Iterate(
|
|
||||||
func(t reputation.Trust) error {
|
|
||||||
// check if context is done
|
|
||||||
if err := ctx.Err(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetWriter.Write(ctx, t)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil && !errors.Is(err, context.Canceled) {
|
|
||||||
c.log.Debug(logs.ControllerIteratorOverLocalTrustFailed,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// finish writing
|
|
||||||
err = targetWriter.Close(ctx)
|
|
||||||
if err != nil {
|
|
||||||
c.log.Debug(logs.ControllerCouldNotFinishWritingLocalTrustValues,
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.log.Debug(logs.ControllerReportingSuccessfullyFinished)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) freeReport(epoch uint64, log *logger.Logger) {
|
|
||||||
var stopped bool
|
|
||||||
|
|
||||||
c.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
var cancel context.CancelFunc
|
|
||||||
|
|
||||||
cancel, stopped = c.mCtx[epoch]
|
|
||||||
|
|
||||||
if stopped {
|
|
||||||
cancel()
|
|
||||||
delete(c.mCtx, epoch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.mtx.Unlock()
|
|
||||||
|
|
||||||
if stopped {
|
|
||||||
log.Debug(logs.ControllerReportingSuccessfullyInterrupted)
|
|
||||||
} else {
|
|
||||||
log.Debug(logs.ControllerReportingIsNotStartedOrAlreadyInterrupted)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopPrm groups the required parameters of the Controller.Stop method.
|
|
||||||
type StopPrm struct {
|
|
||||||
epoch uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEpoch sets epoch number the processing of the values of which must be interrupted.
|
|
||||||
func (p *StopPrm) SetEpoch(e uint64) {
|
|
||||||
p.epoch = e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop interrupts the processing of local trust values.
|
|
||||||
//
|
|
||||||
// Releases acquired report context.
|
|
||||||
func (c *Controller) Stop(prm StopPrm) {
|
|
||||||
c.freeReport(
|
|
||||||
prm.epoch,
|
|
||||||
&logger.Logger{Logger: c.opts.log.With(zap.Uint64("epoch", prm.epoch))},
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package trustcontroller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
reputationrouter "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common/router"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Controller's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Iterator over the reputation values
|
|
||||||
// collected by the node locally.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
LocalTrustSource IteratorProvider
|
|
||||||
|
|
||||||
// Place of recording the local values of
|
|
||||||
// trust to other nodes.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
LocalTrustTarget *reputationrouter.Router
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controller represents main handler for starting
|
|
||||||
// and interrupting the reporting local trust values.
|
|
||||||
//
|
|
||||||
// It binds the interfaces of the local value stores
|
|
||||||
// to the target storage points. Controller is abstracted
|
|
||||||
// from the internal storage device and the network location
|
|
||||||
// of the connecting components. At its core, it is a
|
|
||||||
// high-level start-stop trigger for reporting.
|
|
||||||
//
|
|
||||||
// For correct operation, the controller must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the constructor is immediately ready to work through
|
|
||||||
// API of external control of calculations and data transfer.
|
|
||||||
type Controller struct {
|
|
||||||
prm Prm
|
|
||||||
|
|
||||||
opts *options
|
|
||||||
|
|
||||||
mtx sync.Mutex
|
|
||||||
mCtx map[uint64]context.CancelFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Controller.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created Controller does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm, opts ...Option) *Controller {
|
|
||||||
switch {
|
|
||||||
case prm.LocalTrustSource == nil:
|
|
||||||
panicOnPrmValue("LocalTrustSource", prm.LocalTrustSource)
|
|
||||||
case prm.LocalTrustTarget == nil:
|
|
||||||
panicOnPrmValue("LocalTrustTarget", prm.LocalTrustTarget)
|
|
||||||
}
|
|
||||||
|
|
||||||
o := defaultOpts()
|
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Controller{
|
|
||||||
prm: prm,
|
|
||||||
opts: o,
|
|
||||||
mCtx: make(map[uint64]context.CancelFunc),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package trustcontroller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Iterator is a group of methods provided by entity
|
|
||||||
// which can iterate over a group of reputation.Trust values.
|
|
||||||
type Iterator interface {
|
|
||||||
// Iterate must start an iterator over all trust values.
|
|
||||||
// For each value should call a handler, the error
|
|
||||||
// of which should be directly returned from the method.
|
|
||||||
//
|
|
||||||
// Internal failures of the iterator are also signaled via
|
|
||||||
// an error. After a successful call to the last value
|
|
||||||
// handler, nil should be returned.
|
|
||||||
Iterate(reputation.TrustHandler) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// IteratorProvider is a group of methods provided
|
|
||||||
// by entity which generates iterators over
|
|
||||||
// reputation.Trust values.
|
|
||||||
type IteratorProvider interface {
|
|
||||||
// InitIterator should return an initialized Iterator
|
|
||||||
// that iterates over values from IteratorContext.Epoch() epoch.
|
|
||||||
//
|
|
||||||
// Initialization problems are reported via error.
|
|
||||||
// If no error was returned, then the Iterator must not be nil.
|
|
||||||
//
|
|
||||||
// Implementations can have different logic for different
|
|
||||||
// contexts, so specific ones may document their own behavior.
|
|
||||||
InitIterator(common.EpochProvider) (Iterator, error)
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package trustcontroller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option sets an optional parameter of Controller.
|
|
||||||
type Option func(*options)
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultOpts() *options {
|
|
||||||
return &options{
|
|
||||||
log: &logger.Logger{Logger: zap.L()},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLogger returns option to specify logging component.
|
|
||||||
//
|
|
||||||
// Ignores nil values.
|
|
||||||
func WithLogger(l *logger.Logger) Option {
|
|
||||||
return func(o *options) {
|
|
||||||
if l != nil {
|
|
||||||
o.log = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package trustcontroller
|
|
||||||
|
|
||||||
import "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
|
|
||||||
type storageWrapper struct {
|
|
||||||
w common.Writer
|
|
||||||
i Iterator
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s storageWrapper) InitIterator(common.EpochProvider) (Iterator, error) {
|
|
||||||
return s.i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s storageWrapper) InitWriter(common.EpochProvider) (common.Writer, error) {
|
|
||||||
return s.w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleIteratorProvider returns IteratorProvider that provides
|
|
||||||
// static context-independent Iterator.
|
|
||||||
func SimpleIteratorProvider(i Iterator) IteratorProvider {
|
|
||||||
return &storageWrapper{
|
|
||||||
i: i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleWriterProvider returns WriterProvider that provides
|
|
||||||
// static context-independent Writer.
|
|
||||||
func SimpleWriterProvider(w common.Writer) common.WriterProvider {
|
|
||||||
return &storageWrapper{
|
|
||||||
w: w,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package routes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Builder's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct {
|
|
||||||
// Manager builder for current node.
|
|
||||||
//
|
|
||||||
// Must not be nil.
|
|
||||||
ManagerBuilder common.ManagerBuilder
|
|
||||||
|
|
||||||
Log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builder represents component that routes node to its managers.
|
|
||||||
//
|
|
||||||
// For correct operation, Builder must be created using
|
|
||||||
// the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// the Builder is immediately ready to work through API.
|
|
||||||
type Builder struct {
|
|
||||||
managerBuilder common.ManagerBuilder
|
|
||||||
log *logger.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
const invalidPrmValFmt = "invalid parameter %s (%T):%v"
|
|
||||||
|
|
||||||
func panicOnPrmValue(n string, v any) {
|
|
||||||
panic(fmt.Sprintf(invalidPrmValFmt, n, v, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Builder.
|
|
||||||
//
|
|
||||||
// Panics if at least one value of the parameters is invalid.
|
|
||||||
//
|
|
||||||
// The created Builder does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm) *Builder {
|
|
||||||
switch {
|
|
||||||
case prm.ManagerBuilder == nil:
|
|
||||||
panicOnPrmValue("ManagerBuilder", prm.ManagerBuilder)
|
|
||||||
case prm.Log == nil:
|
|
||||||
panicOnPrmValue("Logger", prm.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Builder{
|
|
||||||
managerBuilder: prm.ManagerBuilder,
|
|
||||||
log: prm.Log,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package routes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation/common"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NextStage builds Manager list for trusting node and returns it directly.
|
|
||||||
//
|
|
||||||
// If passed route has more than one point, then endpoint of the route is reached.
|
|
||||||
func (b *Builder) NextStage(epoch uint64, t reputation.Trust, passed []common.ServerInfo) ([]common.ServerInfo, error) {
|
|
||||||
passedLen := len(passed)
|
|
||||||
|
|
||||||
b.log.Debug(logs.RoutesBuildingNextStageForLocalTrustRoute,
|
|
||||||
zap.Uint64("epoch", epoch),
|
|
||||||
zap.Int("passed_length", passedLen),
|
|
||||||
)
|
|
||||||
|
|
||||||
if passedLen > 1 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
route, err := b.managerBuilder.BuildManagers(epoch, t.TrustingPeer())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not build managers for epoch: %d: %w", epoch, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return route, nil
|
|
||||||
}
|
|
|
@ -1,175 +0,0 @@
|
||||||
package truststorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/reputation"
|
|
||||||
apireputation "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpdatePrm groups the parameters of Storage's Update operation.
|
|
||||||
type UpdatePrm struct {
|
|
||||||
sat bool
|
|
||||||
|
|
||||||
epoch uint64
|
|
||||||
|
|
||||||
peer apireputation.PeerID
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEpoch sets number of the epoch
|
|
||||||
// when the interaction happened.
|
|
||||||
func (p *UpdatePrm) SetEpoch(e uint64) {
|
|
||||||
p.epoch = e
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPeer sets identifier of the peer
|
|
||||||
// with which the local node interacted.
|
|
||||||
func (p *UpdatePrm) SetPeer(id apireputation.PeerID) {
|
|
||||||
p.peer = id
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSatisfactory sets successful completion status.
|
|
||||||
func (p *UpdatePrm) SetSatisfactory(sat bool) {
|
|
||||||
p.sat = sat
|
|
||||||
}
|
|
||||||
|
|
||||||
type trustValue struct {
|
|
||||||
sat, all int
|
|
||||||
}
|
|
||||||
|
|
||||||
// EpochTrustValueStorage represents storage of
|
|
||||||
// the trust values by particular epoch.
|
|
||||||
type EpochTrustValueStorage struct {
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[string]*trustValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTrustValueStorage() *EpochTrustValueStorage {
|
|
||||||
return &EpochTrustValueStorage{
|
|
||||||
mItems: make(map[string]*trustValue, 1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifyPeerID(id apireputation.PeerID) string {
|
|
||||||
return string(id.PublicKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
func peerIDFromString(str string) (res apireputation.PeerID) {
|
|
||||||
res.SetPublicKey([]byte(str))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *EpochTrustValueStorage) update(prm UpdatePrm) {
|
|
||||||
s.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
strID := stringifyPeerID(prm.peer)
|
|
||||||
|
|
||||||
val, ok := s.mItems[strID]
|
|
||||||
if !ok {
|
|
||||||
val = new(trustValue)
|
|
||||||
s.mItems[strID] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
if prm.sat {
|
|
||||||
val.sat++
|
|
||||||
}
|
|
||||||
|
|
||||||
val.all++
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update updates the number of satisfactory transactions with peer.
|
|
||||||
func (s *Storage) Update(prm UpdatePrm) {
|
|
||||||
var trustStorage *EpochTrustValueStorage
|
|
||||||
|
|
||||||
s.mtx.Lock()
|
|
||||||
|
|
||||||
{
|
|
||||||
var (
|
|
||||||
ok bool
|
|
||||||
epoch = prm.epoch
|
|
||||||
)
|
|
||||||
|
|
||||||
trustStorage, ok = s.mItems[epoch]
|
|
||||||
if !ok {
|
|
||||||
trustStorage = newTrustValueStorage()
|
|
||||||
s.mItems[epoch] = trustStorage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mtx.Unlock()
|
|
||||||
|
|
||||||
trustStorage.update(prm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNoPositiveTrust is returned by iterator when
|
|
||||||
// there is no positive number of successful transactions.
|
|
||||||
var ErrNoPositiveTrust = errors.New("no positive trust")
|
|
||||||
|
|
||||||
// DataForEpoch returns EpochValueStorage for epoch.
|
|
||||||
//
|
|
||||||
// If there is no data for the epoch, ErrNoPositiveTrust returns.
|
|
||||||
func (s *Storage) DataForEpoch(epoch uint64) (*EpochTrustValueStorage, error) {
|
|
||||||
s.mtx.RLock()
|
|
||||||
trustStorage, ok := s.mItems[epoch]
|
|
||||||
s.mtx.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, ErrNoPositiveTrust
|
|
||||||
}
|
|
||||||
|
|
||||||
return trustStorage, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate iterates over normalized trust values and passes them to parameterized handler.
|
|
||||||
//
|
|
||||||
// Values are normalized according to http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Chapter 4.5.
|
|
||||||
// If divisor in formula is zero, ErrNoPositiveTrust returns.
|
|
||||||
func (s *EpochTrustValueStorage) Iterate(h reputation.TrustHandler) (err error) {
|
|
||||||
s.mtx.RLock()
|
|
||||||
|
|
||||||
{
|
|
||||||
var (
|
|
||||||
sum reputation.TrustValue
|
|
||||||
mVals = make(map[string]reputation.TrustValue, len(s.mItems))
|
|
||||||
)
|
|
||||||
|
|
||||||
// iterate first time to calculate normalizing divisor
|
|
||||||
for strID, val := range s.mItems {
|
|
||||||
if val.all > 0 {
|
|
||||||
num := reputation.TrustValueFromInt(val.sat)
|
|
||||||
denom := reputation.TrustValueFromInt(val.all)
|
|
||||||
|
|
||||||
v := num.Div(denom)
|
|
||||||
|
|
||||||
mVals[strID] = v
|
|
||||||
|
|
||||||
sum.Add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ErrNoPositiveTrust
|
|
||||||
|
|
||||||
if !sum.IsZero() {
|
|
||||||
for strID, val := range mVals {
|
|
||||||
t := reputation.Trust{}
|
|
||||||
|
|
||||||
t.SetPeer(peerIDFromString(strID))
|
|
||||||
t.SetValue(val.Div(sum))
|
|
||||||
|
|
||||||
if err = h(t); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mtx.RUnlock()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package truststorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Storage's constructor.
|
|
||||||
//
|
|
||||||
// All values must comply with the requirements imposed on them.
|
|
||||||
// Passing incorrect parameter values will result in constructor
|
|
||||||
// failure (error or panic depending on the implementation).
|
|
||||||
type Prm struct{}
|
|
||||||
|
|
||||||
// Storage represents in-memory storage of
|
|
||||||
// local reputation values.
|
|
||||||
//
|
|
||||||
// Storage provides access to normalized local trust
|
|
||||||
// values through iterator interface.
|
|
||||||
//
|
|
||||||
// For correct operation, Storage must be created
|
|
||||||
// using the constructor (New) based on the required parameters
|
|
||||||
// and optional components. After successful creation,
|
|
||||||
// Storage is immediately ready to work through API.
|
|
||||||
type Storage struct {
|
|
||||||
prm Prm
|
|
||||||
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
mItems map[uint64]*EpochTrustValueStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new instance of the Storage.
|
|
||||||
//
|
|
||||||
// The created Storage does not require additional
|
|
||||||
// initialization and is completely ready for work.
|
|
||||||
func New(prm Prm) *Storage {
|
|
||||||
return &Storage{
|
|
||||||
prm: prm,
|
|
||||||
mItems: make(map[uint64]*EpochTrustValueStorage),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package reputationrpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/util"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/util/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
type responseService struct {
|
|
||||||
respSvc *response.Service
|
|
||||||
|
|
||||||
svc Server
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResponseService returns reputation service server instance that passes
|
|
||||||
// internal service call to response service.
|
|
||||||
func NewResponseService(cnrSvc Server, respSvc *response.Service) Server {
|
|
||||||
return &responseService{
|
|
||||||
respSvc: respSvc,
|
|
||||||
svc: cnrSvc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *responseService) AnnounceLocalTrust(ctx context.Context, req *reputation.AnnounceLocalTrustRequest) (*reputation.AnnounceLocalTrustResponse, error) {
|
|
||||||
resp, err := s.respSvc.HandleUnaryRequest(ctx, req,
|
|
||||||
func(ctx context.Context, req any) (util.ResponseMessage, error) {
|
|
||||||
return s.svc.AnnounceLocalTrust(ctx, req.(*reputation.AnnounceLocalTrustRequest))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.(*reputation.AnnounceLocalTrustResponse), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *responseService) AnnounceIntermediateResult(ctx context.Context, req *reputation.AnnounceIntermediateResultRequest) (*reputation.AnnounceIntermediateResultResponse, error) {
|
|
||||||
resp, err := s.respSvc.HandleUnaryRequest(ctx, req,
|
|
||||||
func(ctx context.Context, req any) (util.ResponseMessage, error) {
|
|
||||||
return s.svc.AnnounceIntermediateResult(ctx, req.(*reputation.AnnounceIntermediateResultRequest))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.(*reputation.AnnounceIntermediateResultResponse), nil
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package reputationrpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Server is an interface of the FrostFS API v2 Reputation service server.
|
|
||||||
type Server interface {
|
|
||||||
AnnounceLocalTrust(context.Context, *reputation.AnnounceLocalTrustRequest) (*reputation.AnnounceLocalTrustResponse, error)
|
|
||||||
AnnounceIntermediateResult(context.Context, *reputation.AnnounceIntermediateResultRequest) (*reputation.AnnounceIntermediateResultResponse, error)
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package reputationrpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/reputation"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
type signService struct {
|
|
||||||
sigSvc *util.SignService
|
|
||||||
|
|
||||||
svc Server
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSignService(key *ecdsa.PrivateKey, svc Server) Server {
|
|
||||||
return &signService{
|
|
||||||
sigSvc: util.NewUnarySignService(key),
|
|
||||||
svc: svc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *signService) AnnounceLocalTrust(ctx context.Context, req *reputation.AnnounceLocalTrustRequest) (*reputation.AnnounceLocalTrustResponse, error) {
|
|
||||||
resp, err := s.sigSvc.HandleUnaryRequest(ctx, req,
|
|
||||||
func(ctx context.Context, req any) (util.ResponseMessage, error) {
|
|
||||||
return s.svc.AnnounceLocalTrust(ctx, req.(*reputation.AnnounceLocalTrustRequest))
|
|
||||||
},
|
|
||||||
func() util.ResponseMessage {
|
|
||||||
return new(reputation.AnnounceLocalTrustResponse)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.(*reputation.AnnounceLocalTrustResponse), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *signService) AnnounceIntermediateResult(ctx context.Context, req *reputation.AnnounceIntermediateResultRequest) (*reputation.AnnounceIntermediateResultResponse, error) {
|
|
||||||
resp, err := s.sigSvc.HandleUnaryRequest(ctx, req,
|
|
||||||
func(ctx context.Context, req any) (util.ResponseMessage, error) {
|
|
||||||
return s.svc.AnnounceIntermediateResult(ctx, req.(*reputation.AnnounceIntermediateResultRequest))
|
|
||||||
},
|
|
||||||
func() util.ResponseMessage {
|
|
||||||
return new(reputation.AnnounceIntermediateResultResponse)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.(*reputation.AnnounceIntermediateResultResponse), nil
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
package reputation
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/reputation"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TrustValue represents the numeric value of the node's trust.
|
|
||||||
type TrustValue float64
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TrustOne is a trust value equal to one.
|
|
||||||
TrustOne = TrustValue(1)
|
|
||||||
|
|
||||||
// TrustZero is a trust value equal to zero.
|
|
||||||
TrustZero = TrustValue(0)
|
|
||||||
)
|
|
||||||
|
|
||||||
// TrustValueFromFloat64 converts float64 to TrustValue.
|
|
||||||
func TrustValueFromFloat64(v float64) TrustValue {
|
|
||||||
return TrustValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustValueFromInt converts int to TrustValue.
|
|
||||||
func TrustValueFromInt(v int) TrustValue {
|
|
||||||
return TrustValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v TrustValue) String() string {
|
|
||||||
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 converts TrustValue to float64.
|
|
||||||
func (v TrustValue) Float64() float64 {
|
|
||||||
return float64(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds v2 to v.
|
|
||||||
func (v *TrustValue) Add(v2 TrustValue) {
|
|
||||||
*v = *v + v2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Div returns the result of dividing v by v2.
|
|
||||||
func (v TrustValue) Div(v2 TrustValue) TrustValue {
|
|
||||||
return v / v2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mul multiplies v by v2.
|
|
||||||
func (v *TrustValue) Mul(v2 TrustValue) {
|
|
||||||
*v *= v2
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsZero returns true if v equal to zero.
|
|
||||||
func (v TrustValue) IsZero() bool {
|
|
||||||
return v == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trust represents peer's trust (reputation).
|
|
||||||
type Trust struct {
|
|
||||||
trusting, peer reputation.PeerID
|
|
||||||
|
|
||||||
val TrustValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustHandler describes the signature of the reputation.Trust
|
|
||||||
// value handling function.
|
|
||||||
//
|
|
||||||
// Termination of processing without failures is usually signaled
|
|
||||||
// with a zero error, while a specific value may describe the reason
|
|
||||||
// for failure.
|
|
||||||
type TrustHandler func(Trust) error
|
|
||||||
|
|
||||||
// Value returns peer's trust value.
|
|
||||||
func (t Trust) Value() TrustValue {
|
|
||||||
return t.val
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue sets peer's trust value.
|
|
||||||
func (t *Trust) SetValue(val TrustValue) {
|
|
||||||
t.val = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peer returns trusted peer ID.
|
|
||||||
func (t Trust) Peer() reputation.PeerID {
|
|
||||||
return t.peer
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPeer sets trusted peer ID.
|
|
||||||
func (t *Trust) SetPeer(id reputation.PeerID) {
|
|
||||||
t.peer = id
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrustingPeer returns trusting peer ID.
|
|
||||||
func (t Trust) TrustingPeer() reputation.PeerID {
|
|
||||||
return t.trusting
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTrustingPeer sets trusting peer ID.
|
|
||||||
func (t *Trust) SetTrustingPeer(id reputation.PeerID) {
|
|
||||||
t.trusting = id
|
|
||||||
}
|
|
Loading…
Reference in a new issue