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 5, 2023
1 parent 9224e9f commit 85ca87e
Show file tree
Hide file tree
Showing 2 changed files with 122 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
121 changes: 121 additions & 0 deletions pkg/innerring/processors/netmap/process_peers.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package netmap

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

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 +42,43 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
return
}

var results []*client.ResEndpointInfo
nodeInfo.IterateNetworkEndpoints(func(s string) bool {
var res *client.ResEndpointInfo
var c *client.Client

c, err = createSDKClient(s)
if err != nil {
err = fmt.Errorf("'%s': client creation: %w", s, err)
return true
}
defer func() {
_ = c.Close()
}()

timeoutContext, cancel := context.WithTimeout(context.Background(), pingTimeout)
defer cancel()

res, err = c.EndpointInfo(timeoutContext, client.PrmEndpointInfo{})
if err != nil {
err = fmt.Errorf("'%s': could not ping node with `EndpointInfo`: %w", s, err)
return true
}

results = append(results, res)
return false
})

for _, res := range results {
err = compareNodeInfos(nodeInfo, res.NodeInfo())
if err != nil {
np.log.Warn("`EndpointInfo` RPC call result differs",
zap.Error(err),
zap.String("node", hex.EncodeToString(nodeInfo.PublicKey())))
return
}
}

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

func compareNodeInfos(niExp, niGot netmap.NodeInfo) error {
// a node can be in a STATE_1 (and respond with it)
// but the request can mean a state transfer to a
// STATE_2, so make both node infos in the same state,
// e.g. ONLINE
niGot.SetOnline()
niExp.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)
}

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 nil
}

const pingTimeout = 15 * time.Second

func createSDKClient(e string) (*client.Client, error) {
var prmInit client.PrmInit
var prmDial client.PrmDial

prmDial.SetTimeout(pingTimeout)
prmDial.SetStreamTimeout(pingTimeout)
prmDial.SetServerURI(e)

c, err := client.New(prmInit)
if err != nil {
return nil, fmt.Errorf("can't create SDK client: %w", err)
}

err = c.Dial(prmDial)
if err != nil {
return nil, fmt.Errorf("can't init SDK client: %w", err)
}

return c, nil
}

0 comments on commit 85ca87e

Please sign in to comment.