From e8885d72f42c521d893a23280a1c207f0f6c20b4 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Fri, 23 Apr 2021 17:49:23 +0300 Subject: [PATCH] [#488] reputation/remoteProvider: Implement intermediate remote Move common remoteProvider code to cmd/reputation/common. Hide WriterProvider initialization behind interface and add implementation of that interface to local and intermediate packages in cmd/reputation directory. Signed-off-by: Pavel Karpy --- cmd/neofs-node/reputation/common/remote.go | 90 +++++++++++++ .../reputation/intermediate/remote.go | 120 ++++++++++++++++++ cmd/neofs-node/reputation/local/remote.go | 89 ++++--------- go.sum | Bin 60232 -> 59798 bytes 4 files changed, 235 insertions(+), 64 deletions(-) create mode 100644 cmd/neofs-node/reputation/common/remote.go create mode 100644 cmd/neofs-node/reputation/intermediate/remote.go diff --git a/cmd/neofs-node/reputation/common/remote.go b/cmd/neofs-node/reputation/common/remote.go new file mode 100644 index 000000000..66d3d7838 --- /dev/null +++ b/cmd/neofs-node/reputation/common/remote.go @@ -0,0 +1,90 @@ +package common + +import ( + apiClient "github.com/nspcc-dev/neofs-api-go/pkg/client" + "github.com/nspcc-dev/neofs-node/pkg/network" + reputationcommon "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common" + reputationrouter "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common/router" + trustcontroller "github.com/nspcc-dev/neofs-node/pkg/services/reputation/local/controller" + "github.com/pkg/errors" +) + +type clientCache interface { + Get(string) (apiClient.Client, error) +} + +// clientKeyRemoteProvider must provide remote writer and take into account +// that requests must be sent via passed api client and must be signed with +// passed private key. +type clientKeyRemoteProvider interface { + WithClient(apiClient.Client) reputationcommon.WriterProvider +} + +// remoteTrustProvider is implementation of reputation RemoteWriterProvider interface. +// It caches clients, checks if it is the end of the route and checks either current +// node is remote target or not. +// +// remoteTrustProvider requires to be provided with clientKeyRemoteProvider. +type remoteTrustProvider struct { + localAddrSrc network.LocalAddressSource + deadEndProvider reputationcommon.WriterProvider + clientCache clientCache + remoteProvider clientKeyRemoteProvider +} + +// 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 { + LocalAddrSrc network.LocalAddressSource + DeadEndProvider reputationcommon.WriterProvider + ClientCache clientCache + WriterProvider clientKeyRemoteProvider +} + +func NewRemoteTrustProvider(prm RemoteProviderPrm) reputationrouter.RemoteWriterProvider { + switch { + case prm.LocalAddrSrc == nil: + PanicOnPrmValue("LocalAddrSrc", prm.LocalAddrSrc) + case prm.DeadEndProvider == nil: + PanicOnPrmValue("DeadEndProvider", prm.DeadEndProvider) + case prm.ClientCache == nil: + PanicOnPrmValue("ClientCache", prm.ClientCache) + case prm.WriterProvider == nil: + PanicOnPrmValue("WriterProvider", prm.WriterProvider) + } + + return &remoteTrustProvider{ + localAddrSrc: prm.LocalAddrSrc, + deadEndProvider: prm.DeadEndProvider, + clientCache: prm.ClientCache, + remoteProvider: prm.WriterProvider, + } +} + +func (rtp *remoteTrustProvider) InitRemote(srv reputationcommon.ServerInfo) (reputationcommon.WriterProvider, error) { + if srv == nil { + return rtp.deadEndProvider, nil + } + + addr := srv.Address() + + if rtp.localAddrSrc.LocalAddress().String() == srv.Address() { + // if local => return no-op writer + return trustcontroller.SimpleWriterProvider(new(NopReputationWriter)), nil + } + + ipAddr, err := network.IPAddrFromMultiaddr(addr) + if err != nil { + return nil, errors.Wrap(err, "could not convert address to IP format") + } + + c, err := rtp.clientCache.Get(ipAddr) + if err != nil { + return nil, errors.Wrap(err, "could not initialize API client") + } + + return rtp.remoteProvider.WithClient(c), nil +} diff --git a/cmd/neofs-node/reputation/intermediate/remote.go b/cmd/neofs-node/reputation/intermediate/remote.go new file mode 100644 index 000000000..6120491d0 --- /dev/null +++ b/cmd/neofs-node/reputation/intermediate/remote.go @@ -0,0 +1,120 @@ +package intermediate + +import ( + "crypto/ecdsa" + apiClient "github.com/nspcc-dev/neofs-api-go/pkg/client" + reputationapi "github.com/nspcc-dev/neofs-api-go/pkg/reputation" + "github.com/nspcc-dev/neofs-node/cmd/neofs-node/reputation/common" + "github.com/nspcc-dev/neofs-node/pkg/services/reputation" + reputationcommon "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common" + eigentrustcalc "github.com/nspcc-dev/neofs-node/pkg/services/reputation/eigentrust/calculator" +) + +// 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 +} + +// 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) + } + + return &RemoteProvider{ + key: prm.Key, + } +} + +// RemoteProvider is an implementation of the clientKeyRemoteProvider interface. +type RemoteProvider struct { + key *ecdsa.PrivateKey +} + +func (rp RemoteProvider) WithClient(c apiClient.Client) reputationcommon.WriterProvider { + return &TrustWriterProvider{ + client: c, + key: rp.key, + } +} + +type TrustWriterProvider struct { + client apiClient.Client + key *ecdsa.PrivateKey +} + +func (twp *TrustWriterProvider) InitWriter(ctx reputationcommon.Context) (reputationcommon.Writer, error) { + return &RemoteTrustWriter{ + ctx: ctx, + client: twp.client, + key: twp.key, + }, nil +} + +type RemoteTrustWriter struct { + ctx reputationcommon.Context + client apiClient.Client + key *ecdsa.PrivateKey + + buf []*apiClient.SendIntermediateTrustPrm +} + +// Write check if passed context contains required +// data(returns ErrIncorrectContext if not) and +// caches passed trusts(as SendIntermediateTrustPrm structs). +func (rtp *RemoteTrustWriter) Write(ctx reputationcommon.Context, t reputation.Trust) error { + eiContext, ok := ctx.(eigentrustcalc.Context) + if !ok { + return ErrIncorrectContext + } + + apiTrustingPeer := reputationapi.NewPeerID() + apiTrustingPeer.SetPublicKey(t.TrustingPeer()) + + apiTrustedPeer := reputationapi.NewPeerID() + apiTrustedPeer.SetPublicKey(t.Peer()) + + apiTrust := reputationapi.NewTrust() + apiTrust.SetValue(t.Value().Float64()) + apiTrust.SetPeer(apiTrustedPeer) + + apiPeerToPeerTrust := reputationapi.NewPeerToPeerTrust() + apiPeerToPeerTrust.SetTrustingPeer(apiTrustingPeer) + apiPeerToPeerTrust.SetTrust(apiTrust) + + p := &apiClient.SendIntermediateTrustPrm{} + p.SetEpoch(eiContext.Epoch()) + p.SetIteration(eiContext.I()) + p.SetTrust(apiPeerToPeerTrust) + + rtp.buf = append(rtp.buf, p) + + return nil +} + +// Close sends all cached intermediate trusts. +// If error occurs, returns in immediately and stops iteration. +func (rtp *RemoteTrustWriter) Close() (err error) { + for _, prm := range rtp.buf { + _, err = rtp.client.SendIntermediateTrust( + rtp.ctx, + *prm, + apiClient.WithKey(rtp.key), + ) + if err != nil { + return + } + } + + return +} diff --git a/cmd/neofs-node/reputation/local/remote.go b/cmd/neofs-node/reputation/local/remote.go index e4d9c2482..9a9bb61f9 100644 --- a/cmd/neofs-node/reputation/local/remote.go +++ b/cmd/neofs-node/reputation/local/remote.go @@ -5,98 +5,59 @@ import ( apiClient "github.com/nspcc-dev/neofs-api-go/pkg/client" reputationapi "github.com/nspcc-dev/neofs-api-go/pkg/reputation" - reputationutil "github.com/nspcc-dev/neofs-node/cmd/neofs-node/reputation/common" - "github.com/nspcc-dev/neofs-node/pkg/network" + "github.com/nspcc-dev/neofs-node/cmd/neofs-node/reputation/common" "github.com/nspcc-dev/neofs-node/pkg/services/reputation" reputationcommon "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common" - reputationrouter "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common/router" - trustcontroller "github.com/nspcc-dev/neofs-node/pkg/services/reputation/local/controller" - "github.com/pkg/errors" ) -type clientCache interface { - Get(string) (apiClient.Client, error) -} - -// remoteTrustProvider is implementation of reputation RemoteWriterProvider interface. -type remoteTrustProvider struct { - localAddrSrc network.LocalAddressSource - deadEndProvider reputationcommon.WriterProvider - key *ecdsa.PrivateKey - - clientCache clientCache -} - -// RemoteProviderPrm groups the required parameters of the remoteTrustProvider's constructor. +// 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 { - LocalAddrSrc network.LocalAddressSource - DeadEndProvider reputationcommon.WriterProvider - Key *ecdsa.PrivateKey - ClientCache clientCache + Key *ecdsa.PrivateKey } -func NewRemoteTrustProvider(prm RemoteProviderPrm) reputationrouter.RemoteWriterProvider { +// 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.LocalAddrSrc == nil: - reputationutil.PanicOnPrmValue("LocalAddrSrc", prm.LocalAddrSrc) - case prm.DeadEndProvider == nil: - reputationutil.PanicOnPrmValue("DeadEndProvider", prm.DeadEndProvider) case prm.Key == nil: - reputationutil.PanicOnPrmValue("Key", prm.Key) - case prm.ClientCache == nil: - reputationutil.PanicOnPrmValue("ClientCache", prm.ClientCache) + common.PanicOnPrmValue("NetMapSource", prm.Key) } - return &remoteTrustProvider{ - localAddrSrc: prm.LocalAddrSrc, - deadEndProvider: prm.DeadEndProvider, - key: prm.Key, - clientCache: prm.ClientCache, + return &RemoteProvider{ + key: prm.Key, } } -func (rtp *remoteTrustProvider) InitRemote(srv reputationrouter.ServerInfo) (reputationcommon.WriterProvider, error) { - if srv == nil { - return rtp.deadEndProvider, nil - } +// RemoteProvider is an implementation of the clientKeyRemoteProvider interface. +type RemoteProvider struct { + key *ecdsa.PrivateKey +} - addr := srv.Address() - - if rtp.localAddrSrc.LocalAddress().String() == srv.Address() { - // if local => return no-op writer - return trustcontroller.SimpleWriterProvider(new(reputationutil.NopReputationWriter)), nil - } - - ipAddr, err := network.IPAddrFromMultiaddr(addr) - if err != nil { - return nil, errors.Wrap(err, "could not convert address to IP format") - } - - c, err := rtp.clientCache.Get(ipAddr) - if err != nil { - return nil, errors.Wrap(err, "could not initialize API client") - } - - return &RemoteTrustWriterProvider{ +func (rp RemoteProvider) WithClient(c apiClient.Client) reputationcommon.WriterProvider { + return &TrustWriterProvider{ client: c, - key: rtp.key, - }, nil + key: rp.key, + } } -type RemoteTrustWriterProvider struct { +type TrustWriterProvider struct { client apiClient.Client key *ecdsa.PrivateKey } -func (rtwp *RemoteTrustWriterProvider) InitWriter(ctx reputationcommon.Context) (reputationcommon.Writer, error) { +func (twp *TrustWriterProvider) InitWriter(ctx reputationcommon.Context) (reputationcommon.Writer, error) { return &RemoteTrustWriter{ ctx: ctx, - client: rtwp.client, - key: rtwp.key, + client: twp.client, + key: twp.key, }, nil } diff --git a/go.sum b/go.sum index fed37d89063dee350c00709aa9ff2bee5c0c2d1e..036b5c4bc042f34f5eec613481575a7cc01d77ff 100644 GIT binary patch delta 18 acmX?cjd|K-<_)n~lP6?zZI;Z@uLl5BJ_rK< delta 174 zcmbPsnfb&u<_)n~1_lZlhE^Hnh9M!D#`?zP&Q4Co-hO7umC2>P7QuP?zHWJm1;K#@ zB~BF<-svu$k&_cr#V31Z2~Yl$neAd=X<%V$ZepZsVQ6HLVrprTVqjzhGSJ)9FGt%w zJH;@=CB4M3I6EN6GN2@_syNToyP~`(uhg+LB;U=T&^aJ29crMgC|1KZ|IM6P4*