[#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 <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2021-06-25 18:23:29 +03:00 committed by Alex Vanin
parent 403f836968
commit d664a00e94
2 changed files with 149 additions and 19 deletions

View file

@ -34,6 +34,7 @@ type cfg struct {
addPeerMethod, // add peer method name for invocation addPeerMethod, // add peer method name for invocation
newEpochMethod, // new epoch method name for invocation newEpochMethod, // new epoch method name for invocation
netMapMethod, // get network map method name netMapMethod, // get network map method name
netMapCandidatesMethod, // get network candidates method name
snapshotMethod, // get network map snapshot method name snapshotMethod, // get network map snapshot method name
epochSnapshotMethod, // get network map snapshot by epoch method name epochSnapshotMethod, // get network map snapshot by epoch method name
updateStateMethod, // update state method name for invocation updateStateMethod, // update state method name for invocation
@ -44,30 +45,32 @@ type cfg struct {
} }
const ( const (
defaultAddPeerMethod = "addPeer" // default add peer method name defaultAddPeerMethod = "addPeer" // default add peer method name
defaultNewEpochMethod = "newEpoch" // default new epoch method name defaultConfigMethod = "config" // default get config value method name
defaultNetMapMethod = "netmap" // default get network map method name defaultEpochMethod = "epoch" // default get epoch number method name
defaultSnapshotMethod = "snapshot" // default get network map snapshot method name defaultNetMapCandidateMethod = "netmapCandidates" // default get network candidates method name
defaultUpdateStateMethod = "updateState" // default update state method name defaultNetMapMethod = "netmap" // default get network map method name
defaultEpochMethod = "epoch" // default get epoch number method name defaultNewEpochMethod = "newEpoch" // default new epoch method name
defaultSetInnerRingMethod = "updateInnerRing" // default set innerring method name defaultSetConfigMethod = "setConfig" // default get config value method name
defaultSetConfigMethod = "setConfig" // default get config value method name defaultSetInnerRingMethod = "updateInnerRing" // default set innerring method name
defaultConfigMethod = "config" // default get config value 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 defaultEpochSnapshotMethod = "snapshotByEpoch" // default get network map snapshot by epoch method name
) )
func defaultConfig() *cfg { func defaultConfig() *cfg {
return &cfg{ return &cfg{
addPeerMethod: defaultAddPeerMethod, addPeerMethod: defaultAddPeerMethod,
newEpochMethod: defaultNewEpochMethod, configMethod: defaultConfigMethod,
netMapMethod: defaultNetMapMethod, epochMethod: defaultEpochMethod,
snapshotMethod: defaultSnapshotMethod, netMapCandidatesMethod: defaultNetMapCandidateMethod,
epochSnapshotMethod: defaultEpochSnapshotMethod, netMapMethod: defaultNetMapMethod,
updateStateMethod: defaultUpdateStateMethod, newEpochMethod: defaultNewEpochMethod,
epochMethod: defaultEpochMethod, setConfigMethod: defaultSetConfigMethod,
setConfigMethod: defaultSetConfigMethod, snapshotMethod: defaultSnapshotMethod,
configMethod: defaultConfigMethod, updateStateMethod: defaultUpdateStateMethod,
epochSnapshotMethod: defaultEpochSnapshotMethod,
} }
} }

View file

@ -36,7 +36,55 @@ type EpochSnapshotValues struct {
*GetNetMapValues *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 // SetDiff sets argument for snapshot method of
// netmap contract. // netmap contract.
@ -107,6 +155,85 @@ func (c *Client) EpochSnapshot(args EpochSnapshotArgs) (*EpochSnapshotValues, er
}, nil }, 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) { func peersFromStackItems(stack []stackitem.Item, method string) (*GetNetMapValues, error) {
if ln := len(stack); ln != 1 { if ln := len(stack); ln != 1 {
return nil, fmt.Errorf("unexpected stack item count (%s): %d", return nil, fmt.Errorf("unexpected stack item count (%s): %d",