From c155459d955ec6eac39cdf28d3d035efb30e7d3d Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Fri, 25 Jun 2021 14:16:03 +0300 Subject: [PATCH 1/3] [#647] pkg/morph: Add constant var to err message Use defined constant variable instead of hardcoded number in error message. Signed-off-by: Pavel Karpy --- pkg/morph/client/netmap/netmap.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/morph/client/netmap/netmap.go b/pkg/morph/client/netmap/netmap.go index 3707901bbc..1a0dd83920 100644 --- a/pkg/morph/client/netmap/netmap.go +++ b/pkg/morph/client/netmap/netmap.go @@ -140,7 +140,11 @@ func peerInfoFromStackItem(prm stackitem.Item) ([]byte, error) { if err != nil { return nil, fmt.Errorf("could not get stack item array (PeerInfo): %w", err) } else if ln := len(prms); ln != nodeInfoFixedPrmNumber { - return nil, fmt.Errorf("unexpected stack item count (PeerInfo): expected %d, has %d", 1, ln) + return nil, fmt.Errorf( + "unexpected stack item count (PeerInfo): expected %d, has %d", + nodeInfoFixedPrmNumber, + ln, + ) } return client.BytesFromStackItem(prms[0]) From bb0911cf7d12429ead1d1a50cc70ead6d18c7666 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Fri, 25 Jun 2021 18:23:29 +0300 Subject: [PATCH 2/3] [#647] pkg/morph/netmap: Add `netmapCandidates` method Add `netmapCandidates` method to `netmap` client wrapper. Method parses node storages candidates for the next epoch. Signed-off-by: Pavel Karpy --- pkg/morph/client/netmap/client.go | 39 ++++----- pkg/morph/client/netmap/netmap.go | 129 +++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 19 deletions(-) diff --git a/pkg/morph/client/netmap/client.go b/pkg/morph/client/netmap/client.go index f0b0015160..805e5b1f45 100644 --- a/pkg/morph/client/netmap/client.go +++ b/pkg/morph/client/netmap/client.go @@ -34,6 +34,7 @@ type cfg struct { addPeerMethod, // add peer method name for invocation newEpochMethod, // new epoch method name for invocation netMapMethod, // get network map method name + netMapCandidatesMethod, // get network candidates method name snapshotMethod, // get network map snapshot method name epochSnapshotMethod, // get network map snapshot by epoch method name updateStateMethod, // update state method name for invocation @@ -44,30 +45,32 @@ type cfg struct { } const ( - defaultAddPeerMethod = "addPeer" // default add peer method name - defaultNewEpochMethod = "newEpoch" // default new epoch method name - defaultNetMapMethod = "netmap" // default get network map method name - defaultSnapshotMethod = "snapshot" // default get network map snapshot method name - defaultUpdateStateMethod = "updateState" // default update state method name - defaultEpochMethod = "epoch" // default get epoch number method name - defaultSetInnerRingMethod = "updateInnerRing" // default set innerring method name - defaultSetConfigMethod = "setConfig" // default get config value method name - defaultConfigMethod = "config" // default get config value method name + defaultAddPeerMethod = "addPeer" // default add peer method name + defaultConfigMethod = "config" // default get config value method name + defaultEpochMethod = "epoch" // default get epoch number method name + defaultNetMapCandidateMethod = "netmapCandidates" // default get network candidates method name + defaultNetMapMethod = "netmap" // default get network map method name + defaultNewEpochMethod = "newEpoch" // default new epoch method name + defaultSetConfigMethod = "setConfig" // default get config value method name + defaultSetInnerRingMethod = "updateInnerRing" // default set innerring method name + defaultSnapshotMethod = "snapshot" // default get network map snapshot method name + defaultUpdateStateMethod = "updateState" // default update state method name defaultEpochSnapshotMethod = "snapshotByEpoch" // default get network map snapshot by epoch method name ) func defaultConfig() *cfg { return &cfg{ - addPeerMethod: defaultAddPeerMethod, - newEpochMethod: defaultNewEpochMethod, - netMapMethod: defaultNetMapMethod, - snapshotMethod: defaultSnapshotMethod, - epochSnapshotMethod: defaultEpochSnapshotMethod, - updateStateMethod: defaultUpdateStateMethod, - epochMethod: defaultEpochMethod, - setConfigMethod: defaultSetConfigMethod, - configMethod: defaultConfigMethod, + addPeerMethod: defaultAddPeerMethod, + configMethod: defaultConfigMethod, + epochMethod: defaultEpochMethod, + netMapCandidatesMethod: defaultNetMapCandidateMethod, + netMapMethod: defaultNetMapMethod, + newEpochMethod: defaultNewEpochMethod, + setConfigMethod: defaultSetConfigMethod, + snapshotMethod: defaultSnapshotMethod, + updateStateMethod: defaultUpdateStateMethod, + epochSnapshotMethod: defaultEpochSnapshotMethod, } } diff --git a/pkg/morph/client/netmap/netmap.go b/pkg/morph/client/netmap/netmap.go index 1a0dd83920..4e7662da9f 100644 --- a/pkg/morph/client/netmap/netmap.go +++ b/pkg/morph/client/netmap/netmap.go @@ -36,7 +36,55 @@ type EpochSnapshotValues struct { *GetNetMapValues } -const nodeInfoFixedPrmNumber = 1 +// GetNetMapCandidatesArgs groups the arguments +// of get network map candidates test invoke call. +type GetNetMapCandidatesArgs struct { +} + +// GetNetMapCandidatesValues groups the stack parameters +// returned by get network map candidates test invoke. +type GetNetMapCandidatesValues struct { + netmapNodes []*PeerWithState +} + +func (g GetNetMapCandidatesValues) NetmapNodes() []*PeerWithState { + return g.netmapNodes +} + +// State is an enumeration of various states of the NeoFS node. +type State int64 + +const ( + // Undefined is unknown state. + Undefined State = iota + + // Online is network unavailable state. + Online + + // Offline is an active state in the network. + Offline +) + +// PeerWithState groups information about peer +// and its state in network map. +type PeerWithState struct { + peer []byte + state State +} + +func (ps PeerWithState) State() State { + return ps.state +} + +func (ps PeerWithState) Peer() []byte { + return ps.peer +} + +const ( + nodeInfoFixedPrmNumber = 1 + + peerWithStateFixedPrmNumber = 2 +) // SetDiff sets argument for snapshot method of // netmap contract. @@ -107,6 +155,85 @@ func (c *Client) EpochSnapshot(args EpochSnapshotArgs) (*EpochSnapshotValues, er }, nil } +func (c *Client) Candidates(_ GetNetMapCandidatesArgs) (*GetNetMapCandidatesValues, error) { + prms, err := c.client.TestInvoke( + c.netMapCandidatesMethod, + ) + if err != nil { + return nil, fmt.Errorf("could not perform test invocation (%s): %w", c.netMapCandidatesMethod, err) + } + + candVals, err := peersWithStateFromStackItems(prms, c.netMapCandidatesMethod) + if err != nil { + return nil, fmt.Errorf("could not parse contract response: %w", err) + } + + return candVals, nil +} + +func peersWithStateFromStackItems(stack []stackitem.Item, method string) (*GetNetMapCandidatesValues, error) { + if ln := len(stack); ln != 1 { + return nil, fmt.Errorf("unexpected stack item count (%s): %d", method, ln) + } + + netmapNodes, err := client.ArrayFromStackItem(stack[0]) + if err != nil { + return nil, fmt.Errorf("could not get stack item array from stack item (%s): %w", method, err) + } + + res := &GetNetMapCandidatesValues{ + netmapNodes: make([]*PeerWithState, 0, len(netmapNodes)), + } + + for i := range netmapNodes { + node, err := peerWithStateFromStackItem(netmapNodes[i]) + if err != nil { + return nil, fmt.Errorf("could not parse stack item (Peer #%d): %w", i, err) + } + + res.netmapNodes = append(res.netmapNodes, node) + } + + return res, nil +} + +func peerWithStateFromStackItem(prm stackitem.Item) (*PeerWithState, error) { + prms, err := client.ArrayFromStackItem(prm) + if err != nil { + return nil, fmt.Errorf("could not get stack item array (PeerWithState): %w", err) + } else if ln := len(prms); ln != peerWithStateFixedPrmNumber { + return nil, fmt.Errorf( + "unexpected stack item count (PeerWithState): expected %d, has %d", + peerWithStateFixedPrmNumber, + ln, + ) + } + + var res PeerWithState + + // peer + if res.peer, err = peerInfoFromStackItem(prms[0]); err != nil { + return nil, fmt.Errorf("could not get bytes from 'node' field of PeerWithState: %w", err) + } + + // state + state, err := client.IntFromStackItem(prms[1]) + if err != nil { + return nil, fmt.Errorf("could not get int from 'state' field of PeerWithState: %w", err) + } + + switch state { + case 1: + res.state = Online + case 2: + res.state = Offline + default: + res.state = Undefined + } + + return &res, nil +} + func peersFromStackItems(stack []stackitem.Item, method string) (*GetNetMapValues, error) { if ln := len(stack); ln != 1 { return nil, fmt.Errorf("unexpected stack item count (%s): %d", From 700e5e19bd4ce039e4257de731eacf82c8770eb1 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Fri, 25 Jun 2021 18:58:05 +0300 Subject: [PATCH 3/3] [#647] pkg/morph/netmap/wrapper: `GetCandidates` method Signed-off-by: Pavel Karpy --- pkg/morph/client/netmap/wrapper/netmap.go | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pkg/morph/client/netmap/wrapper/netmap.go b/pkg/morph/client/netmap/wrapper/netmap.go index a8e99ab181..4f3b51ec62 100644 --- a/pkg/morph/client/netmap/wrapper/netmap.go +++ b/pkg/morph/client/netmap/wrapper/netmap.go @@ -38,6 +38,20 @@ func (w Wrapper) GetNetMapByEpoch(epoch uint64) (*netmap.Netmap, error) { return unmarshalNetmap(vals.Peers()) } +// GetCandidates receives information list about candidates +// for the next epoch network map through the Netmap contract +// call, composes network map from them and returns it. +func (w Wrapper) GetCandidates() (*netmap.Netmap, error) { + args := client.GetNetMapCandidatesArgs{} + + vals, err := w.client.Candidates(args) + if err != nil { + return nil, err + } + + return unmarshalCandidates(vals.NetmapNodes()) +} + func unmarshalNetmap(rawPeers [][]byte) (*netmap.Netmap, error) { infos := make([]netmap.NodeInfo, 0, len(rawPeers)) @@ -54,3 +68,29 @@ func unmarshalNetmap(rawPeers [][]byte) (*netmap.Netmap, error) { return netmap.NewNetmap(nodes) } + +func unmarshalCandidates(rawCandidate []*client.PeerWithState) (*netmap.Netmap, error) { + candidates := make([]netmap.NodeInfo, 0, len(rawCandidate)) + + for _, candidate := range rawCandidate { + nodeInfo := netmap.NewNodeInfo() + if err := nodeInfo.Unmarshal(candidate.Peer()); err != nil { + return nil, fmt.Errorf("can't unmarshal peer info: %w", err) + } + + switch candidate.State() { + case client.Online: + nodeInfo.SetState(netmap.NodeStateOnline) + case client.Offline: + nodeInfo.SetState(netmap.NodeStateOffline) + default: + nodeInfo.SetState(0) + } + + candidates = append(candidates, *nodeInfo) + } + + nodes := netmap.NodesFromInfo(candidates) + + return netmap.NewNetmap(nodes) +}