aergoio/aergo

View on GitHub
contract/enterprise/changecluster.go

Summary

Maintainability
A
55 mins
Test Coverage
D
62%
package enterprise

import (
    "fmt"
    "reflect"
    "strconv"

    "github.com/aergoio/aergo/v2/types"
)

type CcArgument map[string]interface{}

const (
    CmdMembershipAdd    = "add"
    CmdMembershipRemove = "remove"

    CCCommand         = "command"
    MemberAttrName    = "name"
    MemberAttrAddress = "address"
    MemberAttrPeerID  = "peerid"
    MemberAttrID      = "id"
)

/*
var (
    ConfChangeState_name = map[ConfChangeState]string{
        0: "Proposed",
        1: "Saved",
        2: "Applied",
    }
)*/

func ValidateChangeCluster(ci types.CallInfo, blockNo types.BlockNo) (interface{}, error) {
    var (
        ccArg     CcArgument
        ok        bool
        err       error
        changeReq *types.MembershipChange
    )

    if len(ci.Args) != 1 { //args[0] : map{ "command": "add", "name:", "address:", "peerid:", "id:"}
        return nil, fmt.Errorf("invalid arguments in payload for ChangeCluster: %s", ci.Args)
    }

    ccArg, ok = ci.Args[0].(map[string]interface{})
    if !ok {
        return nil, fmt.Errorf("invalid argument in payload for ChangeCluster(map[string]interface{}) : argument=%v", reflect.TypeOf(ci.Args[0]))
    }

    if changeReq, err = ccArg.parse(); err != nil {
        return nil, err
    }

    changeReq.RequestID = blockNo

    return changeReq, nil
}

func (cc CcArgument) get(key string) (string, error) {
    var (
        val    interface{}
        valStr string
        ok     bool
    )

    if val, ok = cc[key]; !ok {
        return "", fmt.Errorf("invalid ChangeCluster argument: not exist %s", key)
    }

    if valStr, ok = val.(string); !ok {
        return "", fmt.Errorf("invalid ChangeCluster argument: not string value(%v)", reflect.TypeOf(val))
    }

    return valStr, nil
}

func (cc CcArgument) getUint64(key string) (uint64, error) {
    var (
        val     interface{}
        valUint float64
        ok      bool
    )

    if val, ok = cc[key]; !ok {
        return 0, fmt.Errorf("invalid ChangeCluster argument: not exist %s", key)
    }

    if valUint, ok = val.(float64); !ok {
        return 0, fmt.Errorf("invalid ChangeCluster argument: not uint64(%v)", reflect.TypeOf(val))
    }

    return uint64(valUint), nil
}

func (cc CcArgument) parse() (*types.MembershipChange, error) {
    var (
        cmd, name, address, peeridStr, idStr string
        id                                   uint64
        err                                  error
        mChange                              types.MembershipChange
        peerID                               types.PeerID
    )

    if cmd, err = cc.get(CCCommand); err != nil {
        return nil, err
    }

    switch cmd {
    case CmdMembershipAdd:
        mChange.Type = types.MembershipChangeType_ADD_MEMBER

        if name, err = cc.get(MemberAttrName); err != nil {
            return nil, err
        }

        if address, err = cc.get(MemberAttrAddress); err != nil {
            return nil, err
        }

        if peeridStr, err = cc.get(MemberAttrPeerID); err != nil {
            return nil, err
        }

        peerID, err = types.IDB58Decode(peeridStr)
        if err != nil {
            return nil, fmt.Errorf("invalid ChangeCluster argument: can't decode peerid string(%s)", peeridStr)
        }

        if _, err := types.ParseMultiaddr(address); err != nil {
            return nil, fmt.Errorf("invalid ChangeCluster argument: %s", err.Error())
        }

    case CmdMembershipRemove:
        mChange.Type = types.MembershipChangeType_REMOVE_MEMBER

        if idStr, err = cc.get(MemberAttrID); err != nil {
            return nil, err
        }

        if id, err = strconv.ParseUint(idStr, 16, 64); err != nil {
            return nil, fmt.Errorf("invalid ChangeCluster argument: invalid id %s. ID must be a string in hexadecial format(ex:dd44cf1a06727dc5)", idStr)
        }

    default:
        return nil, fmt.Errorf("invalid ChangeCluster argument: invalid command %s", cmd)
    }

    mChange.Attr = &types.MemberAttr{Name: name, Address: address, PeerID: []byte(peerID), ID: id}

    return &mChange, nil
}