implement NodeStatus API
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
d7cd8bae2c
commit
ed61642b3a
@ -664,6 +664,11 @@ type FullNode interface {
|
|||||||
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) //perm:write
|
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) //perm:write
|
||||||
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) //perm:sign
|
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) //perm:sign
|
||||||
|
|
||||||
|
// MethodGroup: Node
|
||||||
|
// These methods are general node management and status commands
|
||||||
|
|
||||||
|
NodeStatus(ctx context.Context, inclChainStatus bool) (NodeStatus, error) //perm:read
|
||||||
|
|
||||||
// CreateBackup creates node backup onder the specified file name. The
|
// CreateBackup creates node backup onder the specified file name. The
|
||||||
// method requires that the lotus daemon is running with the
|
// method requires that the lotus daemon is running with the
|
||||||
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||||
|
@ -1692,6 +1692,21 @@ func (mr *MockFullNodeMockRecorder) NetPubsubScores(arg0 interface{}) *gomock.Ca
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetPubsubScores", reflect.TypeOf((*MockFullNode)(nil).NetPubsubScores), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetPubsubScores", reflect.TypeOf((*MockFullNode)(nil).NetPubsubScores), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeStatus mocks base method
|
||||||
|
func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "NodeStatus", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(api.NodeStatus)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeStatus indicates an expected call of NodeStatus
|
||||||
|
func (mr *MockFullNodeMockRecorder) NodeStatus(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStatus", reflect.TypeOf((*MockFullNode)(nil).NodeStatus), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// PaychAllocateLane mocks base method
|
// PaychAllocateLane mocks base method
|
||||||
func (m *MockFullNode) PaychAllocateLane(arg0 context.Context, arg1 address.Address) (uint64, error) {
|
func (m *MockFullNode) PaychAllocateLane(arg0 context.Context, arg1 address.Address) (uint64, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -287,6 +287,8 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (cid.Cid, error) `perm:"sign"`
|
MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (cid.Cid, error) `perm:"sign"`
|
||||||
|
|
||||||
|
NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"`
|
||||||
|
|
||||||
PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"`
|
PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"`
|
||||||
|
|
||||||
PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"`
|
PaychAvailableFunds func(p0 context.Context, p1 address.Address) (*ChannelAvailableFunds, error) `perm:"sign"`
|
||||||
@ -1715,6 +1717,14 @@ func (s *FullNodeStub) MsigSwapPropose(p0 context.Context, p1 address.Address, p
|
|||||||
return *new(cid.Cid), xerrors.New("method not supported")
|
return *new(cid.Cid), xerrors.New("method not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {
|
||||||
|
return s.Internal.NodeStatus(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {
|
||||||
|
return *new(NodeStatus), xerrors.New("method not supported")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) PaychAllocateLane(p0 context.Context, p1 address.Address) (uint64, error) {
|
func (s *FullNodeStruct) PaychAllocateLane(p0 context.Context, p1 address.Address) (uint64, error) {
|
||||||
return s.Internal.PaychAllocateLane(p0, p1)
|
return s.Internal.PaychAllocateLane(p0, p1)
|
||||||
}
|
}
|
||||||
|
21
api/types.go
21
api/types.go
@ -116,3 +116,24 @@ type ConnMgrInfo struct {
|
|||||||
Tags map[string]int
|
Tags map[string]int
|
||||||
Conns map[string]time.Time
|
Conns map[string]time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeStatus struct {
|
||||||
|
SyncStatus NodeSyncStatus
|
||||||
|
PeerStatus NodePeerStatus
|
||||||
|
ChainStatus NodeChainStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeSyncStatus struct {
|
||||||
|
Epoch uint64
|
||||||
|
Behind uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodePeerStatus struct {
|
||||||
|
PeersToPublishMsgs int
|
||||||
|
PeersToPublishBlocks int
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeChainStatus struct {
|
||||||
|
BlocksPerTipsetLast100 float64
|
||||||
|
BlocksPerTipsetLastFinality float64
|
||||||
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -81,6 +81,7 @@ var Commands = []*cli.Command{
|
|||||||
WithCategory("developer", FetchParamCmd),
|
WithCategory("developer", FetchParamCmd),
|
||||||
WithCategory("network", NetCmd),
|
WithCategory("network", NetCmd),
|
||||||
WithCategory("network", SyncCmd),
|
WithCategory("network", SyncCmd),
|
||||||
|
WithCategory("status", StatusCmd),
|
||||||
PprofCmd,
|
PprofCmd,
|
||||||
VersionCmd,
|
VersionCmd,
|
||||||
}
|
}
|
||||||
|
60
cli/status.go
Normal file
60
cli/status.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
var StatusCmd = &cli.Command{
|
||||||
|
Name: "status",
|
||||||
|
Usage: "Check node status",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "chain",
|
||||||
|
Usage: "include chain health status",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
apic, closer, err := GetFullNodeAPIV1(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
ctx := ReqContext(cctx)
|
||||||
|
|
||||||
|
inclChainStatus := cctx.Bool("chain")
|
||||||
|
|
||||||
|
status, err := apic.NodeStatus(ctx, inclChainStatus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Sync Epoch: %d\n", status.SyncStatus.Epoch)
|
||||||
|
fmt.Printf("Epochs Behind: %d\n", status.SyncStatus.Behind)
|
||||||
|
fmt.Printf("Peers to Publish Messages: %d\n", status.PeerStatus.PeersToPublishMsgs)
|
||||||
|
fmt.Printf("Peers to Publish Blocks: %d\n", status.PeerStatus.PeersToPublishBlocks)
|
||||||
|
|
||||||
|
if inclChainStatus && status.SyncStatus.Epoch > uint64(build.Finality) {
|
||||||
|
var ok100, okFin string
|
||||||
|
if status.ChainStatus.BlocksPerTipsetLast100 >= 4.75 {
|
||||||
|
ok100 = "[OK]"
|
||||||
|
} else {
|
||||||
|
ok100 = "[UNHEALTHY]"
|
||||||
|
}
|
||||||
|
if status.ChainStatus.BlocksPerTipsetLastFinality >= 4.75 {
|
||||||
|
okFin = "[OK]"
|
||||||
|
} else {
|
||||||
|
okFin = "[UNHEALTHY]"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Blocks per TipSet in last 100 epochs: %f %s\n", status.ChainStatus.BlocksPerTipsetLast100, ok100)
|
||||||
|
fmt.Printf("Blocks per TipSet in last finality: %f %s\n", status.ChainStatus.BlocksPerTipsetLastFinality, okFin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
@ -126,6 +126,8 @@
|
|||||||
* [NetPeerInfo](#NetPeerInfo)
|
* [NetPeerInfo](#NetPeerInfo)
|
||||||
* [NetPeers](#NetPeers)
|
* [NetPeers](#NetPeers)
|
||||||
* [NetPubsubScores](#NetPubsubScores)
|
* [NetPubsubScores](#NetPubsubScores)
|
||||||
|
* [Node](#Node)
|
||||||
|
* [NodeStatus](#NodeStatus)
|
||||||
* [Paych](#Paych)
|
* [Paych](#Paych)
|
||||||
* [PaychAllocateLane](#PaychAllocateLane)
|
* [PaychAllocateLane](#PaychAllocateLane)
|
||||||
* [PaychAvailableFunds](#PaychAvailableFunds)
|
* [PaychAvailableFunds](#PaychAvailableFunds)
|
||||||
@ -3000,6 +3002,40 @@ Inputs: `null`
|
|||||||
|
|
||||||
Response: `null`
|
Response: `null`
|
||||||
|
|
||||||
|
## Node
|
||||||
|
These methods are general node management and status commands
|
||||||
|
|
||||||
|
|
||||||
|
### NodeStatus
|
||||||
|
There are not yet any comments for this method.
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
true
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"SyncStatus": {
|
||||||
|
"Epoch": 42,
|
||||||
|
"Behind": 42
|
||||||
|
},
|
||||||
|
"PeerStatus": {
|
||||||
|
"PeersToPublishMsgs": 123,
|
||||||
|
"PeersToPublishBlocks": 123
|
||||||
|
},
|
||||||
|
"ChainStatus": {
|
||||||
|
"BlocksPerTipsetLast100": 12.3,
|
||||||
|
"BlocksPerTipsetLastFinality": 12.3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Paych
|
## Paych
|
||||||
The Paych methods are for interacting with and managing payment channels
|
The Paych methods are for interacting with and managing payment channels
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ COMMANDS:
|
|||||||
NETWORK:
|
NETWORK:
|
||||||
net Manage P2P Network
|
net Manage P2P Network
|
||||||
sync Inspect or interact with the chain syncer
|
sync Inspect or interact with the chain syncer
|
||||||
|
STATUS:
|
||||||
|
status Check node status
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
--help, -h show help (default: false)
|
--help, -h show help (default: false)
|
||||||
@ -2671,3 +2673,20 @@ OPTIONS:
|
|||||||
--help, -h show help (default: false)
|
--help, -h show help (default: false)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## lotus status
|
||||||
|
```
|
||||||
|
NAME:
|
||||||
|
lotus status - Check node status
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
lotus status [command options] [arguments...]
|
||||||
|
|
||||||
|
CATEGORY:
|
||||||
|
STATUS
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
--chain include chain health status (default: false)
|
||||||
|
--help, -h show help (default: false)
|
||||||
|
|
||||||
|
```
|
||||||
|
@ -2,16 +2,21 @@ package impl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/node/impl/client"
|
"github.com/filecoin-project/lotus/node/impl/client"
|
||||||
"github.com/filecoin-project/lotus/node/impl/common"
|
"github.com/filecoin-project/lotus/node/impl/common"
|
||||||
"github.com/filecoin-project/lotus/node/impl/full"
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
"github.com/filecoin-project/lotus/node/impl/market"
|
"github.com/filecoin-project/lotus/node/impl/market"
|
||||||
"github.com/filecoin-project/lotus/node/impl/paych"
|
"github.com/filecoin-project/lotus/node/impl/paych"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/lp2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("node")
|
var log = logging.Logger("node")
|
||||||
@ -30,11 +35,86 @@ type FullNodeAPI struct {
|
|||||||
full.SyncAPI
|
full.SyncAPI
|
||||||
full.BeaconAPI
|
full.BeaconAPI
|
||||||
|
|
||||||
DS dtypes.MetadataDS
|
DS dtypes.MetadataDS
|
||||||
|
NetworkName dtypes.NetworkName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *FullNodeAPI) CreateBackup(ctx context.Context, fpath string) error {
|
func (n *FullNodeAPI) CreateBackup(ctx context.Context, fpath string) error {
|
||||||
return backup(n.DS, fpath)
|
return backup(n.DS, fpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *FullNodeAPI) NodeStatus(ctx context.Context, inclChainStatus bool) (status api.NodeStatus, err error) {
|
||||||
|
curTs, err := n.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
|
||||||
|
status.SyncStatus.Epoch = uint64(curTs.Height())
|
||||||
|
timestamp := time.Unix(int64(curTs.MinTimestamp()), 0)
|
||||||
|
delta := time.Since(timestamp).Seconds()
|
||||||
|
status.SyncStatus.Behind = uint64(delta / 30)
|
||||||
|
|
||||||
|
// get peers in the messages and blocks topics
|
||||||
|
peersMsgs := make(map[peer.ID]struct{})
|
||||||
|
peersBlocks := make(map[peer.ID]struct{})
|
||||||
|
|
||||||
|
for _, p := range n.PubSub.ListPeers(build.MessagesTopic(n.NetworkName)) {
|
||||||
|
peersMsgs[p] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range n.PubSub.ListPeers(build.BlocksTopic(n.NetworkName)) {
|
||||||
|
peersBlocks[p] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get scores for all connected and recent peers
|
||||||
|
scores, err := n.NetPubsubScores(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, score := range scores {
|
||||||
|
if score.Score.Score > lp2p.PublishScoreThreshold {
|
||||||
|
_, inMsgs := peersMsgs[score.ID]
|
||||||
|
if inMsgs {
|
||||||
|
status.PeerStatus.PeersToPublishMsgs++
|
||||||
|
}
|
||||||
|
|
||||||
|
_, inBlocks := peersBlocks[score.ID]
|
||||||
|
if inBlocks {
|
||||||
|
status.PeerStatus.PeersToPublishBlocks++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if inclChainStatus && status.SyncStatus.Epoch > uint64(build.Finality) {
|
||||||
|
blockCnt := 0
|
||||||
|
ts := curTs
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
blockCnt += len(ts.Blocks())
|
||||||
|
tsk := ts.Parents()
|
||||||
|
ts, err = n.ChainGetTipSet(ctx, tsk)
|
||||||
|
if err != nil {
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.ChainStatus.BlocksPerTipsetLast100 = float64(blockCnt) / 100
|
||||||
|
|
||||||
|
for i := 100; i < int(build.Finality); i++ {
|
||||||
|
blockCnt += len(ts.Blocks())
|
||||||
|
tsk := ts.Parents()
|
||||||
|
ts, err = n.ChainGetTipSet(ctx, tsk)
|
||||||
|
if err != nil {
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status.ChainStatus.BlocksPerTipsetLastFinality = float64(blockCnt) / float64(build.Finality)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ api.FullNode = &FullNodeAPI{}
|
var _ api.FullNode = &FullNodeAPI{}
|
||||||
|
@ -36,6 +36,15 @@ func init() {
|
|||||||
pubsub.GossipSubHistoryLength = 10
|
pubsub.GossipSubHistoryLength = 10
|
||||||
pubsub.GossipSubGossipFactor = 0.1
|
pubsub.GossipSubGossipFactor = 0.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
GossipScoreThreshold = -500
|
||||||
|
PublishScoreThreshold = -1000
|
||||||
|
GraylistScoreThreshold = -2500
|
||||||
|
AcceptPXScoreThreshold = 1000
|
||||||
|
OpportunisticGraftScoreThreshold = 3.5
|
||||||
|
)
|
||||||
|
|
||||||
func ScoreKeeper() *dtypes.ScoreKeeper {
|
func ScoreKeeper() *dtypes.ScoreKeeper {
|
||||||
return new(dtypes.ScoreKeeper)
|
return new(dtypes.ScoreKeeper)
|
||||||
}
|
}
|
||||||
@ -256,11 +265,11 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) {
|
|||||||
Topics: topicParams,
|
Topics: topicParams,
|
||||||
},
|
},
|
||||||
&pubsub.PeerScoreThresholds{
|
&pubsub.PeerScoreThresholds{
|
||||||
GossipThreshold: -500,
|
GossipThreshold: GossipScoreThreshold,
|
||||||
PublishThreshold: -1000,
|
PublishThreshold: PublishScoreThreshold,
|
||||||
GraylistThreshold: -2500,
|
GraylistThreshold: GraylistScoreThreshold,
|
||||||
AcceptPXThreshold: 1000,
|
AcceptPXThreshold: AcceptPXScoreThreshold,
|
||||||
OpportunisticGraftThreshold: 3.5,
|
OpportunisticGraftThreshold: OpportunisticGraftScoreThreshold,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
pubsub.WithPeerScoreInspect(in.Sk.Update, 10*time.Second),
|
pubsub.WithPeerScoreInspect(in.Sk.Update, 10*time.Second),
|
||||||
|
Loading…
Reference in New Issue
Block a user