Merge remote-tracking branch 'origin/master' into feat/async-restartable-workers
This commit is contained in:
commit
aa5bd7bc17
@ -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
1
.gitignore
vendored
@ -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
3
.gitmodules
vendored
@ -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
|
||||||
|
24
CHANGELOG.md
24
CHANGELOG.md
@ -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:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
)
|
)
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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..): ")
|
||||||
|
55
cli/state.go
55
cli/state.go
@ -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",
|
||||||
|
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!")
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
|
@ -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
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
|
||||||
|
},
|
||||||
|
}
|
@ -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)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -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...")
|
||||||
|
@ -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)))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
1
extern/oni
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 8b7e7d438c4cc38a0d2d671876d4590ad20655b3
|
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/storage-sealing/upgrade_queue.go
vendored
2
extern/storage-sealing/upgrade_queue.go
vendored
@ -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
2
extern/test-vectors
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12
|
Subproject commit 6bea015edddde116001a4251dce3c4a9966c25d9
|
4
go.mod
4
go.mod
@ -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
8
go.sum
@ -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=
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user