0fddf3e114
This configurability is unlocked through the `testground` build tag, which Project Oni will uses. Changes in the usage places of these relaxed constants were required due to the fact that Golang constants are untyped, but vars aren't. Read https://blog.golang.org/constants for more info.
202 lines
4.3 KiB
Go
202 lines
4.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
cid "github.com/ipfs/go-cid"
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/lotus/chain"
|
|
)
|
|
|
|
var syncCmd = &cli.Command{
|
|
Name: "sync",
|
|
Usage: "Inspect or interact with the chain syncer",
|
|
Subcommands: []*cli.Command{
|
|
syncStatusCmd,
|
|
syncWaitCmd,
|
|
syncMarkBadCmd,
|
|
syncCheckBadCmd,
|
|
},
|
|
}
|
|
|
|
var syncStatusCmd = &cli.Command{
|
|
Name: "status",
|
|
Usage: "check sync status",
|
|
Action: func(cctx *cli.Context) error {
|
|
apic, closer, err := GetFullNodeAPI(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closer()
|
|
ctx := ReqContext(cctx)
|
|
|
|
state, err := apic.SyncState(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Println("sync status:")
|
|
for i, ss := range state.ActiveSyncs {
|
|
fmt.Printf("worker %d:\n", i)
|
|
var base, target []cid.Cid
|
|
var heightDiff int64
|
|
var theight abi.ChainEpoch
|
|
if ss.Base != nil {
|
|
base = ss.Base.Cids()
|
|
heightDiff = int64(ss.Base.Height())
|
|
}
|
|
if ss.Target != nil {
|
|
target = ss.Target.Cids()
|
|
heightDiff = int64(ss.Target.Height()) - heightDiff
|
|
theight = ss.Target.Height()
|
|
} else {
|
|
heightDiff = 0
|
|
}
|
|
fmt.Printf("\tBase:\t%s\n", base)
|
|
fmt.Printf("\tTarget:\t%s (%d)\n", target, theight)
|
|
fmt.Printf("\tHeight diff:\t%d\n", heightDiff)
|
|
fmt.Printf("\tStage: %s\n", chain.SyncStageString(ss.Stage))
|
|
fmt.Printf("\tHeight: %d\n", ss.Height)
|
|
if ss.End.IsZero() {
|
|
if !ss.Start.IsZero() {
|
|
fmt.Printf("\tElapsed: %s\n", time.Since(ss.Start))
|
|
}
|
|
} else {
|
|
fmt.Printf("\tElapsed: %s\n", ss.End.Sub(ss.Start))
|
|
}
|
|
if ss.Stage == api.StageSyncErrored {
|
|
fmt.Printf("\tError: %s\n", ss.Message)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var syncWaitCmd = &cli.Command{
|
|
Name: "wait",
|
|
Usage: "Wait for sync to be complete",
|
|
Action: func(cctx *cli.Context) error {
|
|
napi, closer, err := GetFullNodeAPI(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closer()
|
|
ctx := ReqContext(cctx)
|
|
|
|
return SyncWait(ctx, napi)
|
|
},
|
|
}
|
|
|
|
var syncMarkBadCmd = &cli.Command{
|
|
Name: "mark-bad",
|
|
Usage: "Mark the given block as bad, will prevent syncing to a chain that contains it",
|
|
ArgsUsage: "[blockCid]",
|
|
Action: func(cctx *cli.Context) error {
|
|
napi, closer, err := GetFullNodeAPI(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closer()
|
|
ctx := ReqContext(cctx)
|
|
|
|
if !cctx.Args().Present() {
|
|
return fmt.Errorf("must specify block cid to mark")
|
|
}
|
|
|
|
bcid, err := cid.Decode(cctx.Args().First())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to decode input as a cid: %s", err)
|
|
}
|
|
|
|
return napi.SyncMarkBad(ctx, bcid)
|
|
},
|
|
}
|
|
|
|
var syncCheckBadCmd = &cli.Command{
|
|
Name: "check-bad",
|
|
Usage: "check if the given block was marked bad, and for what reason",
|
|
ArgsUsage: "[blockCid]",
|
|
Action: func(cctx *cli.Context) error {
|
|
napi, closer, err := GetFullNodeAPI(cctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closer()
|
|
ctx := ReqContext(cctx)
|
|
|
|
if !cctx.Args().Present() {
|
|
return fmt.Errorf("must specify block cid to check")
|
|
}
|
|
|
|
bcid, err := cid.Decode(cctx.Args().First())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to decode input as a cid: %s", err)
|
|
}
|
|
|
|
reason, err := napi.SyncCheckBad(ctx, bcid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if reason == "" {
|
|
fmt.Println("block was not marked as bad")
|
|
return nil
|
|
}
|
|
|
|
fmt.Println(reason)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|
for {
|
|
state, err := napi.SyncState(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
head, err := napi.ChainHead(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
working := 0
|
|
for i, ss := range state.ActiveSyncs {
|
|
switch ss.Stage {
|
|
case api.StageSyncComplete:
|
|
default:
|
|
working = i
|
|
case api.StageIdle:
|
|
// not complete, not actively working
|
|
}
|
|
}
|
|
|
|
ss := state.ActiveSyncs[working]
|
|
|
|
var target []cid.Cid
|
|
if ss.Target != nil {
|
|
target = ss.Target.Cids()
|
|
}
|
|
|
|
fmt.Printf("\r\x1b[2KWorker %d: Target: %s\tState: %s\tHeight: %d", working, target, chain.SyncStageString(ss.Stage), ss.Height)
|
|
|
|
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelay) {
|
|
fmt.Println("\nDone!")
|
|
return nil
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
fmt.Println("\nExit by user")
|
|
return nil
|
|
case <-time.After(1 * time.Second):
|
|
}
|
|
}
|
|
}
|