Merge remote-tracking branch 'origin/master' into feat/async-restartable-workers

This commit is contained in:
Łukasz Magiera 2020-09-21 22:36:16 +02:00
commit aa5bd7bc17
50 changed files with 1691 additions and 153 deletions

View File

@ -254,6 +254,25 @@ jobs:
path: /tmp/test-reports path: /tmp/test-reports
- store_artifacts: - store_artifacts:
path: /tmp/test-artifacts/conformance-coverage.html path: /tmp/test-artifacts/conformance-coverage.html
build-lotus-soup:
description: |
Compile `lotus-soup` Testground test plan using the current version of Lotus.
parameters:
<<: *test-params
executor: << parameters.executor >>
steps:
- install-deps
- prepare
- run: cd extern/oni && git submodule sync
- run: cd extern/oni && git submodule update --init
- run: cd extern/filecoin-ffi && make
- run:
name: "replace lotus, filecoin-ffi, blst and fil-blst deps"
command: cd extern/oni/lotus-soup && go mod edit -replace github.com/filecoin-project/lotus=../../../ && go mod edit -replace github.com/filecoin-project/filecoin-ffi=../../filecoin-ffi && go mod edit -replace github.com/supranational/blst=../../fil-blst/blst && go mod edit -replace github.com/filecoin-project/fil-blst=../../fil-blst
- run:
name: "build lotus-soup testplan"
command: pushd extern/oni/lotus-soup && go build -tags=testground .
build-macos: build-macos:
description: build darwin lotus binary description: build darwin lotus binary
@ -428,6 +447,7 @@ workflows:
test-suite-name: conformance-bleeding-edge test-suite-name: conformance-bleeding-edge
packages: "./conformance" packages: "./conformance"
vectors-branch: master vectors-branch: master
- build-lotus-soup
- build-debug - build-debug
- build-all: - build-all:
requires: requires:

1
.gitignore vendored
View File

@ -11,6 +11,7 @@
/lotus-stats /lotus-stats
/lotus-bench /lotus-bench
/lotus-gateway /lotus-gateway
/lotus-pcr
/bench.json /bench.json
/lotuspond/front/node_modules /lotuspond/front/node_modules
/lotuspond/front/build /lotuspond/front/build

3
.gitmodules vendored
View File

@ -11,3 +11,6 @@
[submodule "extern/fil-blst"] [submodule "extern/fil-blst"]
path = extern/fil-blst path = extern/fil-blst
url = https://github.com/filecoin-project/fil-blst.git url = https://github.com/filecoin-project/fil-blst.git
[submodule "extern/oni"]
path = extern/oni
url = https://github.com/filecoin-project/oni

View File

@ -1,5 +1,29 @@
# Lotus changelog # Lotus changelog
# 0.7.1 / 2020-09-17
This optional release of Lotus introduces some critical fixes to the window PoSt process. It also upgrades some core dependencies, and introduces many improvements to the mining process, deal-making cycle, and overall User Experience.
## Changes
#### Some notable improvements:
- Correctly construct params for `SubmitWindowedPoSt` messages (https://github.com/filecoin-project/lotus/pull/3909)
- Skip sectors correctly for Window PoSt (https://github.com/filecoin-project/lotus/pull/3839)
- Split window PoST submission into multiple messages (https://github.com/filecoin-project/lotus/pull/3689)
- Improve journal coverage (https://github.com/filecoin-project/lotus/pull/2455)
- Allow retrievals while sealing (https://github.com/filecoin-project/lotus/pull/3778)
- Don't prune locally published messages (https://github.com/filecoin-project/lotus/pull/3772)
- Add get-ask, set-ask retrieval commands (https://github.com/filecoin-project/lotus/pull/3886)
- Consistently name winning and window post in logs (https://github.com/filecoin-project/lotus/pull/3873))
- Add auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3752))
#### Dependencies
- Upgrade markets to `v0.6.1` (https://github.com/filecoin-project/lotus/pull/3906)
- Upgrade specs-actors to `v0.9.10` (https://github.com/filecoin-project/lotus/pull/3846)
- Upgrade badger (https://github.com/filecoin-project/lotus/pull/3739)
# 0.7.0 / 2020-09-10 # 0.7.0 / 2020-09-10
This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are:

View File

@ -18,7 +18,7 @@ Lotus is an implementation of the Filecoin Distributed Storage Network. For more
## Building & Documentation ## Building & Documentation
For instructions on how to build lotus from source, please visit [https://lotu.sh](https://lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation). For instructions on how to build lotus from source, please visit [Lotus build and setup instruction](https://docs.filecoin.io/get-started/lotus/installation/#minimal-requirements) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
## Reporting a Vulnerability ## Reporting a Vulnerability

View File

@ -354,6 +354,8 @@ type FullNode interface {
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*SectorLocation, error)
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed // StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error) StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
// StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
StateMsgGasCost(context.Context, cid.Cid, types.TipSetKey) (*MsgGasCost, error)
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the // StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
// message arrives on chain, and gets to the indicated confidence depth. // message arrives on chain, and gets to the indicated confidence depth.
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error) StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
@ -531,6 +533,17 @@ type MsgLookup struct {
Height abi.ChainEpoch Height abi.ChainEpoch
} }
type MsgGasCost struct {
Message cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
GasUsed abi.TokenAmount
BaseFeeBurn abi.TokenAmount
OverEstimationBurn abi.TokenAmount
MinerPenalty abi.TokenAmount
MinerTip abi.TokenAmount
Refund abi.TokenAmount
TotalCost abi.TokenAmount
}
type BlockMessages struct { type BlockMessages struct {
BlsMessages []*types.Message BlsMessages []*types.Message
SecpkMessages []*types.SignedMessage SecpkMessages []*types.SignedMessage

View File

@ -183,6 +183,7 @@ type FullNodeStruct struct {
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"` StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"` StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"` StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"` StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"` StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"` StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
@ -827,6 +828,10 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
return c.Internal.StateReadState(ctx, addr, tsk) return c.Internal.StateReadState(ctx, addr, tsk)
} }
func (c *FullNodeStruct) StateMsgGasCost(ctx context.Context, msgc cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
return c.Internal.StateMsgGasCost(ctx, msgc, tsk)
}
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) { func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc, confidence) return c.Internal.StateWaitMsg(ctx, msgc, confidence)
} }

View File

@ -29,7 +29,7 @@ func init() {
BuildType |= Build2k BuildType |= Build2k
} }
const BlockDelaySecs = uint64(30) const BlockDelaySecs = uint64(4)
const PropagationDelaySecs = uint64(1) const PropagationDelaySecs = uint64(1)

View File

@ -29,7 +29,7 @@ func buildType() string {
} }
// BuildVersion is the local build version, set by build system // BuildVersion is the local build version, set by build system
const BuildVersion = "0.7.0" const BuildVersion = "0.7.1"
func UserVersion() string { func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit return BuildVersion + buildType() + CurrentCommit
@ -83,7 +83,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
// semver versions of the rpc api exposed // semver versions of the rpc api exposed
var ( var (
FullAPIVersion = newVer(0, 14, 0) FullAPIVersion = newVer(0, 15, 0)
MinerAPIVersion = newVer(0, 15, 0) MinerAPIVersion = newVer(0, 15, 0)
WorkerAPIVersion = newVer(0, 15, 0) WorkerAPIVersion = newVer(0, 15, 0)
) )

View File

@ -233,8 +233,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
} }
receipts = append(receipts, &r.MessageReceipt) receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, r.MinerTip) gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
penalty = big.Add(penalty, r.Penalty) penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
if cb != nil { if cb != nil {
if err := cb(cm.Cid(), m, r); err != nil { if err := cb(cm.Cid(), m, r); err != nil {

View File

@ -554,7 +554,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand) sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
if err != nil { if err != nil {
return nil, xerrors.Errorf("getting wpost proving set: %w", err) return nil, xerrors.Errorf("getting winning post proving set: %w", err)
} }
if len(sectors) == 0 { if len(sectors) == 0 {

View File

@ -18,7 +18,6 @@ import (
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/journal" "github.com/filecoin-project/lotus/journal"
bstore "github.com/filecoin-project/lotus/lib/blockstore" bstore "github.com/filecoin-project/lotus/lib/blockstore"
@ -767,32 +766,16 @@ type BlockMessages struct {
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) { func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
applied := make(map[address.Address]uint64) applied := make(map[address.Address]uint64)
cst := cbor.NewCborStore(cs.bs)
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
if err != nil {
return nil, xerrors.Errorf("failed to load state tree")
}
preloadAddr := func(a address.Address) error {
if _, ok := applied[a]; !ok {
act, err := st.GetActor(a)
if err != nil {
return err
}
applied[a] = act.Nonce
}
return nil
}
selectMsg := func(m *types.Message) (bool, error) { selectMsg := func(m *types.Message) (bool, error) {
if err := preloadAddr(m.From); err != nil { // The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
return false, err if _, ok := applied[m.From]; !ok {
applied[m.From] = m.Nonce
} }
if applied[m.From] != m.Nonce { if applied[m.From] != m.Nonce {
return false, nil return false, nil
} }
applied[m.From]++ applied[m.From]++
return true, nil return true, nil

View File

@ -991,7 +991,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block
rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes()) rand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, h.Height, buf.Bytes())
if err != nil { if err != nil {
return xerrors.Errorf("failed to get randomness for verifying winningPost proof: %w", err) return xerrors.Errorf("failed to get randomness for verifying winning post proof: %w", err)
} }
mid, err := address.IDFromAddress(h.Miner) mid, err := address.IDFromAddress(h.Miner)

View File

@ -662,6 +662,49 @@ func TestDuplicateNonce(t *testing.T) {
require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message") require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message")
} }
// This test asserts that a block that includes a message with bad nonce can't be synced. A nonce is "bad" if it can't
// be applied on the parent state.
func TestBadNonce(t *testing.T) {
H := 10
tu := prepSyncTest(t, H)
base := tu.g.CurTipset
// Produce a message from the banker with a bad nonce
makeBadMsg := func() *types.SignedMessage {
ba, err := tu.nds[0].StateGetActor(context.TODO(), tu.g.Banker(), base.TipSet().Key())
require.NoError(t, err)
msg := types.Message{
To: tu.g.Banker(),
From: tu.g.Banker(),
Nonce: ba.Nonce + 5,
Value: types.NewInt(1),
Method: 0,
GasLimit: 100_000_000,
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
}
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
require.NoError(t, err)
return &types.SignedMessage{
Message: msg,
Signature: *sig,
}
}
msgs := make([][]*types.SignedMessage, 1)
msgs[0] = []*types.SignedMessage{makeBadMsg()}
tu.mineOnBlock(base, 0, []int{0}, true, true, msgs)
}
func BenchmarkSyncBasic(b *testing.B) { func BenchmarkSyncBasic(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
runSyncBenchLength(b, 100) runSyncBenchLength(b, 100)

View File

@ -22,6 +22,17 @@ type GasOutputs struct {
GasBurned int64 GasBurned int64
} }
// ZeroGasOutputs returns a logically zeroed GasOutputs.
func ZeroGasOutputs() GasOutputs {
return GasOutputs{
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}
}
// ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned // ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned
// Result is (refund, burn) // Result is (refund, burn)
func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) { func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
@ -58,13 +69,7 @@ func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs { func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
gasUsedBig := big.NewInt(gasUsed) gasUsedBig := big.NewInt(gasUsed)
out := GasOutputs{ out := ZeroGasOutputs()
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}
baseFeeToPay := baseFee baseFeeToPay := baseFee
if baseFee.Cmp(feeCap.Int) > 0 { if baseFee.Cmp(feeCap.Int) > 0 {

View File

@ -201,10 +201,9 @@ type Rand interface {
type ApplyRet struct { type ApplyRet struct {
types.MessageReceipt types.MessageReceipt
ActorErr aerrors.ActorError ActorErr aerrors.ActorError
Penalty types.BigInt
MinerTip types.BigInt
ExecutionTrace types.ExecutionTrace ExecutionTrace types.ExecutionTrace
Duration time.Duration Duration time.Duration
GasCosts GasOutputs
} }
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
@ -328,8 +327,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
}, },
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0), GasCosts: GasOutputs{},
MinerTip: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, actorErr }, actorErr
} }
@ -357,14 +355,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
msgGasCost := msgGas.Total() msgGasCost := msgGas.Total()
// this should never happen, but is currently still exercised by some tests // this should never happen, but is currently still exercised by some tests
if msgGasCost > msg.GasLimit { if msgGasCost > msg.GasLimit {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost))
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrOutOfGas, ExitCode: exitcode.SysErrOutOfGas,
GasUsed: 0, GasUsed: 0,
}, },
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)), GasCosts: gasOutputs,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
@ -375,15 +374,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
// this should never happen, but is currently still exercised by some tests // this should never happen, but is currently still exercised by some tests
if err != nil { if err != nil {
if xerrors.Is(err, types.ErrActorNotFound) { if xerrors.Is(err, types.ErrActorNotFound) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderInvalid, ExitCode: exitcode.SysErrSenderInvalid,
GasUsed: 0, GasUsed: 0,
}, },
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From), ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
Penalty: minerPenaltyAmount, GasCosts: gasOutputs,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
return nil, xerrors.Errorf("failed to look up from actor: %w", err) return nil, xerrors.Errorf("failed to look up from actor: %w", err)
@ -391,19 +391,22 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
// this should never happen, but is currently still exercised by some tests // this should never happen, but is currently still exercised by some tests
if !fromActor.Code.Equals(builtin.AccountActorCodeID) { if !fromActor.Code.Equals(builtin.AccountActorCodeID) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderInvalid, ExitCode: exitcode.SysErrSenderInvalid,
GasUsed: 0, GasUsed: 0,
}, },
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code), ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
Penalty: minerPenaltyAmount, GasCosts: gasOutputs,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
if msg.Nonce != fromActor.Nonce { if msg.Nonce != fromActor.Nonce {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderStateInvalid, ExitCode: exitcode.SysErrSenderStateInvalid,
@ -411,14 +414,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}, },
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce), "actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
Penalty: minerPenaltyAmount,
GasCosts: gasOutputs,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap) gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
if fromActor.Balance.LessThan(gascost) { if fromActor.Balance.LessThan(gascost) {
gasOutputs := ZeroGasOutputs()
gasOutputs.MinerPenalty = minerPenaltyAmount
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
ExitCode: exitcode.SysErrSenderStateInvalid, ExitCode: exitcode.SysErrSenderStateInvalid,
@ -426,9 +431,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}, },
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)), "actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
Penalty: minerPenaltyAmount, GasCosts: gasOutputs,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
@ -521,8 +525,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}, },
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, ExecutionTrace: rt.executionTrace,
Penalty: gasOutputs.MinerPenalty, GasCosts: gasOutputs,
MinerTip: gasOutputs.MinerTip,
Duration: time.Since(start), Duration: time.Since(start),
}, nil }, nil
} }

View File

@ -12,6 +12,8 @@ import (
"text/tabwriter" "text/tabwriter"
"time" "time"
"github.com/filecoin-project/specs-actors/actors/builtin"
tm "github.com/buger/goterm" tm "github.com/buger/goterm"
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/fatih/color" "github.com/fatih/color"
@ -527,6 +529,11 @@ func interactiveDeal(cctx *cli.Context) error {
continue continue
} }
if days < int(build.MinDealDuration/builtin.EpochsInDay) {
printErr(xerrors.Errorf("minimum duration is %d days", int(build.MinDealDuration/builtin.EpochsInDay)))
continue
}
state = "miner" state = "miner"
case "miner": case "miner":
fmt.Print("Miner Address (t0..): ") fmt.Print("Miner Address (t0..): ")

View File

@ -66,6 +66,7 @@ var stateCmd = &cli.Command{
stateGetDealSetCmd, stateGetDealSetCmd,
stateWaitMsgCmd, stateWaitMsgCmd,
stateSearchMsgCmd, stateSearchMsgCmd,
stateMsgCostCmd,
stateMinerInfo, stateMinerInfo,
stateMarketCmd, stateMarketCmd,
}, },
@ -1312,6 +1313,60 @@ var stateSearchMsgCmd = &cli.Command{
}, },
} }
var stateMsgCostCmd = &cli.Command{
Name: "msg-cost",
Usage: "Get the detailed gas costs of a message",
ArgsUsage: "[messageCid]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must specify message cid to get gas costs for")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msg, err := cid.Decode(cctx.Args().First())
if err != nil {
return err
}
tsk := types.EmptyTSK
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
if ts != nil {
tsk = ts.Key()
}
mgc, err := api.StateMsgGasCost(ctx, msg, tsk)
if err != nil {
return err
}
if mgc != nil {
fmt.Printf("Message CID: %s", mgc.Message)
fmt.Printf("\nGas Used: %d", mgc.GasUsed)
fmt.Printf("\nBase Fee Burn: %d", mgc.BaseFeeBurn)
fmt.Printf("\nOverestimation Burn: %d", mgc.OverEstimationBurn)
fmt.Printf("\nMiner Tip: %d", mgc.MinerTip)
fmt.Printf("\nRefund: %d", mgc.Refund)
fmt.Printf("\nTotal Cost: %d", mgc.TotalCost)
fmt.Printf("\nMiner Penalty: %d", mgc.MinerPenalty)
} else {
fmt.Print("message was not found on chain")
}
return nil
},
}
var stateCallCmd = &cli.Command{ var stateCallCmd = &cli.Command{
Name: "call", Name: "call",
Usage: "Invoke a method on an actor locally", Usage: "Invoke a method on an actor locally",

View File

@ -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!")

View File

@ -56,6 +56,10 @@ var importBenchCmd = &cli.Command{
Usage: "set the parallelism factor for batch seal verification", Usage: "set the parallelism factor for batch seal verification",
Value: runtime.NumCPU(), Value: runtime.NumCPU(),
}, },
&cli.StringFlag{
Name: "repodir",
Usage: "set the repo directory for the lotus bench run (defaults to /tmp)",
},
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads") vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads")
@ -70,10 +74,16 @@ var importBenchCmd = &cli.Command{
} }
defer cfi.Close() //nolint:errcheck // read only file defer cfi.Close() //nolint:errcheck // read only file
tdir, err := ioutil.TempDir("", "lotus-import-bench") var tdir string
if rdir := cctx.String("repodir"); rdir != "" {
tdir = rdir
} else {
tmp, err := ioutil.TempDir("", "lotus-import-bench")
if err != nil { if err != nil {
return err return err
} }
tdir = tmp
}
bds, err := badger.NewDatastore(tdir, nil) bds, err := badger.NewDatastore(tdir, nil)
if err != nil { if err != nil {

View File

@ -387,7 +387,7 @@ var sealBenchCmd = &cli.Command{
return err return err
} }
if !ok { if !ok {
log.Error("post verification failed") log.Error("window post verification failed")
} }
verifyWindowpost1 := time.Now() verifyWindowpost1 := time.Now()
@ -403,7 +403,7 @@ var sealBenchCmd = &cli.Command{
return err return err
} }
if !ok { if !ok {
log.Error("post verification failed") log.Error("window post verification failed")
} }
verifyWindowpost2 := time.Now() verifyWindowpost2 := time.Now()

View File

@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
@ -28,6 +29,9 @@ var bitFieldCmd = &cli.Command{
bitFieldRunsCmd, bitFieldRunsCmd,
bitFieldStatCmd, bitFieldStatCmd,
bitFieldDecodeCmd, bitFieldDecodeCmd,
bitFieldIntersectCmd,
bitFieldEncodeCmd,
bitFieldSubCmd,
}, },
} }
@ -200,39 +204,10 @@ var bitFieldDecodeCmd = &cli.Command{
}, },
}, },
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
var val string rle, err := decode(cctx, 0)
if cctx.Args().Present() {
val = cctx.Args().Get(0)
} else {
b, err := ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
return err return err
} }
val = string(b)
}
var dec []byte
switch cctx.String("enc") {
case "base64":
d, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return fmt.Errorf("decoding base64 value: %w", err)
}
dec = d
case "hex":
d, err := hex.DecodeString(val)
if err != nil {
return fmt.Errorf("decoding hex value: %w", err)
}
dec = d
default:
return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
}
rle, err := bitfield.NewFromBytes(dec)
if err != nil {
return xerrors.Errorf("failed to parse bitfield: %w", err)
}
vals, err := rle.All(100000000000) vals, err := rle.All(100000000000)
if err != nil { if err != nil {
@ -243,3 +218,170 @@ var bitFieldDecodeCmd = &cli.Command{
return nil return nil
}, },
} }
var bitFieldIntersectCmd = &cli.Command{
Name: "intersect",
Description: "intersect 2 bitfields and print the resulting bitfield as base64",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "enc",
Value: "base64",
Usage: "specify input encoding to parse",
},
},
Action: func(cctx *cli.Context) error {
b, err := decode(cctx, 1)
if err != nil {
return err
}
a, err := decode(cctx, 0)
if err != nil {
return err
}
o, err := bitfield.IntersectBitField(a, b)
if err != nil {
return xerrors.Errorf("intersect: %w", err)
}
s, err := o.RunIterator()
if err != nil {
return err
}
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
if err != nil {
return err
}
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
return nil
},
}
var bitFieldSubCmd = &cli.Command{
Name: "sub",
Description: "subtract 2 bitfields and print the resulting bitfield as base64",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "enc",
Value: "base64",
Usage: "specify input encoding to parse",
},
},
Action: func(cctx *cli.Context) error {
b, err := decode(cctx, 1)
if err != nil {
return err
}
a, err := decode(cctx, 0)
if err != nil {
return err
}
o, err := bitfield.SubtractBitField(a, b)
if err != nil {
return xerrors.Errorf("intersect: %w", err)
}
s, err := o.RunIterator()
if err != nil {
return err
}
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
if err != nil {
return err
}
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
return nil
},
}
var bitFieldEncodeCmd = &cli.Command{
Name: "encode",
Description: "encode a series of decimal numbers into a bitfield",
ArgsUsage: "[infile]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "enc",
Value: "base64",
Usage: "specify input encoding to parse",
},
},
Action: func(cctx *cli.Context) error {
f, err := os.Open(cctx.Args().First())
if err != nil {
return err
}
defer f.Close() // nolint
out := bitfield.New()
for {
var i uint64
_, err := fmt.Fscan(f, &i)
if err == io.EOF {
break
}
out.Set(i)
}
s, err := out.RunIterator()
if err != nil {
return err
}
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
if err != nil {
return err
}
fmt.Println(base64.StdEncoding.EncodeToString(bytes))
return nil
},
}
func decode(cctx *cli.Context, a int) (bitfield.BitField, error) {
var val string
if cctx.Args().Present() {
if a >= cctx.NArg() {
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
}
val = cctx.Args().Get(a)
} else {
if a > 0 {
return bitfield.BitField{}, xerrors.Errorf("need more than %d args", a)
}
b, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return bitfield.BitField{}, err
}
val = string(b)
}
var dec []byte
switch cctx.String("enc") {
case "base64":
d, err := base64.StdEncoding.DecodeString(val)
if err != nil {
return bitfield.BitField{}, fmt.Errorf("decoding base64 value: %w", err)
}
dec = d
case "hex":
d, err := hex.DecodeString(val)
if err != nil {
return bitfield.BitField{}, fmt.Errorf("decoding hex value: %w", err)
}
dec = d
default:
return bitfield.BitField{}, fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
}
return bitfield.NewFromBytes(dec)
}

286
cmd/lotus-shed/consensus.go Normal file
View 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
},
}

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bufio"
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
@ -8,10 +9,12 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"github.com/gbrlsnchs/jwt/v3" "github.com/gbrlsnchs/jwt/v3"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/api/apistruct" "github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/node/modules"
@ -24,6 +27,102 @@ var jwtCmd = &cli.Command{
having to run the lotus daemon.`, having to run the lotus daemon.`,
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
jwtNewCmd, jwtNewCmd,
jwtTokenCmd,
},
}
var jwtTokenCmd = &cli.Command{
Name: "token",
Usage: "create a token for a given jwt secret",
ArgsUsage: "<name>",
Description: `The jwt tokens have four different levels of permissions that provide some ability
to control access to what methods can be invoked by the holder of the token.
This command only works on jwt secrets that are base16 encoded files, such as those produced by the
sibling 'new' command.
`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "output",
Value: "token",
Usage: "specify a name",
},
&cli.BoolFlag{
Name: "read",
Value: false,
Usage: "add read permissions to the token",
},
&cli.BoolFlag{
Name: "write",
Value: false,
Usage: "add write permissions to the token",
},
&cli.BoolFlag{
Name: "sign",
Value: false,
Usage: "add sign permissions to the token",
},
&cli.BoolFlag{
Name: "admin",
Value: false,
Usage: "add admin permissions to the token",
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("please specify a name")
}
inputFile, err := os.Open(cctx.Args().First())
if err != nil {
return err
}
defer inputFile.Close() //nolint:errcheck
input := bufio.NewReader(inputFile)
encoded, err := ioutil.ReadAll(input)
if err != nil {
return err
}
decoded, err := hex.DecodeString(strings.TrimSpace(string(encoded)))
if err != nil {
return err
}
var keyInfo types.KeyInfo
if err := json.Unmarshal(decoded, &keyInfo); err != nil {
return err
}
perms := []auth.Permission{}
if cctx.Bool("read") {
perms = append(perms, apistruct.PermRead)
}
if cctx.Bool("write") {
perms = append(perms, apistruct.PermWrite)
}
if cctx.Bool("sign") {
perms = append(perms, apistruct.PermSign)
}
if cctx.Bool("admin") {
perms = append(perms, apistruct.PermAdmin)
}
p := modules.JwtPayload{
Allow: perms,
}
token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey))
if err != nil {
return err
}
return ioutil.WriteFile(cctx.String("output"), token, 0600)
}, },
} }

View File

@ -9,16 +9,22 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"strings" "strings"
"text/template" "text/template"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/multiformats/go-base32"
"github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/modules/lp2p" "github.com/filecoin-project/lotus/node/modules/lp2p"
"github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo"
@ -43,6 +49,90 @@ var keyinfoCmd = &cli.Command{
keyinfoNewCmd, keyinfoNewCmd,
keyinfoInfoCmd, keyinfoInfoCmd,
keyinfoImportCmd, keyinfoImportCmd,
keyinfoVerifyCmd,
},
}
var keyinfoVerifyCmd = &cli.Command{
Name: "verify",
Usage: "verify the filename of a keystore object on disk with it's contents",
Description: `Keystore objects are base32 enocded strings, with wallets being dynamically named via
the wallet address. This command can ensure that the naming of these keystore objects are correct`,
Action: func(cctx *cli.Context) error {
filePath := cctx.Args().First()
fileName := path.Base(filePath)
inputFile, err := os.Open(filePath)
if err != nil {
return err
}
defer inputFile.Close() //nolint:errcheck
input := bufio.NewReader(inputFile)
keyContent, err := ioutil.ReadAll(input)
if err != nil {
return err
}
var keyInfo types.KeyInfo
if err := json.Unmarshal(keyContent, &keyInfo); err != nil {
return err
}
switch keyInfo.Type {
case lp2p.KTLibp2pHost:
name, err := base32.RawStdEncoding.DecodeString(fileName)
if err != nil {
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
}
if string(name) != keyInfo.Type {
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
}
case modules.KTJwtHmacSecret:
name, err := base32.RawStdEncoding.DecodeString(fileName)
if err != nil {
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
}
if string(name) != modules.JWTSecretName {
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
}
case wallet.KTSecp256k1, wallet.KTBLS:
keystore := wallet.NewMemKeyStore()
w, err := wallet.NewWallet(keystore)
if err != nil {
return err
}
if _, err := w.Import(&keyInfo); err != nil {
return err
}
list, err := keystore.List()
if err != nil {
return err
}
if len(list) != 1 {
return fmt.Errorf("Unexpected number of keys, expected 1, found %d", len(list))
}
name, err := base32.RawStdEncoding.DecodeString(fileName)
if err != nil {
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
}
if string(name) != list[0] {
return fmt.Errorf("%s of type %s; file is named for %s, but key is actually %s", fileName, keyInfo.Type, string(name), list[0])
}
break
default:
return fmt.Errorf("Unknown keytype %s", keyInfo.Type)
}
return nil
}, },
} }

View File

@ -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"))
}, },
} }

View File

@ -5,9 +5,12 @@ import (
"os" "os"
"text/tabwriter" "text/tabwriter"
"github.com/docker/go-units"
"github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-state-types/abi"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli" lcli "github.com/filecoin-project/lotus/cli"
) )
@ -17,6 +20,8 @@ var retrievalDealsCmd = &cli.Command{
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
retrievalDealSelectionCmd, retrievalDealSelectionCmd,
retrievalDealsListCmd, retrievalDealsListCmd,
retrievalSetAskCmd,
retrievalGetAskCmd,
}, },
} }
@ -154,3 +159,112 @@ var retrievalDealsListCmd = &cli.Command{
return w.Flush() return w.Flush()
}, },
} }
var retrievalSetAskCmd = &cli.Command{
Name: "set-ask",
Usage: "Configure the provider's retrieval ask",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "price",
Usage: "Set the price of the ask for retrievals (FIL/GiB)",
},
&cli.StringFlag{
Name: "unseal-price",
Usage: "Set the price to unseal",
},
&cli.StringFlag{
Name: "payment-interval",
Usage: "Set the payment interval (in bytes) for retrieval",
DefaultText: "1MiB",
},
&cli.StringFlag{
Name: "payment-interval-increase",
Usage: "Set the payment interval increase (in bytes) for retrieval",
DefaultText: "1MiB",
},
},
Action: func(cctx *cli.Context) error {
ctx := lcli.DaemonContext(cctx)
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
ask, err := api.MarketGetRetrievalAsk(ctx)
if err != nil {
return err
}
if cctx.IsSet("price") {
v, err := types.ParseFIL(cctx.String("price"))
if err != nil {
return err
}
ask.PricePerByte = types.BigDiv(types.BigInt(v), types.NewInt(1<<30))
}
if cctx.IsSet("unseal-price") {
v, err := types.ParseFIL(cctx.String("unseal-price"))
if err != nil {
return err
}
ask.UnsealPrice = abi.TokenAmount(v)
}
if cctx.IsSet("payment-interval") {
v, err := units.RAMInBytes(cctx.String("payment-interval"))
if err != nil {
return err
}
ask.PaymentInterval = uint64(v)
}
if cctx.IsSet("payment-interval-increase") {
v, err := units.RAMInBytes(cctx.String("payment-interval-increase"))
if err != nil {
return err
}
ask.PaymentIntervalIncrease = uint64(v)
}
return api.MarketSetRetrievalAsk(ctx, ask)
},
}
var retrievalGetAskCmd = &cli.Command{
Name: "get-ask",
Usage: "Get the provider's current retrieval ask",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
ctx := lcli.DaemonContext(cctx)
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
ask, err := api.MarketGetRetrievalAsk(ctx)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
fmt.Fprintf(w, "Price per Byte\tUnseal Price\tPayment Interval\tPayment Interval Increase\n")
if ask == nil {
fmt.Fprintf(w, "<miner does not have an retrieval ask set>\n")
return w.Flush()
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
types.FIL(ask.PricePerByte),
types.FIL(ask.UnsealPrice),
units.BytesSize(float64(ask.PaymentInterval)),
units.BytesSize(float64(ask.PaymentIntervalIncrease)),
)
return w.Flush()
},
}

View File

@ -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...")

View File

@ -17,7 +17,9 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"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{
@ -136,6 +138,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 {
@ -192,10 +200,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),
@ -206,6 +215,7 @@ var sectorsListCmd = &cli.Command{
st.ToUpgrade, st.ToUpgrade,
) )
} }
}
return w.Flush() return w.Flush()
}, },
@ -420,6 +430,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)))
}, },
} }

View File

@ -371,7 +371,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 {

View File

@ -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...")

View File

@ -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.
@ -64,6 +66,9 @@ const (
// MethodAbortWith is the identifier for the method that panics optionally with // MethodAbortWith is the identifier for the method that panics optionally with
// a passed exit code. // a passed exit code.
MethodAbortWith MethodAbortWith
// MethodInspectRuntime is the identifier for the method that returns the
// current runtime values.
MethodInspectRuntime
) )
// Exports defines the methods this actor exposes publicly. // Exports defines the methods this actor exposes publicly.
@ -77,6 +82,7 @@ func (a Actor) Exports() []interface{} {
MethodSend: a.Send, MethodSend: a.Send,
MethodMutateState: a.MutateState, MethodMutateState: a.MutateState,
MethodAbortWith: a.AbortWith, MethodAbortWith: a.AbortWith,
MethodInspectRuntime: a.InspectRuntime,
} }
} }
@ -119,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")
} }
@ -247,3 +259,28 @@ func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValu
} }
return nil return nil
} }
// InspectRuntimeReturn is the return value for the Actor.InspectRuntime method.
type InspectRuntimeReturn struct {
Caller address.Address
Receiver address.Address
ValueReceived abi.TokenAmount
CurrEpoch abi.ChainEpoch
CurrentBalance abi.TokenAmount
State State
}
// InspectRuntime returns a copy of the serializable values available in the Runtime.
func (a Actor) InspectRuntime(rt runtime.Runtime, _ *abi.EmptyValue) *InspectRuntimeReturn {
rt.ValidateImmediateCallerAcceptAny()
var st State
rt.StateReadonly(&st)
return &InspectRuntimeReturn{
Caller: rt.Caller(),
Receiver: rt.Receiver(),
ValueReceived: rt.ValueReceived(),
CurrEpoch: rt.CurrEpoch(),
CurrentBalance: rt.CurrentBalance(),
State: st,
}
}

View File

@ -4,10 +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/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) {
@ -24,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)
@ -117,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)
@ -151,3 +248,28 @@ func TestAbortWithUncontrolled(t *testing.T) {
}) })
rt.Verify() rt.Verify()
} }
func TestInspectRuntime(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)
rt.StateCreate(&State{})
var a Actor
rt.ExpectValidateCallerAny()
ret := rt.Call(a.InspectRuntime, abi.Empty)
rtr, ok := ret.(*InspectRuntimeReturn)
if !ok {
t.Fatal("invalid return value")
}
if rtr.Caller != caller {
t.Fatal("unexpected runtime caller")
}
if rtr.Receiver != receiver {
t.Fatal("unexpected runtime receiver")
}
rt.Verify()
}

View File

@ -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 {
@ -730,3 +889,145 @@ func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error {
} }
return nil return nil
} }
var lengthBufInspectRuntimeReturn = []byte{134}
func (t *InspectRuntimeReturn) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write(lengthBufInspectRuntimeReturn); err != nil {
return err
}
scratch := make([]byte, 9)
// t.Caller (address.Address) (struct)
if err := t.Caller.MarshalCBOR(w); err != nil {
return err
}
// t.Receiver (address.Address) (struct)
if err := t.Receiver.MarshalCBOR(w); err != nil {
return err
}
// t.ValueReceived (big.Int) (struct)
if err := t.ValueReceived.MarshalCBOR(w); err != nil {
return err
}
// t.CurrEpoch (abi.ChainEpoch) (int64)
if t.CurrEpoch >= 0 {
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.CurrEpoch)); err != nil {
return err
}
} else {
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.CurrEpoch-1)); err != nil {
return err
}
}
// t.CurrentBalance (big.Int) (struct)
if err := t.CurrentBalance.MarshalCBOR(w); err != nil {
return err
}
// t.State (chaos.State) (struct)
if err := t.State.MarshalCBOR(w); err != nil {
return err
}
return nil
}
func (t *InspectRuntimeReturn) UnmarshalCBOR(r io.Reader) error {
*t = InspectRuntimeReturn{}
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 != 6 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Caller (address.Address) (struct)
{
if err := t.Caller.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.Caller: %w", err)
}
}
// t.Receiver (address.Address) (struct)
{
if err := t.Receiver.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.Receiver: %w", err)
}
}
// t.ValueReceived (big.Int) (struct)
{
if err := t.ValueReceived.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.ValueReceived: %w", err)
}
}
// t.CurrEpoch (abi.ChainEpoch) (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.CurrEpoch = abi.ChainEpoch(extraI)
}
// t.CurrentBalance (big.Int) (struct)
{
if err := t.CurrentBalance.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.CurrentBalance: %w", err)
}
}
// t.State (chaos.State) (struct)
{
if err := t.State.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.State: %w", err)
}
}
return nil
}

View File

@ -7,14 +7,16 @@ 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{},
chaos.SendReturn{}, chaos.SendReturn{},
chaos.MutateStateArgs{}, chaos.MutateStateArgs{},
chaos.AbortWithArgs{}, chaos.AbortWithArgs{},
chaos.InspectRuntimeReturn{},
); err != nil { ); err != nil {
panic(err) panic(err)
} }

View File

@ -148,6 +148,7 @@
* [StateMinerRecoveries](#StateMinerRecoveries) * [StateMinerRecoveries](#StateMinerRecoveries)
* [StateMinerSectorCount](#StateMinerSectorCount) * [StateMinerSectorCount](#StateMinerSectorCount)
* [StateMinerSectors](#StateMinerSectors) * [StateMinerSectors](#StateMinerSectors)
* [StateMsgGasCost](#StateMsgGasCost)
* [StateNetworkName](#StateNetworkName) * [StateNetworkName](#StateNetworkName)
* [StateReadState](#StateReadState) * [StateReadState](#StateReadState)
* [StateReplay](#StateReplay) * [StateReplay](#StateReplay)
@ -211,7 +212,7 @@ Response:
```json ```json
{ {
"Version": "string value", "Version": "string value",
"APIVersion": 3584, "APIVersion": 3840,
"BlockDelay": 42 "BlockDelay": 42
} }
``` ```
@ -3737,6 +3738,45 @@ Inputs:
Response: `null` Response: `null`
### StateMsgGasCost
StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
Perms: read
Inputs:
```json
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
]
]
```
Response:
```json
{
"Message": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"GasUsed": "0",
"BaseFeeBurn": "0",
"OverEstimationBurn": "0",
"MinerPenalty": "0",
"MinerTip": "0",
"Refund": "0",
"TotalCost": "0"
}
```
### StateNetworkName ### StateNetworkName
StateNetworkName returns the name of the network the node is synced to StateNetworkName returns the name of the network the node is synced to

1
extern/oni vendored Submodule

@ -0,0 +1 @@
Subproject commit 8b7e7d438c4cc38a0d2d671876d4590ad20655b3

View File

@ -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 = ""

View File

@ -67,6 +67,8 @@ func (m *Sealing) tryUpgradeSector(ctx context.Context, params *miner.SectorPreC
params.ReplaceSectorDeadline = loc.Deadline params.ReplaceSectorDeadline = loc.Deadline
params.ReplaceSectorPartition = loc.Partition params.ReplaceSectorPartition = loc.Partition
log.Infof("replacing sector %d with %d", *replace, params.SectorNumber)
ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil) ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil)
if err != nil { if err != nil {
log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err) log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err)

2
extern/test-vectors vendored

@ -1 +1 @@
Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12 Subproject commit 6bea015edddde116001a4251dce3c4a9966c25d9

4
go.mod
View File

@ -25,9 +25,9 @@ require (
github.com/filecoin-project/go-bitfield v0.2.0 github.com/filecoin-project/go-bitfield v0.2.0
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-data-transfer v0.6.4
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f
github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c github.com/filecoin-project/go-fil-markets v0.6.1
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52
github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-multistore v0.0.3
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20

8
go.sum
View File

@ -222,12 +222,12 @@ github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:a
github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg=
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus=
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ=
github.com/filecoin-project/go-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGRR+LwqM8jmlZqgWuUfY= github.com/filecoin-project/go-data-transfer v0.6.4 h1:Q08ABa+cOTOLoAyHeA94fPLcwu53p6eeAaxMxQb0m0A=
github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM= github.com/filecoin-project/go-data-transfer v0.6.4/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM=
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s=
github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c h1:YGoyYmELQ0LHwDj/WcOvY3oYt+3iM0wdrAhqJQUAIy4= github.com/filecoin-project/go-fil-markets v0.6.1 h1:qCFLcVkUCbxwEfH/6EcqTuQvibXt/TXZr+vh8tWv/BQ=
github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c/go.mod h1:PLr9svZxsnHkae1Ky7+66g7fP9AlneVxIVu+oSMq56A= github.com/filecoin-project/go-fil-markets v0.6.1/go.mod h1:dBJl59dAyl8+cGVb/ONPlEQW4+YzhjI3d6bxLfHVpX0=
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0=

View File

@ -139,6 +139,7 @@ func (m *Miner) niceSleep(d time.Duration) bool {
case <-build.Clock.After(d): case <-build.Clock.After(d):
return true return true
case <-m.stop: case <-m.stop:
log.Infow("received interrupt while trying to sleep in mining cycle")
return false return false
} }
} }
@ -169,7 +170,9 @@ func (m *Miner) mine(ctx context.Context) {
prebase, err := m.GetBestMiningCandidate(ctx) prebase, err := m.GetBestMiningCandidate(ctx)
if err != nil { if err != nil {
log.Errorf("failed to get best mining candidate: %s", err) log.Errorf("failed to get best mining candidate: %s", err)
m.niceSleep(time.Second * 5) if !m.niceSleep(time.Second * 5) {
break
}
continue continue
} }
@ -199,7 +202,9 @@ func (m *Miner) mine(ctx context.Context) {
_, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1) _, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1)
if err != nil { if err != nil {
log.Errorf("failed getting beacon entry: %s", err) log.Errorf("failed getting beacon entry: %s", err)
m.niceSleep(time.Second) if !m.niceSleep(time.Second) {
break
}
continue continue
} }
@ -208,7 +213,9 @@ func (m *Miner) mine(ctx context.Context) {
if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds {
log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds)
m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) if !m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) {
break
}
continue continue
} }
@ -217,7 +224,9 @@ func (m *Miner) mine(ctx context.Context) {
b, err := m.mineOne(ctx, base) b, err := m.mineOne(ctx, base)
if err != nil { if err != nil {
log.Errorf("mining block failed: %+v", err) log.Errorf("mining block failed: %+v", err)
m.niceSleep(time.Second) if !m.niceSleep(time.Second) {
break
}
onDone(false, 0, err) onDone(false, 0, err)
continue continue
} }

View File

@ -384,7 +384,7 @@ func StorageMiner(out *api.StorageMiner) Option {
func(s *Settings) error { func(s *Settings) error {
resAPI := &impl.StorageMinerAPI{} resAPI := &impl.StorageMinerAPI{}
s.invokes[ExtractApiKey] = fx.Extract(resAPI) s.invokes[ExtractApiKey] = fx.Populate(resAPI)
*out = resAPI *out = resAPI
return nil return nil
}, },
@ -511,7 +511,7 @@ func FullAPI(out *api.FullNode) Option {
}, },
func(s *Settings) error { func(s *Settings) error {
resAPI := &impl.FullNodeAPI{} resAPI := &impl.FullNodeAPI{}
s.invokes[ExtractApiKey] = fx.Extract(resAPI) s.invokes[ExtractApiKey] = fx.Populate(resAPI)
*out = resAPI *out = resAPI
return nil return nil
}, },

View File

@ -1225,3 +1225,52 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK
return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree) return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree)
} }
func (a *StateAPI) StateMsgGasCost(ctx context.Context, inputMsg cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
var msg cid.Cid
var ts *types.TipSet
var err error
if tsk != types.EmptyTSK {
msg = inputMsg
ts, err = a.Chain.LoadTipSet(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
} else {
mlkp, err := a.StateSearchMsg(ctx, inputMsg)
if err != nil {
return nil, xerrors.Errorf("searching for msg %s: %w", inputMsg, err)
}
if mlkp == nil {
return nil, xerrors.Errorf("didn't find msg %s", inputMsg)
}
executionTs, err := a.Chain.GetTipSetFromKey(mlkp.TipSet)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", mlkp.TipSet, err)
}
ts, err = a.Chain.LoadTipSet(executionTs.Parents())
if err != nil {
return nil, xerrors.Errorf("loading parent tipset %s: %w", mlkp.TipSet, err)
}
msg = mlkp.Message
}
m, r, err := a.StateManager.Replay(ctx, ts, msg)
if err != nil {
return nil, err
}
return &api.MsgGasCost{
Message: msg,
GasUsed: big.NewInt(r.GasUsed),
BaseFeeBurn: r.GasCosts.BaseFeeBurn,
OverEstimationBurn: r.GasCosts.OverEstimationBurn,
MinerPenalty: r.GasCosts.MinerPenalty,
MinerTip: r.GasCosts.MinerTip,
Refund: r.GasCosts.Refund,
TotalCost: big.Sub(m.RequiredFunds(), r.GasCosts.Refund),
}, nil
}

View File

@ -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

View File

@ -60,7 +60,7 @@ func AddressFor(ctx context.Context, a addrSelectApi, mi api.MinerInfo, use Addr
return addr, nil return addr, nil
} }
log.Warnw("control address didn't have enough funds for PoSt message", "address", addr, "required", types.FIL(minFunds), "balance", types.FIL(b)) log.Warnw("control address didn't have enough funds for window post message", "address", addr, "required", types.FIL(minFunds), "balance", types.FIL(b))
} }
// Try to use the owner account if we can, fallback to worker if we can't // Try to use the owner account if we can, fallback to worker if we can't

View File

@ -78,7 +78,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info,
posts, err := s.runPost(ctx, *deadline, ts) posts, err := s.runPost(ctx, *deadline, ts)
if err != nil { if err != nil {
log.Errorf("runPost failed: %+v", err) log.Errorf("run window post failed: %+v", err)
s.failPost(err, deadline) s.failPost(err, deadline)
return return
} }
@ -92,7 +92,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info,
post := &posts[i] post := &posts[i]
sm, err := s.submitPost(ctx, post) sm, err := s.submitPost(ctx, post)
if err != nil { if err != nil {
log.Errorf("submitPost failed: %+v", err) log.Errorf("submit window post failed: %+v", err)
s.failPost(err, deadline) s.failPost(err, deadline)
} else { } else {
recordProofsEvent(post.Partitions, sm.Cid()) recordProofsEvent(post.Partitions, sm.Cid())
@ -397,7 +397,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
rand, err := s.api.ChainGetRandomnessFromBeacon(ctx, ts.Key(), crypto.DomainSeparationTag_WindowedPoStChallengeSeed, di.Challenge, buf.Bytes()) rand, err := s.api.ChainGetRandomnessFromBeacon(ctx, ts.Key(), crypto.DomainSeparationTag_WindowedPoStChallengeSeed, di.Challenge, buf.Bytes())
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get chain randomness for windowPost (ts=%d; deadline=%d): %w", ts.Height(), di, err) return nil, xerrors.Errorf("failed to get chain randomness for window post (ts=%d; deadline=%d): %w", ts.Height(), di, err)
} }
// Get the partitions for the given deadline // Get the partitions for the given deadline
@ -431,7 +431,9 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
postSkipped := bitfield.New() postSkipped := bitfield.New()
var postOut []proof.PoStProof var postOut []proof.PoStProof
somethingToProve := true somethingToProve := true
for retries := 0; retries < 5; retries++ { for retries := 0; retries < 5; retries++ {
var partitions []miner.PoStPartition
var sinfos []proof.SectorInfo var sinfos []proof.SectorInfo
for partIdx, partition := range batch { for partIdx, partition := range batch {
// TODO: Can do this in parallel // TODO: Can do this in parallel
@ -477,7 +479,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
} }
sinfos = append(sinfos, ssi...) sinfos = append(sinfos, ssi...)
params.Partitions = append(params.Partitions, miner.PoStPartition{ partitions = append(partitions, miner.PoStPartition{
Index: uint64(batchPartitionStartIdx + partIdx), Index: uint64(batchPartitionStartIdx + partIdx),
Skipped: skipped, Skipped: skipped,
}) })
@ -490,7 +492,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
} }
// Generate proof // Generate proof
log.Infow("running windowPost", log.Infow("running window post",
"chain-random", rand, "chain-random", rand,
"deadline", di, "deadline", di,
"height", ts.Height(), "height", ts.Height(),
@ -507,20 +509,22 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand))
elapsed := time.Since(tsStart) elapsed := time.Since(tsStart)
log.Infow("computing window PoSt", "batch", batchIdx, "elapsed", elapsed) log.Infow("computing window post", "batch", batchIdx, "elapsed", elapsed)
if err == nil { if err == nil {
// Proof generation successful, stop retrying // Proof generation successful, stop retrying
params.Partitions = append(params.Partitions, partitions...)
break break
} }
// Proof generation failed, so retry // Proof generation failed, so retry
if len(ps) == 0 { if len(ps) == 0 {
return nil, xerrors.Errorf("running post failed: %w", err) return nil, xerrors.Errorf("running window post failed: %w", err)
} }
log.Warnw("generate window PoSt skipped sectors", "sectors", ps, "error", err, "try", retries) log.Warnw("generate window post skipped sectors", "sectors", ps, "error", err, "try", retries)
skipCount += uint64(len(ps)) skipCount += uint64(len(ps))
for _, sector := range ps { for _, sector := range ps {
@ -547,7 +551,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
commEpoch := di.Open commEpoch := di.Open
commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil) commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get chain randomness for windowPost (ts=%d; deadline=%d): %w", ts.Height(), commEpoch, err) return nil, xerrors.Errorf("failed to get chain randomness for window post (ts=%d; deadline=%d): %w", ts.Height(), commEpoch, err)
} }
for i := range posts { for i := range posts {
@ -644,7 +648,7 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
enc, aerr := actors.SerializeParams(proof) enc, aerr := actors.SerializeParams(proof)
if aerr != nil { if aerr != nil {
return nil, xerrors.Errorf("could not serialize submit post parameters: %w", aerr) return nil, xerrors.Errorf("could not serialize submit window post parameters: %w", aerr)
} }
msg := &types.Message{ msg := &types.Message{
@ -705,7 +709,7 @@ func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message,
pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds) pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds)
if err != nil { if err != nil {
log.Errorw("error selecting address for post", "error", err) log.Errorw("error selecting address for window post", "error", err)
msg.From = s.worker msg.From = s.worker
return return
} }

View File

@ -110,7 +110,7 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) {
select { select {
case changes, ok := <-notifs: case changes, ok := <-notifs:
if !ok { if !ok {
log.Warn("WindowPoStScheduler notifs channel closed") log.Warn("window post scheduler notifs channel closed")
notifs = nil notifs = nil
continue continue
} }
@ -151,10 +151,10 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) {
} }
if err := s.revert(ctx, lowest); err != nil { if err := s.revert(ctx, lowest); err != nil {
log.Error("handling head reverts in windowPost sched: %+v", err) log.Error("handling head reverts in window post sched: %+v", err)
} }
if err := s.update(ctx, highest); err != nil { if err := s.update(ctx, highest); err != nil {
log.Error("handling head updates in windowPost sched: %+v", err) log.Error("handling head updates in window post sched: %+v", err)
} }
span.End() span.End()
@ -184,7 +184,7 @@ func (s *WindowPoStScheduler) revert(ctx context.Context, newLowest *types.TipSe
func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) error { func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) error {
if new == nil { if new == nil {
return xerrors.Errorf("no new tipset in WindowPoStScheduler.update") return xerrors.Errorf("no new tipset in window post sched update")
} }
di, err := s.api.StateMinerProvingDeadline(ctx, s.actor, new.Key()) di, err := s.api.StateMinerProvingDeadline(ctx, s.actor, new.Key())
@ -206,7 +206,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err
// (Need to get correct deadline above, which is tricky) // (Need to get correct deadline above, which is tricky)
if di.Open+StartConfidence >= new.Height() { if di.Open+StartConfidence >= new.Height() {
log.Info("not starting windowPost yet, waiting for startconfidence", di.Open, di.Open+StartConfidence, new.Height()) log.Info("not starting window post yet, waiting for startconfidence", di.Open, di.Open+StartConfidence, new.Height())
return nil return nil
} }
@ -216,7 +216,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err
s.activeEPS = 0 s.activeEPS = 0
} }
s.failLk.Unlock()*/ s.failLk.Unlock()*/
log.Infof("at %d, doPost for P %d, dd %d", new.Height(), di.PeriodStart, di.Index) log.Infof("at %d, do window post for P %d, dd %d", new.Height(), di.PeriodStart, di.Index)
s.doPost(ctx, di, new) s.doPost(ctx, di, new)
@ -238,7 +238,7 @@ func (s *WindowPoStScheduler) abortActivePoSt() {
} }
}) })
log.Warnf("Aborting Window PoSt (Deadline: %+v)", s.activeDeadline) log.Warnf("Aborting window post (Deadline: %+v)", s.activeDeadline)
} }
s.activeDeadline = nil s.activeDeadline = nil

View File

@ -189,7 +189,7 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti
pl.AddPoint(p) pl.AddPoint(p)
} }
{ {
blks := len(cids) blks := int64(len(cids))
p = NewPoint("chain.gas_fill_ratio", float64(totalGasLimit)/float64(blks*build.BlockGasTarget)) p = NewPoint("chain.gas_fill_ratio", float64(totalGasLimit)/float64(blks*build.BlockGasTarget))
pl.AddPoint(p) pl.AddPoint(p)
p = NewPoint("chain.gas_capacity_ratio", float64(totalUniqGasLimit)/float64(blks*build.BlockGasTarget)) p = NewPoint("chain.gas_capacity_ratio", float64(totalUniqGasLimit)/float64(blks*build.BlockGasTarget))