Skip to content

Commit

Permalink
ir: Check that just bootstrapped SN is available
Browse files Browse the repository at this point in the history
Closes nspcc-dev#2475.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
  • Loading branch information
carpawell committed Sep 4, 2023
1 parent 9224e9f commit 30fba81
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ minor release, the component will be purged, so be prepared (see `Updating` sect
- `neofs-cli object nodes` command to get SNs for an object (#2512)
- Fetching container estimations via iterators to prevent NeoVM stack overflow (#2173)
- `neofs-adm morph netmap-candidates` CLI command (#1889)
- SN network validation (is available by its announced addresses) on bootstrap by the IR (#2475)

### Fixed
- `neo-go` RPC connection loss handling (#1337)
Expand Down
1 change: 1 addition & 0 deletions pkg/core/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Client interface {
AnnounceLocalTrust(ctx context.Context, epoch uint64, trusts []reputationSDK.Trust, prm client.PrmAnnounceLocalTrust) error
AnnounceIntermediateTrust(ctx context.Context, epoch uint64, trust reputationSDK.PeerToPeerTrust, prm client.PrmAnnounceIntermediateTrust) error
ExecRaw(f func(client *rawclient.Client) error) error
EndpointInfo(ctx context.Context, prm client.PrmEndpointInfo) (*client.ResEndpointInfo, error)
Close() error
}

Expand Down
1 change: 1 addition & 0 deletions pkg/innerring/innerring.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper, errChan chan<-
locodeValidator,
),
NodeStateSettings: netSettings,
ClientSource: clientCache,
})
if err != nil {
return nil, err
Expand Down
95 changes: 95 additions & 0 deletions pkg/innerring/processors/netmap/process_peers.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package netmap

import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"

clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
netmapCore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
netmapEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
"github.com/nspcc-dev/neofs-sdk-go/client"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -37,6 +44,37 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
return
}

var info clientcore.NodeInfo
err = clientcore.NodeInfoFromRawNetmapElement(&info, netmapCore.Node(nodeInfo))
if err != nil {
np.log.Warn("could not convert node info: %w", zap.Error(err))
return
}

c, err := np.clientSource.Get(info)
if err != nil {
np.log.Warn("could not create client to the node: %w",
zap.Error(err),
zap.String("node", hex.EncodeToString(info.PublicKey())))
return
}

res, err := c.EndpointInfo(context.Background(), client.PrmEndpointInfo{})
if err != nil {
np.log.Warn("could not ping node with `EndpointInfo`",
zap.Error(err),
zap.String("node", hex.EncodeToString(info.PublicKey())))
return
}

err = compareNodeInfos(nodeInfo, res.NodeInfo())
if err != nil && !errors.Is(err, errUnknownDifference) {
np.log.Warn("correct node info, but `EndpointInfo` result differs",
zap.Error(err),
zap.String("node", hex.EncodeToString(info.PublicKey())))
return
}

// validate and update node info
err = np.nodeValidator.VerifyAndUpdate(&nodeInfo)
if err != nil {
Expand Down Expand Up @@ -116,3 +154,60 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
np.log.Error("can't invoke netmap.UpdatePeer", zap.Error(err))
}
}

var errUnknownDifference = errors.New("announced and received information differ but not critical")

func compareNodeInfos(niExp, niGot netmap.NodeInfo) error {
// if a node bootstraps the first time it is OK
// to be OFFLINE but send ONLINE bootstrap requests
niGot.SetOnline()
if exp, got := niExp.Marshal(), niGot.Marshal(); bytes.Equal(exp, got) {
return nil
}

var err error

if exp, got := niExp.Hash(), niGot.Hash(); exp != got {
return fmt.Errorf("hash: got %d, expect %d", got, exp)
}

niExp.SortAttributes()
niGot.SortAttributes()
if exp, got := niExp.NumberOfAttributes(), niGot.NumberOfAttributes(); exp != got {
return fmt.Errorf("attr number: got %d, expect %d", got, exp)
}

niExp.IterateAttributes(func(key, value string) {
vGot := niGot.Attribute(key)
if vGot != value {
err = fmt.Errorf("non-equal %s attribute: got %s, expect %s", key, vGot, value)
}
})
if err != nil {
return err
}

if exp, got := niExp.NumberOfNetworkEndpoints(), niGot.NumberOfNetworkEndpoints(); exp != got {
return fmt.Errorf("address number: got %d, expect %d", got, exp)
}

expAddrM := make(map[string]struct{}, niExp.NumberOfAttributes())
niExp.IterateNetworkEndpoints(func(s string) bool {
expAddrM[s] = struct{}{}
return false
})

niGot.IterateNetworkEndpoints(func(s string) bool {
if _, ok := expAddrM[s]; !ok {
err = fmt.Errorf("got unexpected address: %s", s)
return true
}

return false
})
if err != nil {
return err
}

return errUnknownDifference
}
14 changes: 14 additions & 0 deletions pkg/innerring/processors/netmap/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/state"
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
nmClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
Expand Down Expand Up @@ -49,6 +50,11 @@ type (
VerifyAndUpdate(*netmap.NodeInfo) error
}

// ClientSource must provide working [clientcore.Client].
ClientSource interface {
Get(clientcore.NodeInfo) (clientcore.Client, error)
}

// Processor of events produced by network map contract
// and new epoch ticker, because it is related to contract.
Processor struct {
Expand All @@ -71,6 +77,8 @@ type (
nodeValidator NodeValidator

nodeStateSettings state.NetworkSettings

clientSource ClientSource
}

// Params of the processor constructor.
Expand All @@ -93,6 +101,8 @@ type (
NodeValidator NodeValidator

NodeStateSettings state.NetworkSettings

ClientSource ClientSource
}
)

Expand Down Expand Up @@ -126,6 +136,8 @@ func New(p *Params) (*Processor, error) {
return nil, errors.New("ir/netmap: node validator is not set")
case p.NodeStateSettings == nil:
return nil, errors.New("ir/netmap: node state settings is not set")
case p.ClientSource == nil:
return nil, errors.New("ir/netmap: client source is not set")
}

p.Log.Debug("netmap worker pool", zap.Int("size", p.PoolSize))
Expand Down Expand Up @@ -155,6 +167,8 @@ func New(p *Params) (*Processor, error) {
nodeValidator: p.NodeValidator,

nodeStateSettings: p.NodeStateSettings,

clientSource: p.ClientSource,
}, nil
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/network/cache/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,15 @@ func (x *multiClient) ObjectSearchInit(ctx context.Context, containerID cid.ID,
return
}

func (x *multiClient) EndpointInfo(ctx context.Context, prm client.PrmEndpointInfo) (res *client.ResEndpointInfo, err error) {
err = x.iterateClients(ctx, func(c clientcore.Client) error {
res, err = c.EndpointInfo(ctx, prm)
return err
})

return
}

func (x *multiClient) AnnounceLocalTrust(ctx context.Context, epoch uint64, trusts []reputationSDK.Trust, prm client.PrmAnnounceLocalTrust) error {
return x.iterateClients(ctx, func(c clientcore.Client) error {
return c.AnnounceLocalTrust(ctx, epoch, trusts, prm)
Expand Down

0 comments on commit 30fba81

Please sign in to comment.