package api import ( "context" "net" log "github.com/sirupsen/logrus" "github.com/vapor/common" cfg "github.com/vapor/config" "github.com/vapor/consensus" "github.com/vapor/crypto" "github.com/vapor/errors" "github.com/vapor/netsync/peers" "github.com/vapor/p2p" "github.com/vapor/version" ) type VersionInfo struct { Version string `json:"version"` Update uint16 `json:"update"` // 0: no update; 1: small update; 2: significant update NewVer string `json:"new_version"` } // NetInfo indicate net information type NetInfo struct { Listening bool `json:"listening"` Syncing bool `json:"syncing"` Mining bool `json:"mining"` NodeXPub string `json:"node_xpub"` FedAddress string `json:"federation_address"` PeerCount int `json:"peer_count"` CurrentBlock uint64 `json:"current_block"` HighestBlock uint64 `json:"highest_block"` NetWorkID string `json:"network_id"` Version *VersionInfo `json:"version_info"` } // GetNodeInfo return net information func (a *API) GetNodeInfo() *NetInfo { nodeXPub := cfg.CommonConfig.PrivateKey().XPub() signScript := cfg.FederationPMultiSigScript(cfg.CommonConfig) scriptHash := crypto.Sha256(signScript) address, err := common.NewAddressWitnessScriptHash(scriptHash, consensus.BytomMainNetParams(&consensus.ActiveNetParams)) if err != nil { log.WithFields(log.Fields{"module": logModule, "err": err}).Fatal("Failed to get federation address.") } info := &NetInfo{ Listening: a.sync.IsListening(), Syncing: !a.sync.IsCaughtUp(), Mining: a.blockProposer.IsProposing(), NodeXPub: nodeXPub.String(), FedAddress: address.EncodeAddress(), PeerCount: a.sync.PeerCount(), CurrentBlock: a.chain.BestBlockHeight(), NetWorkID: a.sync.GetNetwork(), Version: &VersionInfo{ Version: version.Version, Update: version.Status.VersionStatus(), NewVer: version.Status.MaxVerSeen(), }, } if bestPeer := a.sync.BestPeer(); bestPeer != nil { info.HighestBlock = bestPeer.Height } if info.CurrentBlock > info.HighestBlock { info.HighestBlock = info.CurrentBlock } return info } // return the currently connected peers with net address func (a *API) getPeerInfoByAddr(addr string) *peers.PeerInfo { peerInfos := a.sync.GetPeerInfos() for _, peerInfo := range peerInfos { if peerInfo.RemoteAddr == addr { return peerInfo } } return nil } // disconnect peer by the peer id func (a *API) disconnectPeerById(peerID string) error { return a.sync.StopPeer(peerID) } // connect peer b y net address func (a *API) connectPeerByIpAndPort(ip string, port uint16) (*peers.PeerInfo, error) { netIp := net.ParseIP(ip) if netIp == nil { return nil, errors.New("invalid ip address") } addr := p2p.NewNetAddressIPPort(netIp, port) if err := a.sync.DialPeerWithAddress(addr); err != nil { return nil, errors.Wrap(err, "can not connect to the address") } peer := a.getPeerInfoByAddr(addr.String()) if peer == nil { return nil, errors.New("the peer is disconnected again") } return peer, nil } // getNetInfo return network information func (a *API) getNetInfo() Response { return NewSuccessResponse(a.GetNodeInfo()) } // isMining return is in mining or not func (a *API) isMining() Response { IsMining := map[string]bool{"is_mining": a.IsMining()} return NewSuccessResponse(IsMining) } // IsProposing return mining status func (a *API) IsMining() bool { return a.blockProposer.IsProposing() } // return the peers of current node func (a *API) listPeers() Response { return NewSuccessResponse(a.sync.GetPeerInfos()) } // disconnect peer func (a *API) disconnectPeer(ctx context.Context, ins struct { PeerID string `json:"peer_id"` }) Response { if err := a.disconnectPeerById(ins.PeerID); err != nil { return NewErrorResponse(err) } return NewSuccessResponse(nil) } // connect peer by ip and port func (a *API) connectPeer(ctx context.Context, ins struct { Ip string `json:"ip"` Port uint16 `json:"port"` }) Response { if peer, err := a.connectPeerByIpAndPort(ins.Ip, ins.Port); err != nil { return NewErrorResponse(err) } else { return NewSuccessResponse(peer) } }