Merge remote-tracking branch 'origin/master' into refactor/net-upgrade
This commit is contained in:
commit
f7934b083c
12
cli/sync.go
12
cli/sync.go
@ -249,14 +249,24 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
|
|||||||
|
|
||||||
ss := state.ActiveSyncs[working]
|
ss := state.ActiveSyncs[working]
|
||||||
|
|
||||||
|
var baseHeight abi.ChainEpoch
|
||||||
var target []cid.Cid
|
var target []cid.Cid
|
||||||
var theight abi.ChainEpoch
|
var theight abi.ChainEpoch
|
||||||
|
var heightDiff int64
|
||||||
|
|
||||||
|
if ss.Base != nil {
|
||||||
|
baseHeight = ss.Base.Height()
|
||||||
|
heightDiff = int64(ss.Base.Height())
|
||||||
|
}
|
||||||
if ss.Target != nil {
|
if ss.Target != nil {
|
||||||
target = ss.Target.Cids()
|
target = ss.Target.Cids()
|
||||||
theight = ss.Target.Height()
|
theight = ss.Target.Height()
|
||||||
|
heightDiff = int64(ss.Target.Height()) - heightDiff
|
||||||
|
} else {
|
||||||
|
heightDiff = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, ss.Stage, ss.Height)
|
fmt.Printf("\r\x1b[2KWorker %d: Base Height: %d\tTarget Height: %d\t Height diff: %d\tTarget: %s\tState: %s\tHeight: %d", working, baseHeight, theight, heightDiff, target, ss.Stage, ss.Height)
|
||||||
|
|
||||||
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
|
||||||
fmt.Println("\nDone!")
|
fmt.Println("\nDone!")
|
||||||
|
286
cmd/lotus-shed/consensus.go
Normal file
286
cmd/lotus-shed/consensus.go
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/api/client"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var consensusCmd = &cli.Command{
|
||||||
|
Name: "consensus",
|
||||||
|
Usage: "tools for gathering information about consensus between nodes",
|
||||||
|
Flags: []cli.Flag{},
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
consensusCheckCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type consensusItem struct {
|
||||||
|
multiaddr multiaddr.Multiaddr
|
||||||
|
genesisTipset *types.TipSet
|
||||||
|
targetTipset *types.TipSet
|
||||||
|
headTipset *types.TipSet
|
||||||
|
peerID peer.ID
|
||||||
|
version api.Version
|
||||||
|
api api.FullNode
|
||||||
|
}
|
||||||
|
|
||||||
|
var consensusCheckCmd = &cli.Command{
|
||||||
|
Name: "check",
|
||||||
|
Usage: "verify if all nodes agree upon a common tipset for a given tipset height",
|
||||||
|
Description: `Consensus check verifies that all nodes share a common tipset for a given
|
||||||
|
height.
|
||||||
|
|
||||||
|
The height flag specifies a chain height to start a comparison from. There are two special
|
||||||
|
arguments for this flag. All other expected values should be chain tipset heights.
|
||||||
|
|
||||||
|
@common - Use the maximum common chain height between all nodes
|
||||||
|
@expected - Use the current time and the genesis timestamp to determine a height
|
||||||
|
|
||||||
|
Examples
|
||||||
|
|
||||||
|
Find the highest common tipset and look back 10 tipsets
|
||||||
|
lotus-shed consensus check --height @common --lookback 10
|
||||||
|
|
||||||
|
Calculate the expected tipset height and look back 10 tipsets
|
||||||
|
lotus-shed consensus check --height @expected --lookback 10
|
||||||
|
|
||||||
|
Check if nodes all share a common genesis
|
||||||
|
lotus-shed consensus check --height 0
|
||||||
|
|
||||||
|
Check that all nodes agree upon the tipset for 1day post genesis
|
||||||
|
lotus-shed consensus check --height 2880 --lookback 0
|
||||||
|
`,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "height",
|
||||||
|
Value: "@common",
|
||||||
|
Usage: "height of tipset to start check from",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "lookback",
|
||||||
|
Value: int(build.MessageConfidence * 2),
|
||||||
|
Usage: "number of tipsets behind to look back when comparing nodes",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
filePath := cctx.Args().First()
|
||||||
|
|
||||||
|
var input *bufio.Reader
|
||||||
|
if cctx.Args().Len() == 0 {
|
||||||
|
input = bufio.NewReader(os.Stdin)
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
inputFile, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer inputFile.Close() //nolint:errcheck
|
||||||
|
input = bufio.NewReader(inputFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes []*consensusItem
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
|
||||||
|
for {
|
||||||
|
strma, errR := input.ReadString('\n')
|
||||||
|
strma = strings.TrimSpace(strma)
|
||||||
|
|
||||||
|
if len(strma) == 0 {
|
||||||
|
if errR == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
apima, err := multiaddr.NewMultiaddr(strma)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ainfo := lcli.APIInfo{Addr: apima}
|
||||||
|
addr, err := ainfo.DialArgs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
api, closer, err := client.NewFullNodeRPC(cctx.Context, addr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
peerID, err := api.ID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := api.Version(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
genesisTipset, err := api.ChainGetGenesis(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
headTipset, err := api.ChainHead(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes = append(nodes, &consensusItem{
|
||||||
|
genesisTipset: genesisTipset,
|
||||||
|
headTipset: headTipset,
|
||||||
|
multiaddr: apima,
|
||||||
|
api: api,
|
||||||
|
peerID: peerID,
|
||||||
|
version: version,
|
||||||
|
})
|
||||||
|
|
||||||
|
if errR != nil && errR != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if errR == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return fmt.Errorf("no nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
genesisBuckets := make(map[types.TipSetKey][]*consensusItem)
|
||||||
|
for _, node := range nodes {
|
||||||
|
genesisBuckets[node.genesisTipset.Key()] = append(genesisBuckets[node.genesisTipset.Key()], node)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(genesisBuckets) != 1 {
|
||||||
|
for _, nodes := range genesisBuckets {
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Errorw(
|
||||||
|
"genesis do not match",
|
||||||
|
"genesis_tipset", node.genesisTipset.Key(),
|
||||||
|
"peer_id", node.peerID,
|
||||||
|
"version", node.version,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("genesis does not match between all nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
target := abi.ChainEpoch(0)
|
||||||
|
|
||||||
|
switch cctx.String("height") {
|
||||||
|
case "@common":
|
||||||
|
minTipset := nodes[0].headTipset
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.headTipset.Height() < minTipset.Height() {
|
||||||
|
minTipset = node.headTipset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target = minTipset.Height()
|
||||||
|
case "@expected":
|
||||||
|
tnow := uint64(time.Now().Unix())
|
||||||
|
tgen := nodes[0].genesisTipset.MinTimestamp()
|
||||||
|
|
||||||
|
target = abi.ChainEpoch((tnow - tgen) / build.BlockDelaySecs)
|
||||||
|
default:
|
||||||
|
h, err := strconv.Atoi(strings.TrimSpace(cctx.String("height")))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse string: %s", cctx.String("height"))
|
||||||
|
}
|
||||||
|
|
||||||
|
target = abi.ChainEpoch(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
lookback := abi.ChainEpoch(cctx.Int("lookback"))
|
||||||
|
if lookback > target {
|
||||||
|
target = abi.ChainEpoch(0)
|
||||||
|
} else {
|
||||||
|
target = target - lookback
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
targetTipset, err := node.api.ChainGetTipSetByHeight(ctx, target, types.EmptyTSK)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorw("error checking target", "err", err)
|
||||||
|
node.targetTipset = nil
|
||||||
|
} else {
|
||||||
|
node.targetTipset = targetTipset
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Debugw(
|
||||||
|
"node info",
|
||||||
|
"peer_id", node.peerID,
|
||||||
|
"version", node.version,
|
||||||
|
"genesis_tipset", node.genesisTipset.Key(),
|
||||||
|
"head_tipset", node.headTipset.Key(),
|
||||||
|
"target_tipset", node.targetTipset.Key(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
targetBuckets := make(map[types.TipSetKey][]*consensusItem)
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.targetTipset == nil {
|
||||||
|
targetBuckets[types.EmptyTSK] = append(targetBuckets[types.EmptyTSK], node)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
targetBuckets[node.targetTipset.Key()] = append(targetBuckets[node.targetTipset.Key()], node)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodes, ok := targetBuckets[types.EmptyTSK]; ok {
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Errorw(
|
||||||
|
"targeted tipset not found",
|
||||||
|
"peer_id", node.peerID,
|
||||||
|
"version", node.version,
|
||||||
|
"genesis_tipset", node.genesisTipset.Key(),
|
||||||
|
"head_tipset", node.headTipset.Key(),
|
||||||
|
"target_tipset", node.targetTipset.Key(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("targeted tipset not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(targetBuckets) != 1 {
|
||||||
|
for _, nodes := range targetBuckets {
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Errorw(
|
||||||
|
"targeted tipset not found",
|
||||||
|
"peer_id", node.peerID,
|
||||||
|
"version", node.version,
|
||||||
|
"genesis_tipset", node.genesisTipset.Key(),
|
||||||
|
"head_tipset", node.headTipset.Key(),
|
||||||
|
"target_tipset", node.targetTipset.Key(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("nodes not in consensus at tipset height %d", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
@ -35,6 +35,7 @@ func main() {
|
|||||||
mathCmd,
|
mathCmd,
|
||||||
mpoolStatsCmd,
|
mpoolStatsCmd,
|
||||||
exportChainCmd,
|
exportChainCmd,
|
||||||
|
consensusCmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
@ -49,6 +50,13 @@ func main() {
|
|||||||
Hidden: true,
|
Hidden: true,
|
||||||
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||||
},
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "log-level",
|
||||||
|
Value: "info",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Before: func(cctx *cli.Context) error {
|
||||||
|
return logging.SetLogLevel("lotus-shed", cctx.String("log-level"))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +163,10 @@ var runCmd = &cli.Command{
|
|||||||
sigChan := make(chan os.Signal, 2)
|
sigChan := make(chan os.Signal, 2)
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-sigChan:
|
case sig := <-sigChan:
|
||||||
|
log.Warnw("received shutdown", "signal", sig)
|
||||||
case <-shutdownChan:
|
case <-shutdownChan:
|
||||||
|
log.Warn("received shutdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("Shutting down...")
|
log.Warn("Shutting down...")
|
||||||
|
@ -18,7 +18,9 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
|
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sectorsCmd = &cli.Command{
|
var sectorsCmd = &cli.Command{
|
||||||
@ -137,6 +139,12 @@ var sectorsStatusCmd = &cli.Command{
|
|||||||
var sectorsListCmd = &cli.Command{
|
var sectorsListCmd = &cli.Command{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List sectors",
|
Usage: "List sectors",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "show-removed",
|
||||||
|
Usage: "show removed sectors",
|
||||||
|
},
|
||||||
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -193,10 +201,11 @@ var sectorsListCmd = &cli.Command{
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cctx.Bool("show-removed") || st.State != api.SectorState(sealing.Removed) {
|
||||||
_, inSSet := commitedIDs[s]
|
_, inSSet := commitedIDs[s]
|
||||||
_, inASet := activeIDs[s]
|
_, inASet := activeIDs[s]
|
||||||
|
|
||||||
fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\t toUpgrade:%t\n",
|
_, _ = fmt.Fprintf(w, "%d: %s\tsSet: %s\tactive: %s\ttktH: %d\tseedH: %d\tdeals: %v\t toUpgrade:%t\n",
|
||||||
s,
|
s,
|
||||||
st.State,
|
st.State,
|
||||||
yesno(inSSet),
|
yesno(inSSet),
|
||||||
@ -207,6 +216,7 @@ var sectorsListCmd = &cli.Command{
|
|||||||
st.ToUpgrade,
|
st.ToUpgrade,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return w.Flush()
|
return w.Flush()
|
||||||
},
|
},
|
||||||
@ -421,6 +431,10 @@ var sectorsUpdateCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("could not parse sector number: %w", err)
|
return xerrors.Errorf("could not parse sector number: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := sealing.ExistSectorStateList[sealing.SectorState(cctx.Args().Get(1))]; !ok {
|
||||||
|
return xerrors.Errorf("Not existing sector state")
|
||||||
|
}
|
||||||
|
|
||||||
return nodeApi.SectorsUpdate(ctx, abi.SectorNumber(id), api.SectorState(cctx.Args().Get(1)))
|
return nodeApi.SectorsUpdate(ctx, abi.SectorNumber(id), api.SectorState(cctx.Args().Get(1)))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -370,7 +370,7 @@ var storageFindCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("In %s (%s)\n", info.id, types[:len(types)-2])
|
fmt.Printf("In %s (%s)\n", info.id, types[:len(types)-2])
|
||||||
fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanSeal)
|
fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanStore)
|
||||||
if localPath, ok := local[info.id]; ok {
|
if localPath, ok := local[info.id]; ok {
|
||||||
fmt.Printf("\tLocal (%s)\n", localPath)
|
fmt.Printf("\tLocal (%s)\n", localPath)
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,8 +66,10 @@ func serveRPC(a api.FullNode, stop node.StopFunc, addr multiaddr.Multiaddr, shut
|
|||||||
shutdownDone := make(chan struct{})
|
shutdownDone := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-sigCh:
|
case sig := <-sigCh:
|
||||||
|
log.Warnw("received shutdown", "signal", sig)
|
||||||
case <-shutdownCh:
|
case <-shutdownCh:
|
||||||
|
log.Warn("received shutdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("Shutting down...")
|
log.Warn("Shutting down...")
|
||||||
|
@ -7,8 +7,6 @@ import (
|
|||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
typegen "github.com/whyrusleeping/cbor-gen"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run ./gen
|
//go:generate go run ./gen
|
||||||
@ -31,10 +29,14 @@ type Actor struct{}
|
|||||||
type CallerValidationBranch int64
|
type CallerValidationBranch int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// CallerValidationBranchNone causes no caller validation to take place.
|
||||||
CallerValidationBranchNone CallerValidationBranch = iota
|
CallerValidationBranchNone CallerValidationBranch = iota
|
||||||
|
// CallerValidationBranchTwice causes Runtime.ValidateImmediateCallerAcceptAny to be called twice.
|
||||||
CallerValidationBranchTwice
|
CallerValidationBranchTwice
|
||||||
CallerValidationBranchAddrNilSet
|
// CallerValidationBranchIsAddress causes caller validation against CallerValidationArgs.Addrs.
|
||||||
CallerValidationBranchTypeNilSet
|
CallerValidationBranchIsAddress
|
||||||
|
// CallerValidationBranchIsType causes caller validation against CallerValidationArgs.Types.
|
||||||
|
CallerValidationBranchIsType
|
||||||
)
|
)
|
||||||
|
|
||||||
// MutateStateBranch is an enum used to select the type of state mutation to attempt.
|
// MutateStateBranch is an enum used to select the type of state mutation to attempt.
|
||||||
@ -123,23 +125,29 @@ func (a Actor) Constructor(_ runtime.Runtime, _ *abi.EmptyValue) *abi.EmptyValue
|
|||||||
panic("constructor should not be called; the Chaos actor is a singleton actor")
|
panic("constructor should not be called; the Chaos actor is a singleton actor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CallerValidationArgs are the arguments to Actor.CallerValidation.
|
||||||
|
type CallerValidationArgs struct {
|
||||||
|
Branch CallerValidationBranch
|
||||||
|
Addrs []address.Address
|
||||||
|
Types []cid.Cid
|
||||||
|
}
|
||||||
|
|
||||||
// CallerValidation violates VM call validation constraints.
|
// CallerValidation violates VM call validation constraints.
|
||||||
//
|
//
|
||||||
// CallerValidationBranchNone performs no validation.
|
// CallerValidationBranchNone performs no validation.
|
||||||
// CallerValidationBranchTwice validates twice.
|
// CallerValidationBranchTwice validates twice.
|
||||||
// CallerValidationBranchAddrNilSet validates against an empty caller
|
// CallerValidationBranchIsAddress validates caller against CallerValidationArgs.Addrs.
|
||||||
// address set.
|
// CallerValidationBranchIsType validates caller against CallerValidationArgs.Types.
|
||||||
// CallerValidationBranchTypeNilSet validates against an empty caller type set.
|
func (a Actor) CallerValidation(rt runtime.Runtime, args *CallerValidationArgs) *abi.EmptyValue {
|
||||||
func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *abi.EmptyValue {
|
switch args.Branch {
|
||||||
switch CallerValidationBranch(*branch) {
|
|
||||||
case CallerValidationBranchNone:
|
case CallerValidationBranchNone:
|
||||||
case CallerValidationBranchTwice:
|
case CallerValidationBranchTwice:
|
||||||
rt.ValidateImmediateCallerAcceptAny()
|
rt.ValidateImmediateCallerAcceptAny()
|
||||||
rt.ValidateImmediateCallerAcceptAny()
|
rt.ValidateImmediateCallerAcceptAny()
|
||||||
case CallerValidationBranchAddrNilSet:
|
case CallerValidationBranchIsAddress:
|
||||||
rt.ValidateImmediateCallerIs()
|
rt.ValidateImmediateCallerIs(args.Addrs...)
|
||||||
case CallerValidationBranchTypeNilSet:
|
case CallerValidationBranchIsType:
|
||||||
rt.ValidateImmediateCallerType()
|
rt.ValidateImmediateCallerType(args.Types...)
|
||||||
default:
|
default:
|
||||||
panic("invalid branch passed to CallerValidation")
|
panic("invalid branch passed to CallerValidation")
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
"github.com/filecoin-project/specs-actors/support/mock"
|
"github.com/filecoin-project/specs-actors/support/mock"
|
||||||
atesting "github.com/filecoin-project/specs-actors/support/testing"
|
atesting "github.com/filecoin-project/specs-actors/support/testing"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSingleton(t *testing.T) {
|
func TestSingleton(t *testing.T) {
|
||||||
@ -25,6 +27,86 @@ func TestSingleton(t *testing.T) {
|
|||||||
rt.Verify()
|
rt.Verify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCallerValidationNone(t *testing.T) {
|
||||||
|
receiver := atesting.NewIDAddr(t, 100)
|
||||||
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
|
||||||
|
rt := builder.Build(t)
|
||||||
|
var a Actor
|
||||||
|
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{Branch: CallerValidationBranchNone})
|
||||||
|
rt.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallerValidationIs(t *testing.T) {
|
||||||
|
caller := atesting.NewIDAddr(t, 100)
|
||||||
|
receiver := atesting.NewIDAddr(t, 101)
|
||||||
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
|
||||||
|
rt := builder.Build(t)
|
||||||
|
rt.SetCaller(caller, builtin.AccountActorCodeID)
|
||||||
|
var a Actor
|
||||||
|
|
||||||
|
caddrs := []address.Address{atesting.NewIDAddr(t, 101)}
|
||||||
|
|
||||||
|
rt.ExpectValidateCallerAddr(caddrs...)
|
||||||
|
// FIXME: https://github.com/filecoin-project/specs-actors/pull/1155
|
||||||
|
rt.ExpectAbort(exitcode.ErrForbidden, func() {
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{
|
||||||
|
Branch: CallerValidationBranchIsAddress,
|
||||||
|
Addrs: caddrs,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
|
||||||
|
rt.ExpectValidateCallerAddr(caller)
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{
|
||||||
|
Branch: CallerValidationBranchIsAddress,
|
||||||
|
Addrs: []address.Address{caller},
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallerValidationType(t *testing.T) {
|
||||||
|
caller := atesting.NewIDAddr(t, 100)
|
||||||
|
receiver := atesting.NewIDAddr(t, 101)
|
||||||
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
|
||||||
|
rt := builder.Build(t)
|
||||||
|
rt.SetCaller(caller, builtin.AccountActorCodeID)
|
||||||
|
var a Actor
|
||||||
|
|
||||||
|
rt.ExpectValidateCallerType(builtin.CronActorCodeID)
|
||||||
|
// FIXME: https://github.com/filecoin-project/specs-actors/pull/1155
|
||||||
|
rt.ExpectAbort(exitcode.ErrForbidden, func() {
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{
|
||||||
|
Branch: CallerValidationBranchIsType,
|
||||||
|
Types: []cid.Cid{builtin.CronActorCodeID},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
|
||||||
|
rt.ExpectValidateCallerType(builtin.AccountActorCodeID)
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{
|
||||||
|
Branch: CallerValidationBranchIsType,
|
||||||
|
Types: []cid.Cid{builtin.AccountActorCodeID},
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCallerValidationInvalidBranch(t *testing.T) {
|
||||||
|
receiver := atesting.NewIDAddr(t, 100)
|
||||||
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
|
||||||
|
rt := builder.Build(t)
|
||||||
|
var a Actor
|
||||||
|
|
||||||
|
rt.ExpectAssertionFailure("invalid branch passed to CallerValidation", func() {
|
||||||
|
rt.Call(a.CallerValidation, &CallerValidationArgs{Branch: -1})
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeleteActor(t *testing.T) {
|
func TestDeleteActor(t *testing.T) {
|
||||||
receiver := atesting.NewIDAddr(t, 100)
|
receiver := atesting.NewIDAddr(t, 100)
|
||||||
beneficiary := atesting.NewIDAddr(t, 101)
|
beneficiary := atesting.NewIDAddr(t, 101)
|
||||||
@ -118,6 +200,20 @@ func TestMutateStateReadonly(t *testing.T) {
|
|||||||
rt.Verify()
|
rt.Verify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMutateStateInvalidBranch(t *testing.T) {
|
||||||
|
receiver := atesting.NewIDAddr(t, 100)
|
||||||
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
|
||||||
|
rt := builder.Build(t)
|
||||||
|
var a Actor
|
||||||
|
|
||||||
|
rt.ExpectValidateCallerAny()
|
||||||
|
rt.ExpectAssertionFailure("unknown mutation type", func() {
|
||||||
|
rt.Call(a.MutateState, &MutateStateArgs{Branch: -1})
|
||||||
|
})
|
||||||
|
rt.Verify()
|
||||||
|
}
|
||||||
|
|
||||||
func TestAbortWith(t *testing.T) {
|
func TestAbortWith(t *testing.T) {
|
||||||
receiver := atesting.NewIDAddr(t, 100)
|
receiver := atesting.NewIDAddr(t, 100)
|
||||||
builder := mock.NewBuilder(context.Background(), receiver)
|
builder := mock.NewBuilder(context.Background(), receiver)
|
||||||
|
@ -6,8 +6,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
address "github.com/filecoin-project/go-address"
|
||||||
abi "github.com/filecoin-project/go-state-types/abi"
|
abi "github.com/filecoin-project/go-state-types/abi"
|
||||||
exitcode "github.com/filecoin-project/go-state-types/exitcode"
|
exitcode "github.com/filecoin-project/go-state-types/exitcode"
|
||||||
|
cid "github.com/ipfs/go-cid"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
xerrors "golang.org/x/xerrors"
|
xerrors "golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
@ -115,6 +117,163 @@ func (t *State) UnmarshalCBOR(r io.Reader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lengthBufCallerValidationArgs = []byte{131}
|
||||||
|
|
||||||
|
func (t *CallerValidationArgs) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write(lengthBufCallerValidationArgs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch := make([]byte, 9)
|
||||||
|
|
||||||
|
// t.Branch (chaos.CallerValidationBranch) (int64)
|
||||||
|
if t.Branch >= 0 {
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Branch)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Branch-1)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Addrs ([]address.Address) (slice)
|
||||||
|
if len(t.Addrs) > cbg.MaxLength {
|
||||||
|
return xerrors.Errorf("Slice value in field t.Addrs was too long")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Addrs))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range t.Addrs {
|
||||||
|
if err := v.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Types ([]cid.Cid) (slice)
|
||||||
|
if len(t.Types) > cbg.MaxLength {
|
||||||
|
return xerrors.Errorf("Slice value in field t.Types was too long")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Types))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range t.Types {
|
||||||
|
if err := cbg.WriteCidBuf(scratch, w, v); err != nil {
|
||||||
|
return xerrors.Errorf("failed writing cid field t.Types: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *CallerValidationArgs) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
*t = CallerValidationArgs{}
|
||||||
|
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
scratch := make([]byte, 8)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 3 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Branch (chaos.CallerValidationBranch) (int64)
|
||||||
|
{
|
||||||
|
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
var extraI int64
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch maj {
|
||||||
|
case cbg.MajUnsignedInt:
|
||||||
|
extraI = int64(extra)
|
||||||
|
if extraI < 0 {
|
||||||
|
return fmt.Errorf("int64 positive overflow")
|
||||||
|
}
|
||||||
|
case cbg.MajNegativeInt:
|
||||||
|
extraI = int64(extra)
|
||||||
|
if extraI < 0 {
|
||||||
|
return fmt.Errorf("int64 negative oveflow")
|
||||||
|
}
|
||||||
|
extraI = -1 - extraI
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Branch = CallerValidationBranch(extraI)
|
||||||
|
}
|
||||||
|
// t.Addrs ([]address.Address) (slice)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra > cbg.MaxLength {
|
||||||
|
return fmt.Errorf("t.Addrs: array too large (%d)", extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("expected cbor array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra > 0 {
|
||||||
|
t.Addrs = make([]address.Address, extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(extra); i++ {
|
||||||
|
|
||||||
|
var v address.Address
|
||||||
|
if err := v.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Addrs[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.Types ([]cid.Cid) (slice)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra > cbg.MaxLength {
|
||||||
|
return fmt.Errorf("t.Types: array too large (%d)", extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("expected cbor array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra > 0 {
|
||||||
|
t.Types = make([]cid.Cid, extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(extra); i++ {
|
||||||
|
|
||||||
|
c, err := cbg.ReadCid(br)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("reading cid field t.Types failed: %w", err)
|
||||||
|
}
|
||||||
|
t.Types[i] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var lengthBufCreateActorArgs = []byte{132}
|
var lengthBufCreateActorArgs = []byte{132}
|
||||||
|
|
||||||
func (t *CreateActorArgs) MarshalCBOR(w io.Writer) error {
|
func (t *CreateActorArgs) MarshalCBOR(w io.Writer) error {
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
if err := gen.WriteTupleEncodersToFile("./cbor_gen.go", "chaos",
|
if err := gen.WriteTupleEncodersToFile("./cbor_gen.go", "chaos",
|
||||||
chaos.State{},
|
chaos.State{},
|
||||||
|
chaos.CallerValidationArgs{},
|
||||||
chaos.CreateActorArgs{},
|
chaos.CreateActorArgs{},
|
||||||
chaos.ResolveAddressResponse{},
|
chaos.ResolveAddressResponse{},
|
||||||
chaos.SendArgs{},
|
chaos.SendArgs{},
|
||||||
|
32
extern/storage-sealing/sector_state.go
vendored
32
extern/storage-sealing/sector_state.go
vendored
@ -2,6 +2,38 @@ package sealing
|
|||||||
|
|
||||||
type SectorState string
|
type SectorState string
|
||||||
|
|
||||||
|
var ExistSectorStateList = map[SectorState]struct{}{
|
||||||
|
Empty: {},
|
||||||
|
WaitDeals: {},
|
||||||
|
Packing: {},
|
||||||
|
PreCommit1: {},
|
||||||
|
PreCommit2: {},
|
||||||
|
PreCommitting: {},
|
||||||
|
PreCommitWait: {},
|
||||||
|
WaitSeed: {},
|
||||||
|
Committing: {},
|
||||||
|
SubmitCommit: {},
|
||||||
|
CommitWait: {},
|
||||||
|
FinalizeSector: {},
|
||||||
|
Proving: {},
|
||||||
|
FailedUnrecoverable: {},
|
||||||
|
SealPreCommit1Failed: {},
|
||||||
|
SealPreCommit2Failed: {},
|
||||||
|
PreCommitFailed: {},
|
||||||
|
ComputeProofFailed: {},
|
||||||
|
CommitFailed: {},
|
||||||
|
PackingFailed: {},
|
||||||
|
FinalizeFailed: {},
|
||||||
|
DealsExpired: {},
|
||||||
|
RecoverDealIDs: {},
|
||||||
|
Faulty: {},
|
||||||
|
FaultReported: {},
|
||||||
|
FaultedFinal: {},
|
||||||
|
Removing: {},
|
||||||
|
RemoveFailed: {},
|
||||||
|
Removed: {},
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UndefinedSectorState SectorState = ""
|
UndefinedSectorState SectorState = ""
|
||||||
|
|
||||||
|
2
extern/test-vectors
vendored
2
extern/test-vectors
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12
|
Subproject commit 6bea015edddde116001a4251dce3c4a9966c25d9
|
@ -2,7 +2,7 @@
|
|||||||
Description=Lotus Miner
|
Description=Lotus Miner
|
||||||
After=network.target
|
After=network.target
|
||||||
After=lotus-daemon.service
|
After=lotus-daemon.service
|
||||||
Requires=lotus-daemon.service
|
Wants=lotus-daemon.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/local/bin/lotus-miner run
|
ExecStart=/usr/local/bin/lotus-miner run
|
||||||
|
Loading…
Reference in New Issue
Block a user