Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4121063ca4 | ||
|
|
aa081dbc6d | ||
|
|
984eee8cd6 | ||
|
|
26bbd9fb9d | ||
|
|
57c1eac37a | ||
|
|
8419dda84b | ||
|
|
dcc5643473 | ||
|
|
1a101e53a6 | ||
|
|
a894c1e8e6 | ||
|
|
b85b50afbc | ||
|
|
97064f1d15 | ||
|
|
f56602c588 | ||
|
|
c66ebc50c1 | ||
|
|
2aef7f7c07 | ||
|
|
665d23cb8e | ||
|
|
3b00c6838a | ||
|
|
a6b7791d32 | ||
|
|
34d31d8124 | ||
|
|
6656e5a6c8 | ||
|
|
487765548e | ||
|
|
ecd115c002 | ||
|
|
5a8ee0dd2a | ||
|
|
4fbb322fa2 | ||
|
|
56f223bfc3 | ||
|
|
0ff5a71114 | ||
|
|
b0677ab38e | ||
|
|
f4f80b25d1 | ||
|
|
3f67c4524e | ||
|
|
b4115021c5 | ||
|
|
b78ffd18c6 | ||
|
|
c9a8f3b8a0 | ||
|
|
d870c74a5e | ||
|
|
3d61a37fcf | ||
|
|
0c41522ebf | ||
|
|
362fc180ec | ||
|
|
2db7b8c998 | ||
|
|
e04331b07c | ||
|
|
808051d34e | ||
|
|
e2cf0c4d4c | ||
|
|
5c69249ba3 | ||
|
|
fa9be9a627 | ||
|
|
937ff4e9ae | ||
|
|
952f2c2f1e | ||
|
|
ed4caac9bf | ||
|
|
0c1c19c6ef | ||
|
|
24756ac056 | ||
|
|
d4a7732d0a | ||
|
|
ae326ce65d | ||
|
|
531b7bf92d | ||
|
|
84fa22110f | ||
|
|
e22aa74865 | ||
|
|
285fc69f6a | ||
|
|
72216fe917 | ||
|
|
692027f625 | ||
|
|
801e01bca0 | ||
|
|
6665a9ca69 | ||
|
|
1c02a417db | ||
|
|
9ec26e776d | ||
|
|
cf82483420 | ||
|
|
db998e9c0f | ||
|
|
f0f15f899c | ||
|
|
7dc091052a | ||
|
|
17e44af542 | ||
|
|
ac8ef29d35 | ||
|
|
48e47ddc23 | ||
|
|
6acd3d6028 | ||
|
|
7fd5c81674 | ||
|
|
f9ea3935ff | ||
|
|
9804310cc8 | ||
|
|
07e574db44 | ||
|
|
dd841f32db | ||
|
|
665f93bbb7 | ||
|
|
32eeb96ce7 | ||
|
|
172bfacae0 | ||
|
|
0a5494dd79 | ||
|
|
044202b37f | ||
|
|
d68ec37942 | ||
|
|
0edcae9e04 | ||
|
|
d1850ea27d | ||
|
|
60a031a713 | ||
|
|
8a05fe86d6 | ||
|
|
8a21198f56 | ||
|
|
b212368a70 | ||
|
|
954ff32503 | ||
|
|
7c13fa95d1 | ||
|
|
09e9d6d778 | ||
|
|
86607452d7 | ||
|
|
05aa5f2d38 | ||
|
|
6d29d75724 | ||
|
|
3a34856dfe | ||
|
|
973738d30f | ||
|
|
747b34c2c8 | ||
|
|
dcae513487 | ||
|
|
18c025f10e | ||
|
|
e45a7749b0 | ||
|
|
b7ea145f38 | ||
|
|
6c61ff0e9e | ||
|
|
45a5eaf913 | ||
|
|
3401cb349b | ||
|
|
8b9a3ea6c3 | ||
|
|
d5aef296ea | ||
|
|
aa83a4c1f5 | ||
|
|
b83463ca76 | ||
|
|
c1ca24e8bc | ||
|
|
b78fe0b898 | ||
|
|
bf1036c78f | ||
|
|
2e3ff9e401 | ||
|
|
eabdf74946 | ||
|
|
cf9820137c | ||
|
|
c017d0fbaf | ||
|
|
16f7d5801b | ||
|
|
62b2963781 | ||
|
|
cd9858420f | ||
|
|
4410da98be | ||
|
|
b89aa02d77 | ||
|
|
3dfb3e641b | ||
|
|
a3f228d05a | ||
|
|
eaf9ebc2ca | ||
|
|
55e4183825 | ||
|
|
aeb3437a9f | ||
|
|
6e7de3c8d9 | ||
|
|
d0175392c0 | ||
|
|
c4b3970c70 | ||
|
|
72eb17d314 | ||
|
|
0efe5ee7d5 | ||
|
|
0e3dd3cb3b | ||
|
|
56b237e7b8 | ||
|
|
2865a0367b | ||
|
|
df5750a21c | ||
|
|
e996a5246b | ||
|
|
bbac86f745 | ||
|
|
22556fb24c | ||
|
|
2374cb1bc5 | ||
|
|
c7b0241a48 | ||
|
|
dc85a276cd | ||
|
|
c94ff3430c | ||
|
|
a214069586 | ||
|
|
d4b185be5e | ||
|
|
5e7737f55d | ||
|
|
7a6ceebb34 | ||
|
|
35a8f7ebca | ||
|
|
0a4c473a7c | ||
|
|
1ec534d607 | ||
|
|
905168e72e | ||
|
|
d46f684bb8 | ||
|
|
97ff90f8fa | ||
|
|
4554c4bda9 | ||
|
|
3206f92063 | ||
|
|
fd04a19544 | ||
|
|
f046af337a | ||
|
|
ac152abc75 | ||
|
|
0b6a182a44 | ||
|
|
cb8e105a94 | ||
|
|
efdfd3ee3e | ||
|
|
4e1ef09751 | ||
|
|
cc859d3948 | ||
|
|
200b0f72cc | ||
|
|
8f19fff1ec | ||
|
|
b534ab9d3c | ||
|
|
2ea5abdfb5 | ||
|
|
d53c6f2599 | ||
|
|
5e2c28d7e9 | ||
|
|
bca516b028 | ||
|
|
92598237c3 | ||
|
|
5074ce5a38 | ||
|
|
b8475114ba | ||
|
|
443473f833 | ||
|
|
4e82cf369c | ||
|
|
d547c2588c | ||
|
|
cb8e209f78 | ||
|
|
3bd9d55a15 | ||
|
|
d6e6eedd58 | ||
|
|
7459ec6bba | ||
|
|
226786c1da | ||
|
|
4d2d8b2d11 | ||
|
|
becbff0b13 | ||
|
|
4bcf01938c | ||
|
|
bef7d64e66 | ||
|
|
695f6cfe45 |
+22
-1
@@ -254,6 +254,25 @@ jobs:
|
||||
path: /tmp/test-reports
|
||||
- store_artifacts:
|
||||
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:
|
||||
description: build darwin lotus binary
|
||||
@@ -400,7 +419,8 @@ workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- lint-all
|
||||
- lint-all:
|
||||
concurrency: "16" # expend all docker 2xlarge CPUs.
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- cbor-gen-check
|
||||
@@ -427,6 +447,7 @@ workflows:
|
||||
test-suite-name: conformance-bleeding-edge
|
||||
packages: "./conformance"
|
||||
vectors-branch: master
|
||||
- build-lotus-soup
|
||||
- build-debug
|
||||
- build-all:
|
||||
requires:
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
/lotus-fountain
|
||||
/lotus-stats
|
||||
/lotus-bench
|
||||
/lotus-gateway
|
||||
/lotus-pcr
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
|
||||
@@ -8,3 +8,9 @@
|
||||
[submodule "extern/test-vectors"]
|
||||
path = extern/test-vectors
|
||||
url = https://github.com/filecoin-project/test-vectors.git
|
||||
[submodule "extern/fil-blst"]
|
||||
path = extern/fil-blst
|
||||
url = https://github.com/filecoin-project/fil-blst.git
|
||||
[submodule "extern/oni"]
|
||||
path = extern/oni
|
||||
url = https://github.com/filecoin-project/oni
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# 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
|
||||
|
||||
This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are:
|
||||
|
||||
@@ -92,6 +92,12 @@ lotus-shed: $(BUILD_DEPS)
|
||||
.PHONY: lotus-shed
|
||||
BINS+=lotus-shed
|
||||
|
||||
lotus-gateway: $(BUILD_DEPS)
|
||||
rm -f lotus-gateway
|
||||
go build $(GOFLAGS) -o lotus-gateway ./cmd/lotus-gateway
|
||||
.PHONY: lotus-gateway
|
||||
BINS+=lotus-gateway
|
||||
|
||||
build: lotus lotus-miner lotus-worker
|
||||
@[[ $$(type -P "lotus") ]] && echo "Caution: you have \
|
||||
an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true
|
||||
|
||||
+17
-3
@@ -118,7 +118,8 @@ type FullNode interface {
|
||||
// The exported chain data includes the header chain from the given tipset
|
||||
// back to genesis, the entire genesis state, and the most recent 'nroots'
|
||||
// state trees.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error)
|
||||
// If oldmsgskip is set, messages from before the requested roots are also not included.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// MethodGroup: Beacon
|
||||
// The Beacon method group contains methods for interacting with the random beacon (DRAND)
|
||||
@@ -353,6 +354,8 @@ type FullNode interface {
|
||||
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(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
|
||||
// message arrives on chain, and gets to the indicated confidence depth.
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
@@ -451,8 +454,8 @@ type FullNode interface {
|
||||
|
||||
PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error)
|
||||
PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error)
|
||||
PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFunds(ctx context.Context, ch address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychAvailableFundsByFromTo(ctx context.Context, from, to address.Address) (*ChannelAvailableFunds, error)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
||||
PaychSettle(context.Context, address.Address) (cid.Cid, error)
|
||||
@@ -530,6 +533,17 @@ type MsgLookup struct {
|
||||
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 {
|
||||
BlsMessages []*types.Message
|
||||
SecpkMessages []*types.SignedMessage
|
||||
|
||||
+14
-9
@@ -95,7 +95,7 @@ type FullNodeStruct struct {
|
||||
ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
ChainExport func(context.Context, abi.ChainEpoch, bool, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
||||
|
||||
@@ -183,6 +183,7 @@ type FullNodeStruct struct {
|
||||
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"`
|
||||
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"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -219,8 +220,8 @@ type FullNodeStruct struct {
|
||||
|
||||
PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"`
|
||||
PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"`
|
||||
PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFunds func(context.Context, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychAvailableFundsByFromTo func(context.Context, address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"`
|
||||
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
|
||||
PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"`
|
||||
PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -692,8 +693,8 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey,
|
||||
return c.Internal.ChainGetPath(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, nroots, tsk)
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, iom bool, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, nroots, iom, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) {
|
||||
@@ -816,6 +817,10 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
|
||||
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) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
@@ -944,12 +949,12 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid
|
||||
return c.Internal.PaychGetWaitReady(ctx, sentinel)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFunds(ch)
|
||||
func (c *FullNodeStruct) PaychAvailableFunds(ctx context.Context, ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFunds(ctx, ch)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFundsByFromTo(from, to)
|
||||
func (c *FullNodeStruct) PaychAvailableFundsByFromTo(ctx context.Context, from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return c.Internal.PaychAvailableFundsByFromTo(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) {
|
||||
|
||||
@@ -192,7 +192,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
|
||||
// Drop the partition
|
||||
err = parts[0].Sectors.ForEach(func(sid uint64) error {
|
||||
return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{
|
||||
return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sid),
|
||||
}, true)
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ func init() {
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(30)
|
||||
const BlockDelaySecs = uint64(4)
|
||||
|
||||
const PropagationDelaySecs = uint64(1)
|
||||
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.7.0"
|
||||
const BuildVersion = "0.7.1"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -83,7 +83,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 14, 0)
|
||||
FullAPIVersion = newVer(0, 15, 0)
|
||||
MinerAPIVersion = newVer(0, 14, 0)
|
||||
WorkerAPIVersion = newVer(0, 14, 0)
|
||||
)
|
||||
|
||||
@@ -27,7 +27,6 @@ type heightEvents struct {
|
||||
}
|
||||
|
||||
func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
|
||||
ctx, span := trace.StartSpan(e.ctx, "events.HeightHeadChange")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("endHeight", int64(app[0].Height())))
|
||||
@@ -145,12 +144,11 @@ func (e *heightEvents) headChangeAt(rev, app []*types.TipSet) error {
|
||||
}
|
||||
|
||||
// ChainAt invokes the specified `HeightHandler` when the chain reaches the
|
||||
// specified height+confidence threshold. If the chain is rolled-back under the
|
||||
// specified height, `RevertHandler` will be called.
|
||||
// specified height+confidence threshold. If the chain is rolled-back under the
|
||||
// specified height, `RevertHandler` will be called.
|
||||
//
|
||||
// ts passed to handlers is the tipset at the specified, or above, if lower tipsets were null
|
||||
func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence int, h abi.ChainEpoch) error {
|
||||
|
||||
e.lk.Lock() // Tricky locking, check your locks if you modify this function!
|
||||
|
||||
best, err := e.tsc.best()
|
||||
|
||||
@@ -3,6 +3,7 @@ package state
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
@@ -69,7 +70,7 @@ func DiffAdtArray(preArr, curArr *adt.Array, out AdtArrayDiff) error {
|
||||
// Modify should be called when a value is modified in the map
|
||||
// Remove should be called when a value is removed from the map
|
||||
type AdtMapDiff interface {
|
||||
AsKey(key string) (adt.Keyer, error)
|
||||
AsKey(key string) (abi.Keyer, error)
|
||||
Add(key string, val *typegen.Deferred) error
|
||||
Modify(key string, from, to *typegen.Deferred) error
|
||||
Remove(key string, val *typegen.Deferred) error
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
typegen "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
@@ -78,21 +79,21 @@ func TestDiffAdtMap(t *testing.T) {
|
||||
mapA := adt.MakeEmptyMap(ctxstoreA)
|
||||
mapB := adt.MakeEmptyMap(ctxstoreB)
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(0), runtime.CBORBytes([]byte{0}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(1), runtime.CBORBytes([]byte{1})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(1), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(1), runtime.CBORBytes([]byte{1})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(2), runtime.CBORBytes([]byte{1}))) // delete
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(2), runtime.CBORBytes([]byte{1}))) // delete
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(3), runtime.CBORBytes([]byte{0})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(3), runtime.CBORBytes([]byte{0}))) // noop
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(3), runtime.CBORBytes([]byte{0})))
|
||||
|
||||
require.NoError(t, mapA.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(4), runtime.CBORBytes([]byte{6})))
|
||||
require.NoError(t, mapA.Put(abi.UIntKey(4), runtime.CBORBytes([]byte{0}))) // modify
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(4), runtime.CBORBytes([]byte{6})))
|
||||
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(5), runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, mapB.Put(adt.UIntKey(6), runtime.CBORBytes{9})) // add
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(5), runtime.CBORBytes{8})) // add
|
||||
require.NoError(t, mapB.Put(abi.UIntKey(6), runtime.CBORBytes{9})) // add
|
||||
|
||||
changes := new(TestDiffMap)
|
||||
|
||||
@@ -134,12 +135,12 @@ type TestDiffMap struct {
|
||||
|
||||
var _ AdtMapDiff = &TestDiffMap{}
|
||||
|
||||
func (t *TestDiffMap) AsKey(key string) (adt.Keyer, error) {
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
func (t *TestDiffMap) AsKey(key string) (abi.Keyer, error) {
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.UIntKey(k), nil
|
||||
return abi.UIntKey(k), nil
|
||||
}
|
||||
|
||||
func (t *TestDiffMap) Add(key string, val *typegen.Deferred) error {
|
||||
@@ -148,7 +149,7 @@ func (t *TestDiffMap) Add(key string, val *typegen.Deferred) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -172,7 +173,7 @@ func (t *TestDiffMap) Modify(key string, from, to *typegen.Deferred) error {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -198,7 +199,7 @@ func (t *TestDiffMap) Remove(key string, val *typegen.Deferred) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, err := adt.ParseUIntKey(key)
|
||||
k, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -537,8 +537,8 @@ type MinerPreCommitChanges struct {
|
||||
Removed []miner.SectorPreCommitOnChainInfo
|
||||
}
|
||||
|
||||
func (m *MinerPreCommitChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
sector, err := adt.ParseUIntKey(key)
|
||||
func (m *MinerPreCommitChanges) AsKey(key string) (abi.Keyer, error) {
|
||||
sector, err := abi.ParseUIntKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -662,12 +662,12 @@ type AddressChange struct {
|
||||
|
||||
type DiffInitActorStateFunc func(ctx context.Context, oldState *init_.State, newState *init_.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (adt.Keyer, error) {
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (abi.Keyer, error) {
|
||||
addr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adt.AddrKey(addr), nil
|
||||
return abi.AddrKey(addr), nil
|
||||
}
|
||||
|
||||
func (i *InitActorAddressChanges) Add(key string, val *typegen.Deferred) error {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
@@ -50,7 +51,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
@@ -77,7 +78,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
@@ -95,7 +96,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
|
||||
}
|
||||
value := cbg.CborInt(80)
|
||||
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(ainfo.Owner), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
} else if rootVerifier.Type == genesis.TMultisig {
|
||||
@@ -110,7 +111,7 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
fmt.Printf("init set %s t0%d\n", e, counter)
|
||||
|
||||
value := cbg.CborInt(counter)
|
||||
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
|
||||
if err := amap.Put(abi.AddrKey(e), &value); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
counter = counter + 1
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
@@ -50,6 +52,7 @@ var RepublishInterval = time.Duration(10*build.BlockDelaySecs+build.PropagationD
|
||||
|
||||
var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee))
|
||||
var baseFeeLowerBoundFactor = types.NewInt(10)
|
||||
var baseFeeLowerBoundFactorConservative = types.NewInt(100)
|
||||
|
||||
var MaxActorPendingMessages = 1000
|
||||
|
||||
@@ -82,9 +85,25 @@ const (
|
||||
localUpdates = "update"
|
||||
)
|
||||
|
||||
// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go
|
||||
// away in the next fork.
|
||||
var strictBaseFeeValidation = false
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeMpoolAdd = iota
|
||||
evtTypeMpoolRemove
|
||||
evtTypeMpoolRepub
|
||||
)
|
||||
|
||||
// MessagePoolEvt is the journal entry for message pool events.
|
||||
type MessagePoolEvt struct {
|
||||
Action string
|
||||
Messages []MessagePoolEvtMessage
|
||||
Error error `json:",omitempty"`
|
||||
}
|
||||
|
||||
type MessagePoolEvtMessage struct {
|
||||
types.Message
|
||||
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
func init() {
|
||||
// if the republish interval is too short compared to the pubsub timecache, adjust it
|
||||
@@ -139,6 +158,8 @@ type MessagePool struct {
|
||||
netName dtypes.NetworkName
|
||||
|
||||
sigValCache *lru.TwoQueueCache
|
||||
|
||||
evtTypes [3]journal.EventType
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
@@ -160,6 +181,22 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount {
|
||||
return types.BigAdd(minPrice, types.NewInt(1))
|
||||
}
|
||||
|
||||
func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||
if maxFee.Equals(big.Zero()) {
|
||||
maxFee = types.NewInt(build.FilecoinPrecision / 10)
|
||||
}
|
||||
|
||||
gl := types.NewInt(uint64(msg.GasLimit))
|
||||
totalFee := types.BigMul(msg.GasFeeCap, gl)
|
||||
|
||||
if totalFee.LessThanEqual(maxFee) {
|
||||
return
|
||||
}
|
||||
|
||||
msg.GasFeeCap = big.Div(maxFee, gl)
|
||||
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
|
||||
}
|
||||
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) {
|
||||
nextNonce := ms.nextNonce
|
||||
nonceGap := false
|
||||
@@ -299,6 +336,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
api: api,
|
||||
netName: netName,
|
||||
cfg: cfg,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
|
||||
},
|
||||
}
|
||||
|
||||
// enable initial prunes
|
||||
@@ -350,10 +392,12 @@ func (mp *MessagePool) runLoop() {
|
||||
if err := mp.republishPendingMessages(); err != nil {
|
||||
log.Errorf("error while republishing messages: %s", err)
|
||||
}
|
||||
|
||||
case <-mp.pruneTrigger:
|
||||
if err := mp.pruneExcessMessages(); err != nil {
|
||||
log.Errorf("failed to prune excess messages from mempool: %s", err)
|
||||
}
|
||||
|
||||
case <-mp.closer:
|
||||
mp.repubTk.Stop()
|
||||
return
|
||||
@@ -397,18 +441,27 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T
|
||||
// Note that for local messages, we always add them so that they can be accepted and republished
|
||||
// automatically.
|
||||
publish := local
|
||||
if strictBaseFeeValidation && len(curTs.Blocks()) > 0 {
|
||||
baseFee := curTs.Blocks()[0].ParentBaseFee
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
if local {
|
||||
log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound)
|
||||
publish = false
|
||||
} else {
|
||||
return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure)
|
||||
}
|
||||
|
||||
var baseFee big.Int
|
||||
if len(curTs.Blocks()) > 0 {
|
||||
baseFee = curTs.Blocks()[0].ParentBaseFee
|
||||
} else {
|
||||
var err error
|
||||
baseFee, err = mp.api.ChainComputeBaseFee(context.TODO(), curTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactorConservative)
|
||||
if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||
if local {
|
||||
log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound)
|
||||
publish = false
|
||||
} else {
|
||||
return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w",
|
||||
m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +736,14 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
Type: api.MpoolAdd,
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "add",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -845,6 +906,12 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "remove",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
||||
})
|
||||
|
||||
mp.currentSize--
|
||||
}
|
||||
|
||||
@@ -1282,3 +1349,12 @@ func (mp *MessagePool) Clear(local bool) {
|
||||
delete(mp.pending, a)
|
||||
}
|
||||
}
|
||||
|
||||
func getBaseFeeLowerBound(baseFee, factor types.BigInt) types.BigInt {
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, factor)
|
||||
if baseFeeLowerBound.LessThan(minimumBaseFee) {
|
||||
baseFeeLowerBound = minimumBaseFee
|
||||
}
|
||||
|
||||
return baseFeeLowerBound
|
||||
}
|
||||
|
||||
@@ -46,13 +46,21 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
|
||||
if err != nil {
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactor)
|
||||
|
||||
pending, _ := mp.getPendingMessages(ts, ts)
|
||||
|
||||
// priority actors -- not pruned
|
||||
priority := make(map[address.Address]struct{})
|
||||
// protected actors -- not pruned
|
||||
protected := make(map[address.Address]struct{})
|
||||
|
||||
// we never prune priority addresses
|
||||
for _, actor := range mp.cfg.PriorityAddrs {
|
||||
priority[actor] = struct{}{}
|
||||
protected[actor] = struct{}{}
|
||||
}
|
||||
|
||||
// we also never prune locally published messages
|
||||
for actor := range mp.localAddrs {
|
||||
protected[actor] = struct{}{}
|
||||
}
|
||||
|
||||
// Collect all messages to track which ones to remove and create chains for block inclusion
|
||||
@@ -61,18 +69,18 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
|
||||
|
||||
var chains []*msgChain
|
||||
for actor, mset := range pending {
|
||||
// we never prune priority actors
|
||||
_, keep := priority[actor]
|
||||
// we never prune protected actors
|
||||
_, keep := protected[actor]
|
||||
if keep {
|
||||
keepCount += len(mset)
|
||||
continue
|
||||
}
|
||||
|
||||
// not a priority actor, track the messages and create chains
|
||||
// not a protected actor, track the messages and create chains
|
||||
for _, m := range mset {
|
||||
pruneMsgs[m.Message.Cid()] = m
|
||||
}
|
||||
actorChains := mp.createMessageChains(actor, mset, baseFee, ts)
|
||||
actorChains := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts)
|
||||
chains = append(chains, actorChains...)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
@@ -27,11 +28,7 @@ func (mp *MessagePool) republishPendingMessages() error {
|
||||
mp.curTsLk.Unlock()
|
||||
return xerrors.Errorf("computing basefee: %w", err)
|
||||
}
|
||||
|
||||
baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor)
|
||||
if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) {
|
||||
baseFeeLowerBound = minimumBaseFee
|
||||
}
|
||||
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactor)
|
||||
|
||||
pending := make(map[address.Address]map[uint64]*types.SignedMessage)
|
||||
mp.lk.Lock()
|
||||
@@ -150,6 +147,19 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
}
|
||||
return MessagePoolEvt{
|
||||
Action: "repub",
|
||||
Messages: msgs,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// track most recently republished messages
|
||||
republished := make(map[cid.Cid]struct{})
|
||||
for _, m := range msgs[:count] {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
|
||||
@@ -209,7 +210,7 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
||||
}
|
||||
|
||||
var act types.Actor
|
||||
if found, err := st.root.Get(adt.AddrKey(addr), &act); err != nil {
|
||||
if found, err := st.root.Get(abi.AddrKey(addr), &act); err != nil {
|
||||
return nil, xerrors.Errorf("hamt find failed: %w", err)
|
||||
} else if !found {
|
||||
return nil, types.ErrActorNotFound
|
||||
@@ -254,11 +255,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
|
||||
for addr, sto := range st.snaps.layers[0].actors {
|
||||
if sto.Delete {
|
||||
if err := st.root.Delete(adt.AddrKey(addr)); err != nil {
|
||||
if err := st.root.Delete(abi.AddrKey(addr)); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
} else {
|
||||
if err := st.root.Put(adt.AddrKey(addr), &sto.Act); err != nil {
|
||||
if err := st.root.Put(abi.AddrKey(addr), &sto.Act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ func (ta *testActor) Exports() []interface{} {
|
||||
|
||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
rt.State().Create(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Message().Receiver())
|
||||
rt.StateCreate(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
|
||||
return abi.Empty
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *ab
|
||||
func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
var st testActorState
|
||||
rt.State().Readonly(&st)
|
||||
rt.StateReadonly(&st)
|
||||
|
||||
if rt.CurrEpoch() > testForkHeight {
|
||||
if st.HasUpgraded != 55 {
|
||||
|
||||
@@ -233,8 +233,8 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
|
||||
receipts = append(receipts, &r.MessageReceipt)
|
||||
gasReward = big.Add(gasReward, r.MinerTip)
|
||||
penalty = big.Add(penalty, r.Penalty)
|
||||
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
||||
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
||||
|
||||
if cb != nil {
|
||||
if err := cb(cm.Cid(), m, r); err != nil {
|
||||
|
||||
@@ -120,7 +120,7 @@ func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr addres
|
||||
}
|
||||
|
||||
var claim power.Claim
|
||||
if _, err := cm.Get(adt.AddrKey(maddr), &claim); err != nil {
|
||||
if _, err := cm.Get(abi.AddrKey(maddr), &claim); err != nil {
|
||||
return power.Claim{}, power.Claim{}, err
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
|
||||
return false, err
|
||||
}
|
||||
|
||||
ok, err := claims.Get(power.AddrKey(maddr), nil)
|
||||
ok, err := claims.Get(abi.AddrKey(maddr), nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -554,7 +554,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
||||
|
||||
sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
|
||||
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 {
|
||||
|
||||
+41
-31
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"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/journal"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
@@ -72,6 +71,20 @@ func init() {
|
||||
// ReorgNotifee represents a callback that gets called upon reorgs.
|
||||
type ReorgNotifee func(rev, app []*types.TipSet) error
|
||||
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeHeadChange = iota
|
||||
)
|
||||
|
||||
type HeadChangeEvt struct {
|
||||
From types.TipSetKey
|
||||
FromHeight abi.ChainEpoch
|
||||
To types.TipSetKey
|
||||
ToHeight abi.ChainEpoch
|
||||
RevertCount int
|
||||
ApplyCount int
|
||||
}
|
||||
|
||||
// ChainStore is the main point of access to chain data.
|
||||
//
|
||||
// Raw chain data is stored in the Blockstore, with relevant markers (genesis,
|
||||
@@ -103,6 +116,8 @@ type ChainStore struct {
|
||||
tsCache *lru.ARCCache
|
||||
|
||||
vmcalls vm.SyscallBuilder
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||
@@ -118,6 +133,10 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
|
||||
vmcalls: vmcalls,
|
||||
}
|
||||
|
||||
cs.evtTypes = [1]journal.EventType{
|
||||
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
|
||||
}
|
||||
|
||||
ci := NewChainIndex(cs.LoadTipSet)
|
||||
|
||||
cs.cindex = ci
|
||||
@@ -344,12 +363,15 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
continue
|
||||
}
|
||||
|
||||
journal.Add("sync", map[string]interface{}{
|
||||
"op": "headChange",
|
||||
"from": r.old.Key(),
|
||||
"to": r.new.Key(),
|
||||
"rev": len(revert),
|
||||
"apply": len(apply),
|
||||
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
return HeadChangeEvt{
|
||||
From: r.old.Key(),
|
||||
FromHeight: r.old.Height(),
|
||||
To: r.new.Key(),
|
||||
ToHeight: r.new.Height(),
|
||||
RevertCount: len(revert),
|
||||
ApplyCount: len(apply),
|
||||
}
|
||||
})
|
||||
|
||||
// reverse the apply array
|
||||
@@ -744,32 +766,16 @@ type BlockMessages struct {
|
||||
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
||||
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) {
|
||||
if err := preloadAddr(m.From); err != nil {
|
||||
return false, err
|
||||
// The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
|
||||
if _, ok := applied[m.From]; !ok {
|
||||
applied[m.From] = m.Nonce
|
||||
}
|
||||
|
||||
if applied[m.From] != m.Nonce {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
applied[m.From]++
|
||||
|
||||
return true, nil
|
||||
@@ -1159,7 +1165,7 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.
|
||||
return in, rerr
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error {
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
@@ -1197,9 +1203,13 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
|
||||
cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
var cids []cid.Cid
|
||||
if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots {
|
||||
mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
}
|
||||
cids = mcids
|
||||
}
|
||||
|
||||
if b.Height > 0 {
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil {
|
||||
if err := cg.ChainStore().Export(context.TODO(), last, 0, false, buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
+16
-15
@@ -58,7 +58,14 @@ import (
|
||||
// the theoretical max height based on systime are quickly rejected
|
||||
const MaxHeightDrift = 5
|
||||
|
||||
var defaultMessageFetchWindowSize = 200
|
||||
var (
|
||||
// LocalIncoming is the _local_ pubsub (unrelated to libp2p pubsub) topic
|
||||
// where the Syncer publishes candidate chain heads to be synced.
|
||||
LocalIncoming = "incoming"
|
||||
|
||||
log = logging.Logger("chain")
|
||||
defaultMessageFetchWindowSize = 200
|
||||
)
|
||||
|
||||
func init() {
|
||||
if s := os.Getenv("LOTUS_BSYNC_MSG_WINDOW"); s != "" {
|
||||
@@ -71,10 +78,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
var log = logging.Logger("chain")
|
||||
|
||||
var LocalIncoming = "incoming"
|
||||
|
||||
// Syncer is in charge of running the chain synchronization logic. As such, it
|
||||
// is tasked with these functions, amongst others:
|
||||
//
|
||||
@@ -119,7 +122,7 @@ type Syncer struct {
|
||||
|
||||
self peer.ID
|
||||
|
||||
syncmgr *SyncManager
|
||||
syncmgr SyncManager
|
||||
|
||||
connmgr connmgr.ConnManager
|
||||
|
||||
@@ -140,8 +143,10 @@ type Syncer struct {
|
||||
ds dtypes.MetadataDS
|
||||
}
|
||||
|
||||
type SyncManagerCtor func(syncFn SyncFunc) SyncManager
|
||||
|
||||
// NewSyncer creates a new Syncer object.
|
||||
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||
func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, syncMgrCtor SyncManagerCtor, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) {
|
||||
gen, err := sm.ChainStore().GetGenesis()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting genesis block: %w", err)
|
||||
@@ -181,7 +186,7 @@ func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.C
|
||||
log.Warn("*********************************************************************************************")
|
||||
}
|
||||
|
||||
s.syncmgr = NewSyncManager(s.Sync)
|
||||
s.syncmgr = syncMgrCtor(s.Sync)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -648,7 +653,7 @@ func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, b
|
||||
}
|
||||
|
||||
var claim power.Claim
|
||||
exist, err := cm.Get(adt.AddrKey(maddr), &claim)
|
||||
exist, err := cm.Get(abi.AddrKey(maddr), &claim)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -986,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())
|
||||
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)
|
||||
@@ -1665,11 +1670,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
|
||||
}
|
||||
|
||||
func (syncer *Syncer) State() []SyncerState {
|
||||
var out []SyncerState
|
||||
for _, ss := range syncer.syncmgr.syncStates {
|
||||
out = append(out, ss.Snapshot())
|
||||
}
|
||||
return out
|
||||
return syncer.syncmgr.State()
|
||||
}
|
||||
|
||||
// MarkBad manually adds a block to the "bad blocks" cache.
|
||||
|
||||
+48
-16
@@ -20,7 +20,28 @@ const (
|
||||
|
||||
type SyncFunc func(context.Context, *types.TipSet) error
|
||||
|
||||
type SyncManager struct {
|
||||
// SyncManager manages the chain synchronization process, both at bootstrap time
|
||||
// and during ongoing operation.
|
||||
//
|
||||
// It receives candidate chain heads in the form of tipsets from peers,
|
||||
// and schedules them onto sync workers, deduplicating processing for
|
||||
// already-active syncs.
|
||||
type SyncManager interface {
|
||||
// Start starts the SyncManager.
|
||||
Start()
|
||||
|
||||
// Stop stops the SyncManager.
|
||||
Stop()
|
||||
|
||||
// SetPeerHead informs the SyncManager that the supplied peer reported the
|
||||
// supplied tipset.
|
||||
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
||||
|
||||
// State retrieves the state of the sync workers.
|
||||
State() []SyncerState
|
||||
}
|
||||
|
||||
type syncManager struct {
|
||||
lk sync.Mutex
|
||||
peerHeads map[peer.ID]*types.TipSet
|
||||
|
||||
@@ -48,6 +69,8 @@ type SyncManager struct {
|
||||
workerChan chan *types.TipSet
|
||||
}
|
||||
|
||||
var _ SyncManager = (*syncManager)(nil)
|
||||
|
||||
type syncResult struct {
|
||||
ts *types.TipSet
|
||||
success bool
|
||||
@@ -55,8 +78,8 @@ type syncResult struct {
|
||||
|
||||
const syncWorkerCount = 3
|
||||
|
||||
func NewSyncManager(sync SyncFunc) *SyncManager {
|
||||
return &SyncManager{
|
||||
func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
return &syncManager{
|
||||
bspThresh: 1,
|
||||
peerHeads: make(map[peer.ID]*types.TipSet),
|
||||
syncTargets: make(chan *types.TipSet),
|
||||
@@ -69,18 +92,18 @@ func NewSyncManager(sync SyncFunc) *SyncManager {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) Start() {
|
||||
func (sm *syncManager) Start() {
|
||||
go sm.syncScheduler()
|
||||
for i := 0; i < syncWorkerCount; i++ {
|
||||
go sm.syncWorker(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) Stop() {
|
||||
func (sm *syncManager) Stop() {
|
||||
close(sm.stop)
|
||||
}
|
||||
|
||||
func (sm *SyncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet) {
|
||||
func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet) {
|
||||
sm.lk.Lock()
|
||||
defer sm.lk.Unlock()
|
||||
sm.peerHeads[p] = ts
|
||||
@@ -105,6 +128,14 @@ func (sm *SyncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
|
||||
sm.incomingTipSets <- ts
|
||||
}
|
||||
|
||||
func (sm *syncManager) State() []SyncerState {
|
||||
ret := make([]SyncerState, 0, len(sm.syncStates))
|
||||
for _, s := range sm.syncStates {
|
||||
ret = append(ret, s.Snapshot())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type syncBucketSet struct {
|
||||
buckets []*syncTargetBucket
|
||||
}
|
||||
@@ -234,7 +265,7 @@ func (stb *syncTargetBucket) heaviestTipSet() *types.TipSet {
|
||||
return best
|
||||
}
|
||||
|
||||
func (sm *SyncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
func (sm *syncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
var buckets syncBucketSet
|
||||
|
||||
var peerHeads []*types.TipSet
|
||||
@@ -258,7 +289,7 @@ func (sm *SyncManager) selectSyncTarget() (*types.TipSet, error) {
|
||||
return buckets.Heaviest(), nil
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncScheduler() {
|
||||
func (sm *syncManager) syncScheduler() {
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -280,7 +311,7 @@ func (sm *SyncManager) syncScheduler() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
func (sm *syncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
log.Debug("scheduling incoming tipset sync: ", ts.Cids())
|
||||
if sm.getBootstrapState() == BSStateSelected {
|
||||
sm.setBootstrapState(BSStateScheduled)
|
||||
@@ -328,10 +359,11 @@ func (sm *SyncManager) scheduleIncoming(ts *types.TipSet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleProcessResult(res *syncResult) {
|
||||
func (sm *syncManager) scheduleProcessResult(res *syncResult) {
|
||||
if res.success && sm.getBootstrapState() != BSStateComplete {
|
||||
sm.setBootstrapState(BSStateComplete)
|
||||
}
|
||||
|
||||
delete(sm.activeSyncs, res.ts.Key())
|
||||
relbucket := sm.activeSyncTips.PopRelated(res.ts)
|
||||
if relbucket != nil {
|
||||
@@ -360,7 +392,7 @@ func (sm *SyncManager) scheduleProcessResult(res *syncResult) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) scheduleWorkSent() {
|
||||
func (sm *syncManager) scheduleWorkSent() {
|
||||
hts := sm.nextSyncTarget.heaviestTipSet()
|
||||
sm.activeSyncs[hts.Key()] = hts
|
||||
|
||||
@@ -372,7 +404,7 @@ func (sm *SyncManager) scheduleWorkSent() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncWorker(id int) {
|
||||
func (sm *syncManager) syncWorker(id int) {
|
||||
ss := &SyncerState{}
|
||||
sm.syncStates[id] = ss
|
||||
for {
|
||||
@@ -397,7 +429,7 @@ func (sm *SyncManager) syncWorker(id int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *SyncManager) syncedPeerCount() int {
|
||||
func (sm *syncManager) syncedPeerCount() int {
|
||||
var count int
|
||||
for _, ts := range sm.peerHeads {
|
||||
if ts.Height() > 0 {
|
||||
@@ -407,19 +439,19 @@ func (sm *SyncManager) syncedPeerCount() int {
|
||||
return count
|
||||
}
|
||||
|
||||
func (sm *SyncManager) getBootstrapState() int {
|
||||
func (sm *syncManager) getBootstrapState() int {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
return sm.bootstrapState
|
||||
}
|
||||
|
||||
func (sm *SyncManager) setBootstrapState(v int) {
|
||||
func (sm *syncManager) setBootstrapState(v int) {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
sm.bootstrapState = v
|
||||
}
|
||||
|
||||
func (sm *SyncManager) IsBootstrapped() bool {
|
||||
func (sm *syncManager) IsBootstrapped() bool {
|
||||
sm.bssLk.Lock()
|
||||
defer sm.bssLk.Unlock()
|
||||
return sm.bootstrapState == BSStateComplete
|
||||
|
||||
@@ -17,7 +17,7 @@ type syncOp struct {
|
||||
done func()
|
||||
}
|
||||
|
||||
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *SyncManager, chan *syncOp)) {
|
||||
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *syncManager, chan *syncOp)) {
|
||||
syncTargets := make(chan *syncOp)
|
||||
sm := NewSyncManager(func(ctx context.Context, ts *types.TipSet) error {
|
||||
ch := make(chan struct{})
|
||||
@@ -27,7 +27,7 @@ func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T,
|
||||
}
|
||||
<-ch
|
||||
return nil
|
||||
})
|
||||
}).(*syncManager)
|
||||
sm.bspThresh = thresh
|
||||
|
||||
sm.Start()
|
||||
@@ -77,12 +77,12 @@ func TestSyncManager(t *testing.T) {
|
||||
c3 := mock.TipSet(mock.MkBlock(b, 3, 5))
|
||||
d := mock.TipSet(mock.MkBlock(c1, 4, 5))
|
||||
|
||||
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", c1)
|
||||
assertGetSyncOp(t, stc, c1)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", c1)
|
||||
assertNoOp(t, stc)
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, c1)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", b)
|
||||
assertGetSyncOp(t, stc, b)
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, c2)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", a)
|
||||
assertGetSyncOp(t, stc, a)
|
||||
|
||||
@@ -122,7 +122,7 @@ func TestSyncManager(t *testing.T) {
|
||||
assertGetSyncOp(t, stc, d)
|
||||
})
|
||||
|
||||
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *SyncManager, stc chan *syncOp) {
|
||||
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
||||
sm.SetPeerHead(ctx, "peer1", a)
|
||||
assertGetSyncOp(t, stc, a)
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
// 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) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
runSyncBenchLength(b, 100)
|
||||
|
||||
+12
-7
@@ -22,6 +22,17 @@ type GasOutputs struct {
|
||||
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
|
||||
// Result is (refund, burn)
|
||||
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 {
|
||||
gasUsedBig := big.NewInt(gasUsed)
|
||||
out := GasOutputs{
|
||||
BaseFeeBurn: big.Zero(),
|
||||
OverEstimationBurn: big.Zero(),
|
||||
MinerPenalty: big.Zero(),
|
||||
MinerTip: big.Zero(),
|
||||
Refund: big.Zero(),
|
||||
}
|
||||
out := ZeroGasOutputs()
|
||||
|
||||
baseFeeToPay := baseFee
|
||||
if baseFee.Cmp(feeCap.Int) > 0 {
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.Metho
|
||||
|
||||
code, ok := inv.builtInCode[codeCid]
|
||||
if !ok {
|
||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Message().Receiver())
|
||||
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
|
||||
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
|
||||
}
|
||||
if method >= abi.MethodNum(len(code)) || code[method] == nil {
|
||||
|
||||
+54
-70
@@ -8,7 +8,9 @@ import (
|
||||
gruntime "runtime"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
rtt "github.com/filecoin-project/go-state-types/rt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -16,11 +18,9 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
vmr "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
rt0 "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -31,20 +31,20 @@ import (
|
||||
)
|
||||
|
||||
type Runtime struct {
|
||||
types.Message
|
||||
rt0.Syscalls
|
||||
|
||||
ctx context.Context
|
||||
|
||||
vm *VM
|
||||
state *state.StateTree
|
||||
vmsg vmr.Message
|
||||
height abi.ChainEpoch
|
||||
cst cbor.IpldStore
|
||||
cst ipldcbor.IpldStore
|
||||
pricelist Pricelist
|
||||
|
||||
gasAvailable int64
|
||||
gasUsed int64
|
||||
|
||||
sys runtime.Syscalls
|
||||
|
||||
// address that started invoke chain
|
||||
origin address.Address
|
||||
originNonce uint64
|
||||
@@ -85,11 +85,11 @@ type notFoundErr interface {
|
||||
IsNotFound() bool
|
||||
}
|
||||
|
||||
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
func (rt *Runtime) StoreGet(c cid.Cid, o cbor.Unmarshaler) bool {
|
||||
if err := rt.cst.Get(context.TODO(), c, o); err != nil {
|
||||
var nfe notFoundErr
|
||||
if xerrors.As(err, &nfe) && nfe.IsNotFound() {
|
||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||
if xerrors.As(err, new(ipldcbor.SerializationError)) {
|
||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to unmarshal cbor object %s", err))
|
||||
}
|
||||
return false
|
||||
@@ -100,10 +100,10 @@ func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
func (rt *Runtime) StorePut(x cbor.Marshaler) cid.Cid {
|
||||
c, err := rt.cst.Put(context.TODO(), x)
|
||||
if err != nil {
|
||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||
if xerrors.As(err, new(ipldcbor.SerializationError)) {
|
||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
|
||||
}
|
||||
panic(aerrors.Fatalf("failed to put cbor object: %s", err))
|
||||
@@ -111,7 +111,7 @@ func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
return c
|
||||
}
|
||||
|
||||
var _ vmr.Runtime = (*Runtime)(nil)
|
||||
var _ rt0.Runtime = (*Runtime)(nil)
|
||||
|
||||
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||
defer func() {
|
||||
@@ -139,7 +139,7 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
return ret, nil
|
||||
case *abi.EmptyValue:
|
||||
return nil, nil
|
||||
case cbg.CBORMarshaler:
|
||||
case cbor.Marshaler:
|
||||
buf := new(bytes.Buffer)
|
||||
if err := ret.MarshalCBOR(buf); err != nil {
|
||||
return nil, aerrors.Absorb(err, 2, "failed to marshal response to cbor")
|
||||
@@ -152,17 +152,13 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *Runtime) Message() vmr.Message {
|
||||
return rt.vmsg
|
||||
}
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerAcceptAny() {
|
||||
rt.abortIfAlreadyValidated()
|
||||
return
|
||||
}
|
||||
|
||||
func (rt *Runtime) CurrentBalance() abi.TokenAmount {
|
||||
b, err := rt.GetBalance(rt.Message().Receiver())
|
||||
b, err := rt.GetBalance(rt.Receiver())
|
||||
if err != nil {
|
||||
rt.Abortf(err.RetCode(), "get current balance: %v", err)
|
||||
}
|
||||
@@ -198,10 +194,6 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati
|
||||
return res
|
||||
}
|
||||
|
||||
func (rt *Runtime) Store() vmr.Store {
|
||||
return rt
|
||||
}
|
||||
|
||||
func (rt *Runtime) NewActorAddress() address.Address {
|
||||
var b bytes.Buffer
|
||||
oa, _ := ResolveToKeyAddr(rt.vm.cstate, rt.vm.cst, rt.origin)
|
||||
@@ -258,7 +250,7 @@ func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
||||
// May only be called by the actor itself.
|
||||
func (rt *Runtime) DeleteActor(beneficiary address.Address) {
|
||||
rt.chargeGas(rt.Pricelist().OnDeleteActor())
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "failed to load actor in delete actor: %s", err)
|
||||
@@ -267,36 +259,32 @@ func (rt *Runtime) DeleteActor(beneficiary address.Address) {
|
||||
}
|
||||
if !act.Balance.IsZero() {
|
||||
// Transfer the executing actor's balance to the beneficiary
|
||||
if err := rt.vm.transfer(rt.Message().Receiver(), beneficiary, act.Balance); err != nil {
|
||||
if err := rt.vm.transfer(rt.Receiver(), beneficiary, act.Balance); err != nil {
|
||||
panic(aerrors.Fatalf("failed to transfer balance to beneficiary actor: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the executing actor
|
||||
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
|
||||
if err := rt.state.DeleteActor(rt.Receiver()); err != nil {
|
||||
panic(aerrors.Fatalf("failed to delete actor: %s", err))
|
||||
}
|
||||
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||
}
|
||||
|
||||
func (rt *Runtime) Syscalls() vmr.Syscalls {
|
||||
return rt.sys
|
||||
}
|
||||
|
||||
func (rt *Runtime) StartSpan(name string) vmr.TraceSpan {
|
||||
func (rt *Runtime) StartSpan(name string) func() {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerIs(as ...address.Address) {
|
||||
rt.abortIfAlreadyValidated()
|
||||
imm := rt.Message().Caller()
|
||||
imm := rt.Caller()
|
||||
|
||||
for _, a := range as {
|
||||
if imm == a {
|
||||
return
|
||||
}
|
||||
}
|
||||
rt.Abortf(exitcode.SysErrForbidden, "caller %s is not one of %s", rt.Message().Caller(), as)
|
||||
rt.Abortf(exitcode.SysErrForbidden, "caller %s is not one of %s", rt.Caller(), as)
|
||||
}
|
||||
|
||||
func (rt *Runtime) Context() context.Context {
|
||||
@@ -314,7 +302,7 @@ func (rt *Runtime) AbortStateMsg(msg string) {
|
||||
|
||||
func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
|
||||
rt.abortIfAlreadyValidated()
|
||||
callerCid, ok := rt.GetActorCodeCID(rt.Message().Caller())
|
||||
callerCid, ok := rt.GetActorCodeCID(rt.Caller())
|
||||
if !ok {
|
||||
panic(aerrors.Fatalf("failed to lookup code cid for caller"))
|
||||
}
|
||||
@@ -334,11 +322,11 @@ type dumbWrapperType struct {
|
||||
val []byte
|
||||
}
|
||||
|
||||
func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
|
||||
func (dwt *dumbWrapperType) Into(um cbor.Unmarshaler) error {
|
||||
return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
|
||||
}
|
||||
|
||||
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
||||
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m cbor.Marshaler, value abi.TokenAmount, out cbor.Er) exitcode.ExitCode {
|
||||
if !rt.allowInternal {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
||||
}
|
||||
@@ -351,16 +339,20 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
|
||||
params = buf.Bytes()
|
||||
}
|
||||
|
||||
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params)
|
||||
ret, err := rt.internalSend(rt.Receiver(), to, method, value, params)
|
||||
if err != nil {
|
||||
if err.IsFatal() {
|
||||
panic(err)
|
||||
}
|
||||
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
|
||||
return &dumbWrapperType{nil}, err.RetCode()
|
||||
return err.RetCode()
|
||||
}
|
||||
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||
return &dumbWrapperType{ret}, 0
|
||||
|
||||
if err := out.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
rt.Abortf(exitcode.ErrSerialization, "failed to unmarshal return value: %s", err)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||
@@ -404,49 +396,41 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
|
||||
return ret, errSend
|
||||
}
|
||||
|
||||
func (rt *Runtime) State() vmr.StateHandle {
|
||||
return &shimStateHandle{rt: rt}
|
||||
}
|
||||
|
||||
type shimStateHandle struct {
|
||||
rt *Runtime
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
||||
c := ssh.rt.Put(obj)
|
||||
err := ssh.rt.stateCommit(EmptyObjectCid, c)
|
||||
func (rt *Runtime) StateCreate(obj cbor.Marshaler) {
|
||||
c := rt.StorePut(obj)
|
||||
err := rt.stateCommit(EmptyObjectCid, c)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to commit state after creating object: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
func (rt *Runtime) StateReadonly(obj cbor.Unmarshaler) {
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
}
|
||||
ssh.rt.Get(act.Head, obj)
|
||||
rt.StoreGet(act.Head, obj)
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func()) {
|
||||
func (rt *Runtime) StateTransaction(obj cbor.Er, f func()) {
|
||||
if obj == nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
}
|
||||
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
}
|
||||
baseState := act.Head
|
||||
ssh.rt.Get(baseState, obj)
|
||||
rt.StoreGet(baseState, obj)
|
||||
|
||||
ssh.rt.allowInternal = false
|
||||
rt.allowInternal = false
|
||||
f()
|
||||
ssh.rt.allowInternal = true
|
||||
rt.allowInternal = true
|
||||
|
||||
c := ssh.rt.Put(obj)
|
||||
c := rt.StorePut(obj)
|
||||
|
||||
err = ssh.rt.stateCommit(baseState, c)
|
||||
err = rt.stateCommit(baseState, c)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to commit state after transaction: %w", err))
|
||||
}
|
||||
@@ -466,7 +450,7 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr
|
||||
|
||||
func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
// TODO: we can make this more efficient in the future...
|
||||
act, err := rt.state.GetActor(rt.Message().Receiver())
|
||||
act, err := rt.state.GetActor(rt.Receiver())
|
||||
if err != nil {
|
||||
return aerrors.Escalate(err, "failed to get actor to commit state")
|
||||
}
|
||||
@@ -477,7 +461,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
|
||||
|
||||
act.Head = newh
|
||||
|
||||
if err := rt.state.SetActor(rt.Message().Receiver(), act); err != nil {
|
||||
if err := rt.state.SetActor(rt.Receiver(), act); err != nil {
|
||||
return aerrors.Fatalf("failed to set actor in commit state: %s", err)
|
||||
}
|
||||
|
||||
@@ -572,15 +556,15 @@ func (rt *Runtime) abortIfAlreadyValidated() {
|
||||
rt.callerValidated = true
|
||||
}
|
||||
|
||||
func (rt *Runtime) Log(level vmr.LogLevel, msg string, args ...interface{}) {
|
||||
func (rt *Runtime) Log(level rtt.LogLevel, msg string, args ...interface{}) {
|
||||
switch level {
|
||||
case vmr.DEBUG:
|
||||
case rtt.DEBUG:
|
||||
actorLog.Debugf(msg, args...)
|
||||
case vmr.INFO:
|
||||
case rtt.INFO:
|
||||
actorLog.Infof(msg, args...)
|
||||
case vmr.WARN:
|
||||
case rtt.WARN:
|
||||
actorLog.Warnf(msg, args...)
|
||||
case vmr.ERROR:
|
||||
case rtt.ERROR:
|
||||
actorLog.Errorf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,6 @@ func TestRuntimePutErrors(t *testing.T) {
|
||||
cst: cbor.NewCborStore(nil),
|
||||
}
|
||||
|
||||
rt.Put(&NotAVeryGoodMarshaler{})
|
||||
rt.StorePut(&NotAVeryGoodMarshaler{})
|
||||
t.Error("expected panic")
|
||||
}
|
||||
|
||||
+23
-20
@@ -116,7 +116,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
Blocks: &gasChargingBlocks{rt.chargeGasFunc(2), rt.pricelist, vm.cst.Blocks},
|
||||
Atlas: vm.cst.Atlas,
|
||||
}
|
||||
rt.sys = pricedSyscalls{
|
||||
rt.Syscalls = pricedSyscalls{
|
||||
under: vm.Syscalls(ctx, vm.cstate, rt.cst),
|
||||
chargeGas: rt.chargeGasFunc(1),
|
||||
pl: rt.pricelist,
|
||||
@@ -128,7 +128,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
|
||||
rt.Abortf(exitcode.SysErrInvalidReceiver, "resolve msg.From address failed")
|
||||
}
|
||||
vmm.From = resF
|
||||
rt.vmsg = &vmm
|
||||
rt.Message = vmm
|
||||
|
||||
return rt
|
||||
}
|
||||
@@ -201,10 +201,9 @@ type Rand interface {
|
||||
type ApplyRet struct {
|
||||
types.MessageReceipt
|
||||
ActorErr aerrors.ActorError
|
||||
Penalty types.BigInt
|
||||
MinerTip types.BigInt
|
||||
ExecutionTrace types.ExecutionTrace
|
||||
Duration time.Duration
|
||||
GasCosts GasOutputs
|
||||
}
|
||||
|
||||
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,
|
||||
ExecutionTrace: rt.executionTrace,
|
||||
Penalty: types.NewInt(0),
|
||||
MinerTip: types.NewInt(0),
|
||||
GasCosts: GasOutputs{},
|
||||
Duration: time.Since(start),
|
||||
}, actorErr
|
||||
}
|
||||
@@ -357,14 +355,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
msgGasCost := msgGas.Total()
|
||||
// this should never happen, but is currently still exercised by some tests
|
||||
if msgGasCost > msg.GasLimit {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost))
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrOutOfGas,
|
||||
GasUsed: 0,
|
||||
},
|
||||
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, 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
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderInvalid,
|
||||
GasUsed: 0,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
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
|
||||
if !fromActor.Code.Equals(builtin.AccountActorCodeID) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderInvalid,
|
||||
GasUsed: 0,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if msg.Nonce != fromActor.Nonce {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderStateInvalid,
|
||||
@@ -411,14 +414,16 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
|
||||
Penalty: minerPenaltyAmount,
|
||||
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
|
||||
if fromActor.Balance.LessThan(gascost) {
|
||||
gasOutputs := ZeroGasOutputs()
|
||||
gasOutputs.MinerPenalty = minerPenaltyAmount
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.SysErrSenderStateInvalid,
|
||||
@@ -426,9 +431,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
|
||||
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
|
||||
Penalty: minerPenaltyAmount,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
MinerTip: big.Zero(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -521,8 +525,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
},
|
||||
ActorErr: actorErr,
|
||||
ExecutionTrace: rt.executionTrace,
|
||||
Penalty: gasOutputs.MinerPenalty,
|
||||
MinerTip: gasOutputs.MinerTip,
|
||||
GasCosts: gasOutputs,
|
||||
Duration: time.Since(start),
|
||||
}, nil
|
||||
}
|
||||
@@ -700,9 +703,9 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("to", rt.Message().Receiver().String()),
|
||||
trace.StringAttribute("to", rt.Receiver().String()),
|
||||
trace.Int64Attribute("method", int64(method)),
|
||||
trace.StringAttribute("value", rt.Message().ValueReceived().String()),
|
||||
trace.StringAttribute("value", rt.ValueReceived().String()),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -659,7 +659,7 @@ func handleHamtEpoch(ctx context.Context, api api.FullNode, r cid.Cid) error {
|
||||
}
|
||||
|
||||
return mp.ForEach(nil, func(key string) error {
|
||||
ik, err := adt.ParseIntKey(key)
|
||||
ik, err := abi.ParseIntKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -844,6 +844,9 @@ var chainExportCmd = &cli.Command{
|
||||
Name: "recent-stateroots",
|
||||
Usage: "specify the number of recent state roots to include in the export",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-old-msgs",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -878,7 +881,13 @@ var chainExportCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := api.ChainExport(ctx, rsrs, ts.Key())
|
||||
skipold := cctx.Bool("skip-old-msgs")
|
||||
|
||||
if rsrs == 0 && skipold {
|
||||
return fmt.Errorf("must pass recent stateroots along with skip-old-msgs")
|
||||
}
|
||||
|
||||
stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/fatih/color"
|
||||
@@ -527,6 +529,11 @@ func interactiveDeal(cctx *cli.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if days < int(build.MinDealDuration/builtin.EpochsInDay) {
|
||||
printErr(xerrors.Errorf("minimum duration is %d days", int(build.MinDealDuration/builtin.EpochsInDay)))
|
||||
continue
|
||||
}
|
||||
|
||||
state = "miner"
|
||||
case "miner":
|
||||
fmt.Print("Miner Address (t0..): ")
|
||||
|
||||
+20
-3
@@ -303,6 +303,10 @@ var mpoolReplaceCmd = &cli.Command{
|
||||
Name: "auto",
|
||||
Usage: "automatically reprice the specified message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "max-fee",
|
||||
Usage: "Spend up to X FIL for this message (applicable for auto mode)",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[from] [nonce]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
@@ -353,17 +357,30 @@ var mpoolReplaceCmd = &cli.Command{
|
||||
msg := found.Message
|
||||
|
||||
if cctx.Bool("auto") {
|
||||
minRBF := messagepool.ComputeMinRBF(msg.GasPremium)
|
||||
|
||||
var mss *lapi.MessageSendSpec
|
||||
if cctx.IsSet("max-fee") {
|
||||
maxFee, err := types.BigFromString(cctx.String("max-fee"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing max-spend: %w", err)
|
||||
}
|
||||
mss = &lapi.MessageSendSpec{
|
||||
MaxFee: maxFee,
|
||||
}
|
||||
}
|
||||
|
||||
// msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool
|
||||
msg.GasFeeCap = abi.NewTokenAmount(0)
|
||||
msg.GasPremium = abi.NewTokenAmount(0)
|
||||
retm, err := api.GasEstimateMessageGas(ctx, &msg, &lapi.MessageSendSpec{}, types.EmptyTSK)
|
||||
retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to estimate gas values: %w", err)
|
||||
}
|
||||
msg.GasFeeCap = retm.GasFeeCap
|
||||
|
||||
minRBF := messagepool.ComputeMinRBF(msg.GasPremium)
|
||||
msg.GasPremium = big.Max(retm.GasPremium, minRBF)
|
||||
msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium)
|
||||
messagepool.CapGasFee(&msg, mss.Get().MaxFee)
|
||||
} else {
|
||||
msg.GasLimit = cctx.Int64("gas-limit")
|
||||
msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium"))
|
||||
|
||||
+6
-2
@@ -28,6 +28,8 @@ var paychCmd = &cli.Command{
|
||||
paychListCmd,
|
||||
paychVoucherCmd,
|
||||
paychSettleCmd,
|
||||
paychStatusCmd,
|
||||
paychStatusByFromToCmd,
|
||||
paychCloseCmd,
|
||||
},
|
||||
}
|
||||
@@ -102,6 +104,7 @@ var paychStatusByFromToCmd = &cli.Command{
|
||||
if cctx.Args().Len() != 2 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass two arguments: <from address> <to address>"))
|
||||
}
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
from, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
@@ -119,7 +122,7 @@ var paychStatusByFromToCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
|
||||
avail, err := api.PaychAvailableFundsByFromTo(from, to)
|
||||
avail, err := api.PaychAvailableFundsByFromTo(ctx, from, to)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -137,6 +140,7 @@ var paychStatusCmd = &cli.Command{
|
||||
if cctx.Args().Len() != 1 {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass an argument: <channel address>"))
|
||||
}
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
ch, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
@@ -149,7 +153,7 @@ var paychStatusCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
|
||||
avail, err := api.PaychAvailableFunds(ch)
|
||||
avail, err := api.PaychAvailableFunds(ctx, ch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+153
-5
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||
@@ -53,6 +54,7 @@ var stateCmd = &cli.Command{
|
||||
stateListActorsCmd,
|
||||
stateListMinersCmd,
|
||||
stateCircSupplyCmd,
|
||||
stateSectorCmd,
|
||||
stateGetActorCmd,
|
||||
stateLookupIDCmd,
|
||||
stateReplaySetCmd,
|
||||
@@ -64,6 +66,7 @@ var stateCmd = &cli.Command{
|
||||
stateGetDealSetCmd,
|
||||
stateWaitMsgCmd,
|
||||
stateSearchMsgCmd,
|
||||
stateMsgCostCmd,
|
||||
stateMinerInfo,
|
||||
stateMarketCmd,
|
||||
},
|
||||
@@ -118,11 +121,18 @@ var stateMinerInfo = &cli.Command{
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Proving Period Start:\t%s\n", EpochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func parseTipSetString(ts string) ([]cid.Cid, error) {
|
||||
func ParseTipSetString(ts string) ([]cid.Cid, error) {
|
||||
strs := strings.Split(ts, ",")
|
||||
|
||||
var cids []cid.Cid
|
||||
@@ -160,7 +170,7 @@ func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.T
|
||||
return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK)
|
||||
}
|
||||
|
||||
cids, err := parseTipSetString(tss)
|
||||
cids, err := ParseTipSetString(tss)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1303,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{
|
||||
Name: "call",
|
||||
Usage: "Invoke a method on an actor locally",
|
||||
@@ -1384,7 +1448,7 @@ var stateCallCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if ret.MsgRct.ExitCode != 0 {
|
||||
return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error)
|
||||
return fmt.Errorf("invocation failed (exit: %d, gasUsed: %d): %s", ret.MsgRct.ExitCode, ret.MsgRct.GasUsed, ret.Error)
|
||||
}
|
||||
|
||||
s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return)
|
||||
@@ -1392,6 +1456,7 @@ var stateCallCmd = &cli.Command{
|
||||
return fmt.Errorf("failed to format output: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("gas used: %d\n", ret.MsgRct.GasUsed)
|
||||
fmt.Printf("return: %s\n", s)
|
||||
|
||||
return nil
|
||||
@@ -1465,11 +1530,11 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
||||
f := methods[method]
|
||||
|
||||
rf := reflect.TypeOf(f)
|
||||
if rf.NumIn() != 3 {
|
||||
if rf.NumIn() != 2 {
|
||||
return nil, fmt.Errorf("expected referenced method to have three arguments")
|
||||
}
|
||||
|
||||
paramObj := rf.In(2).Elem()
|
||||
paramObj := rf.In(1).Elem()
|
||||
if paramObj.NumField() != len(args) {
|
||||
return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField())
|
||||
}
|
||||
@@ -1489,6 +1554,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(val))
|
||||
case reflect.TypeOf(abi.ChainEpoch(0)):
|
||||
val, err := strconv.ParseInt(args[i], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(abi.ChainEpoch(val)))
|
||||
case reflect.TypeOf(big.Int{}):
|
||||
val, err := big.FromString(args[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(val))
|
||||
case reflect.TypeOf(peer.ID("")):
|
||||
pid, err := peer.Decode(args[i])
|
||||
if err != nil {
|
||||
@@ -1540,6 +1617,77 @@ var stateCircSupplyCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var stateSectorCmd = &cli.Command{
|
||||
Name: "sector",
|
||||
Usage: "Get miner sector info",
|
||||
ArgsUsage: "[miner address] [sector number]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() != 2 {
|
||||
return xerrors.Errorf("expected 2 params")
|
||||
}
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ts == nil {
|
||||
ts, err = api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sid, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
si, err := api.StateSectorGetInfo(ctx, maddr, abi.SectorNumber(sid), ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("SectorNumber: ", si.SectorNumber)
|
||||
fmt.Println("SealProof: ", si.SealProof)
|
||||
fmt.Println("SealedCID: ", si.SealedCID)
|
||||
fmt.Println("DealIDs: ", si.DealIDs)
|
||||
fmt.Println()
|
||||
fmt.Println("Activation: ", EpochTime(ts.Height(), si.Activation))
|
||||
fmt.Println("Expiration: ", EpochTime(ts.Height(), si.Expiration))
|
||||
fmt.Println()
|
||||
fmt.Println("DealWeight: ", si.DealWeight)
|
||||
fmt.Println("VerifiedDealWeight: ", si.VerifiedDealWeight)
|
||||
fmt.Println("InitialPledge: ", types.FIL(si.InitialPledge))
|
||||
fmt.Println("ExpectedDayReward: ", types.FIL(si.ExpectedDayReward))
|
||||
fmt.Println("ExpectedStoragePledge: ", types.FIL(si.ExpectedStoragePledge))
|
||||
fmt.Println()
|
||||
|
||||
sp, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(sid), ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Deadline: ", sp.Deadline)
|
||||
fmt.Println("Partition: ", sp.Partition)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateMarketCmd = &cli.Command{
|
||||
Name: "market",
|
||||
Usage: "Inspect the storage market actor",
|
||||
|
||||
+20
-1
@@ -2,10 +2,16 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) {
|
||||
@@ -26,3 +32,16 @@ func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.T
|
||||
|
||||
return types.NewTipSet(headers)
|
||||
}
|
||||
|
||||
func EpochTime(curr, e abi.ChainEpoch) string {
|
||||
switch {
|
||||
case curr > e:
|
||||
return fmt.Sprintf("%d (%s ago)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(curr-e)))
|
||||
case curr == e:
|
||||
return fmt.Sprintf("%d (now)", e)
|
||||
case curr < e:
|
||||
return fmt.Sprintf("%d (in %s)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(e-curr)))
|
||||
}
|
||||
|
||||
panic("math broke")
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ var importBenchCmd = &cli.Command{
|
||||
Usage: "set the parallelism factor for batch seal verification",
|
||||
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 {
|
||||
vm.BatchSealVerifyParallelism = cctx.Int("batch-seal-verify-threads")
|
||||
@@ -70,9 +74,15 @@ var importBenchCmd = &cli.Command{
|
||||
}
|
||||
defer cfi.Close() //nolint:errcheck // read only file
|
||||
|
||||
tdir, err := ioutil.TempDir("", "lotus-import-bench")
|
||||
if err != nil {
|
||||
return err
|
||||
var tdir string
|
||||
if rdir := cctx.String("repodir"); rdir != "" {
|
||||
tdir = rdir
|
||||
} else {
|
||||
tmp, err := ioutil.TempDir("", "lotus-import-bench")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tdir = tmp
|
||||
}
|
||||
|
||||
bds, err := badger.NewDatastore(tdir, nil)
|
||||
|
||||
@@ -387,7 +387,7 @@ var sealBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
log.Error("post verification failed")
|
||||
log.Error("window post verification failed")
|
||||
}
|
||||
|
||||
verifyWindowpost1 := time.Now()
|
||||
@@ -403,7 +403,7 @@ var sealBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
log.Error("post verification failed")
|
||||
log.Error("window post verification failed")
|
||||
}
|
||||
|
||||
verifyWindowpost2 := time.Now()
|
||||
|
||||
@@ -221,7 +221,7 @@ func (p *Processor) processMiners(ctx context.Context, minerTips map[types.TipSe
|
||||
var claim power.Claim
|
||||
// get miner claim from power actors claim map and store if found, else the miner had no claim at
|
||||
// this tipset
|
||||
found, err := minersClaims.Get(adt.AddrKey(act.addr), &claim)
|
||||
found, err := minersClaims.Get(abi.AddrKey(act.addr), &claim)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -136,7 +136,8 @@ create unique index if not exists block_cid_uindex
|
||||
on blocks (cid,height);
|
||||
|
||||
create materialized view if not exists state_heights
|
||||
as select distinct height, parentstateroot from blocks;
|
||||
as select min(b.height) height, b.parentstateroot
|
||||
from blocks b group by b.parentstateroot;
|
||||
|
||||
create index if not exists state_heights_height_index
|
||||
on state_heights (height);
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
const LookbackCap = time.Hour
|
||||
|
||||
var (
|
||||
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
|
||||
)
|
||||
|
||||
type GatewayAPI struct {
|
||||
api api.FullNode
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return time.Now(), nil
|
||||
}
|
||||
|
||||
ts, err := a.api.ChainGetTipSet(ctx, tsk)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error {
|
||||
when, err := a.getTipsetTimestamp(ctx, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if time.Since(when) > time.Hour {
|
||||
return ErrLookbackTooLong
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "StateGetActor")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, ts); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
return a.api.StateGetActor(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainHead")
|
||||
defer span.End()
|
||||
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
|
||||
|
||||
return a.api.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ChainGetTipSet")
|
||||
defer span.End()
|
||||
|
||||
if err := a.checkTipset(ctx, tsk); err != nil {
|
||||
return nil, fmt.Errorf("bad tipset: %w", err)
|
||||
}
|
||||
|
||||
// TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes)
|
||||
return a.api.ChainGetTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "MpoolPush")
|
||||
defer span.End()
|
||||
|
||||
// TODO: additional anti-spam checks
|
||||
|
||||
return a.api.MpoolPush(ctx, sm)
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logging.Logger("gateway")
|
||||
|
||||
func main() {
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
runCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "lotus-gateway",
|
||||
Usage: "Public API server for lotus",
|
||||
Version: build.UserVersion(),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
EnvVars: []string{"LOTUS_PATH"},
|
||||
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||
},
|
||||
},
|
||||
|
||||
Commands: local,
|
||||
}
|
||||
app.Setup()
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Warnf("%+v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var runCmd = &cli.Command{
|
||||
Name: "run",
|
||||
Usage: "Start api server",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "listen",
|
||||
Usage: "host address and port the api server will listen on",
|
||||
Value: "0.0.0.0:2346",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
log.Info("Starting lotus gateway")
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
address := cctx.String("listen")
|
||||
mux := mux.NewRouter()
|
||||
|
||||
log.Info("Setting up API endpoint at " + address)
|
||||
|
||||
rpcServer := jsonrpc.NewServer()
|
||||
rpcServer.Register("Filecoin", &GatewayAPI{api: api})
|
||||
|
||||
mux.Handle("/rpc/v0", rpcServer)
|
||||
mux.PathPrefix("/").Handler(http.DefaultServeMux)
|
||||
|
||||
/*ah := &auth.Handler{
|
||||
Verify: nodeApi.AuthVerify,
|
||||
Next: mux.ServeHTTP,
|
||||
}*/
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: mux,
|
||||
BaseContext: func(listener net.Listener) context.Context {
|
||||
return ctx
|
||||
},
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.Warn("Shutting down...")
|
||||
if err := srv.Shutdown(context.TODO()); err != nil {
|
||||
log.Errorf("shutting down RPC server failed: %s", err)
|
||||
}
|
||||
log.Warn("Graceful shutdown successful")
|
||||
}()
|
||||
|
||||
nl, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return srv.Serve(nl)
|
||||
},
|
||||
}
|
||||
+173
-31
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
@@ -28,6 +29,9 @@ var bitFieldCmd = &cli.Command{
|
||||
bitFieldRunsCmd,
|
||||
bitFieldStatCmd,
|
||||
bitFieldDecodeCmd,
|
||||
bitFieldIntersectCmd,
|
||||
bitFieldEncodeCmd,
|
||||
bitFieldSubCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -200,38 +204,9 @@ var bitFieldDecodeCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
var val string
|
||||
if cctx.Args().Present() {
|
||||
val = cctx.Args().Get(0)
|
||||
} else {
|
||||
b, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
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)
|
||||
rle, err := decode(cctx, 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse bitfield: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
vals, err := rle.All(100000000000)
|
||||
@@ -243,3 +218,170 @@ var bitFieldDecodeCmd = &cli.Command{
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
var exportChainCmd = &cli.Command{
|
||||
Name: "export",
|
||||
Description: "Export chain from repo (requires node to be offline)",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
Value: "~/.lotus",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
Usage: "tipset to export from",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "recent-stateroots",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "full-state",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skip-old-msgs",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return lcli.ShowHelp(cctx, fmt.Errorf("must specify file name to write export to"))
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
r, err := repo.NewFS(cctx.String("repo"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening fs repo: %w", err)
|
||||
}
|
||||
|
||||
exists, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return xerrors.Errorf("lotus repo doesn't exist")
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.FullNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
fi, err := os.Create(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening the output file: %w", err)
|
||||
}
|
||||
|
||||
defer fi.Close() //nolint:errcheck
|
||||
|
||||
ds, err := lr.Datastore("/chain")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mds, err := lr.Datastore("/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, nil)
|
||||
if err := cs.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nroots := abi.ChainEpoch(cctx.Int64("recent-stateroots"))
|
||||
fullstate := cctx.Bool("full-state")
|
||||
skipoldmsgs := cctx.Bool("skip-old-msgs")
|
||||
|
||||
var ts *types.TipSet
|
||||
if tss := cctx.String("tipset"); tss != "" {
|
||||
cids, err := lcli.ParseTipSetString(tss)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse tipset (%q): %w", tss, err)
|
||||
}
|
||||
|
||||
tsk := types.NewTipSetKey(cids...)
|
||||
|
||||
selts, err := cs.LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading tipset: %w", err)
|
||||
}
|
||||
ts = selts
|
||||
} else {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
if fullstate {
|
||||
nroots = ts.Height() + 1
|
||||
}
|
||||
|
||||
if err := cs.Export(ctx, ts, nroots, skipoldmsgs, fi); err != nil {
|
||||
return xerrors.Errorf("export failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -34,6 +34,7 @@ func main() {
|
||||
genesisVerifyCmd,
|
||||
mathCmd,
|
||||
mpoolStatsCmd,
|
||||
exportChainCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
@@ -336,7 +337,7 @@ var verifRegCheckVerifierCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var dcap verifreg.DataCap
|
||||
if found, err := vh.Get(adt.AddrKey(vaddr), &dcap); err != nil {
|
||||
if found, err := vh.Get(abi.AddrKey(vaddr), &dcap); err != nil {
|
||||
return err
|
||||
} else if !found {
|
||||
return fmt.Errorf("not found")
|
||||
|
||||
@@ -44,6 +44,7 @@ import (
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
@@ -459,6 +460,12 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
|
||||
return err
|
||||
}
|
||||
|
||||
if jrnl, err := journal.OpenFSJournal(lr, journal.DefaultDisabledEvents); err == nil {
|
||||
journal.J = jrnl
|
||||
} else {
|
||||
return fmt.Errorf("failed to open filesystem journal: %w", err)
|
||||
}
|
||||
|
||||
m := miner.NewMiner(api, epp, a, slashfilter.New(mds))
|
||||
{
|
||||
if err := m.Start(ctx); err != nil {
|
||||
|
||||
@@ -5,16 +5,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
@@ -203,8 +200,8 @@ var provingInfoCmd = &cli.Command{
|
||||
fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch)
|
||||
|
||||
fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%miner.WPoStProvingPeriod)
|
||||
fmt.Printf("Proving Period Start: %s\n", epochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
fmt.Printf("Next Period Start: %s\n\n", epochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod))
|
||||
fmt.Printf("Proving Period Start: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart))
|
||||
fmt.Printf("Next Period Start: %s\n\n", lcli.EpochTime(cd.CurrentEpoch, cd.PeriodStart+miner.WPoStProvingPeriod))
|
||||
|
||||
fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc)
|
||||
fmt.Printf("Recovering: %d\n", recovering)
|
||||
@@ -224,27 +221,14 @@ var provingInfoCmd = &cli.Command{
|
||||
fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors)
|
||||
}
|
||||
|
||||
fmt.Printf("Deadline Open: %s\n", epochTime(cd.CurrentEpoch, cd.Open))
|
||||
fmt.Printf("Deadline Close: %s\n", epochTime(cd.CurrentEpoch, cd.Close))
|
||||
fmt.Printf("Deadline Challenge: %s\n", epochTime(cd.CurrentEpoch, cd.Challenge))
|
||||
fmt.Printf("Deadline FaultCutoff: %s\n", epochTime(cd.CurrentEpoch, cd.FaultCutoff))
|
||||
fmt.Printf("Deadline Open: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Open))
|
||||
fmt.Printf("Deadline Close: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Close))
|
||||
fmt.Printf("Deadline Challenge: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.Challenge))
|
||||
fmt.Printf("Deadline FaultCutoff: %s\n", lcli.EpochTime(cd.CurrentEpoch, cd.FaultCutoff))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func epochTime(curr, e abi.ChainEpoch) string {
|
||||
switch {
|
||||
case curr > e:
|
||||
return fmt.Sprintf("%d (%s ago)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(curr-e)))
|
||||
case curr == e:
|
||||
return fmt.Sprintf("%d (now)", e)
|
||||
case curr < e:
|
||||
return fmt.Sprintf("%d (in %s)", e, time.Second*time.Duration(int64(build.BlockDelaySecs)*int64(e-curr)))
|
||||
}
|
||||
|
||||
panic("math broke")
|
||||
}
|
||||
|
||||
var provingDeadlinesCmd = &cli.Command{
|
||||
Name: "deadlines",
|
||||
Usage: "View the current proving period deadlines information",
|
||||
|
||||
@@ -5,9 +5,12 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
|
||||
@@ -17,6 +20,8 @@ var retrievalDealsCmd = &cli.Command{
|
||||
Subcommands: []*cli.Command{
|
||||
retrievalDealSelectionCmd,
|
||||
retrievalDealsListCmd,
|
||||
retrievalSetAskCmd,
|
||||
retrievalGetAskCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -154,3 +159,112 @@ var retrievalDealsListCmd = &cli.Command{
|
||||
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()
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
+35
-10
@@ -64,6 +64,9 @@ const (
|
||||
// MethodAbortWith is the identifier for the method that panics optionally with
|
||||
// a passed exit code.
|
||||
MethodAbortWith
|
||||
// MethodInspectRuntime is the identifier for the method that returns the
|
||||
// current runtime values.
|
||||
MethodInspectRuntime
|
||||
)
|
||||
|
||||
// Exports defines the methods this actor exposes publicly.
|
||||
@@ -77,6 +80,7 @@ func (a Actor) Exports() []interface{} {
|
||||
MethodSend: a.Send,
|
||||
MethodMutateState: a.MutateState,
|
||||
MethodAbortWith: a.AbortWith,
|
||||
MethodInspectRuntime: a.InspectRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,18 +104,14 @@ type SendReturn struct {
|
||||
// passed parameters.
|
||||
func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
ret, code := rt.Send(
|
||||
var out runtime.CBORBytes
|
||||
code := rt.Send(
|
||||
args.To,
|
||||
args.Method,
|
||||
runtime.CBORBytes(args.Params),
|
||||
args.Value,
|
||||
&out,
|
||||
)
|
||||
var out runtime.CBORBytes
|
||||
if ret != nil {
|
||||
if err := ret.Into(&out); err != nil {
|
||||
rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err)
|
||||
}
|
||||
}
|
||||
return &SendReturn{
|
||||
Return: out,
|
||||
Code: code,
|
||||
@@ -217,14 +217,14 @@ func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *abi.Empty
|
||||
var st State
|
||||
switch args.Branch {
|
||||
case MutateInTransaction:
|
||||
rt.State().Transaction(&st, func() {
|
||||
rt.StateTransaction(&st, func() {
|
||||
st.Value = args.Value
|
||||
})
|
||||
case MutateReadonly:
|
||||
rt.State().Readonly(&st)
|
||||
rt.StateReadonly(&st)
|
||||
st.Value = args.Value
|
||||
case MutateAfterTransaction:
|
||||
rt.State().Transaction(&st, func() {
|
||||
rt.StateTransaction(&st, func() {
|
||||
st.Value = args.Value + "-in"
|
||||
})
|
||||
st.Value = args.Value
|
||||
@@ -251,3 +251,28 @@ func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValu
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
package chaos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/support/mock"
|
||||
atesting "github.com/filecoin-project/specs-actors/support/testing"
|
||||
)
|
||||
|
||||
func TestSingleton(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "constructor should not be called; the Chaos actor is a singleton actor"
|
||||
rt.ExpectAssertionFailure(msg, func() {
|
||||
rt.Call(a.Constructor, abi.Empty)
|
||||
})
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestDeleteActor(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
beneficiary := atesting.NewIDAddr(t, 101)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.ExpectDeleteActor(beneficiary)
|
||||
rt.Call(a.DeleteActor, &beneficiary)
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateInTransaction(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateInTransaction,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
if st.Value != val {
|
||||
t.Fatal("state was not updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateAfterTransaction(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateAfterTransaction,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
// state should be updated successfully _in_ the transaction but not outside
|
||||
if st.Value != val+"-in" {
|
||||
t.Fatal("state was not updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestMutateStateReadonly(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
rt.ExpectValidateCallerAny()
|
||||
rt.StateCreate(&State{})
|
||||
|
||||
val := "__mutstat test"
|
||||
rt.Call(a.MutateState, &MutateStateArgs{
|
||||
Value: val,
|
||||
Branch: MutateReadonly,
|
||||
})
|
||||
|
||||
var st State
|
||||
rt.GetState(&st)
|
||||
|
||||
if st.Value != "" {
|
||||
t.Fatal("state was not expected to be updated")
|
||||
}
|
||||
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestAbortWith(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "__test forbidden"
|
||||
rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() {
|
||||
rt.Call(a.AbortWith, &AbortWithArgs{
|
||||
Code: exitcode.ErrForbidden,
|
||||
Message: msg,
|
||||
Uncontrolled: false,
|
||||
})
|
||||
})
|
||||
rt.Verify()
|
||||
}
|
||||
|
||||
func TestAbortWithUncontrolled(t *testing.T) {
|
||||
receiver := atesting.NewIDAddr(t, 100)
|
||||
builder := mock.NewBuilder(context.Background(), receiver)
|
||||
|
||||
rt := builder.Build(t)
|
||||
var a Actor
|
||||
|
||||
msg := "__test uncontrolled panic"
|
||||
rt.ExpectAssertionFailure(msg, func() {
|
||||
rt.Call(a.AbortWith, &AbortWithArgs{
|
||||
Message: msg,
|
||||
Uncontrolled: true,
|
||||
})
|
||||
})
|
||||
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,10 +6,10 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
exitcode "github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
@@ -730,3 +730,145 @@ func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ func main() {
|
||||
chaos.SendReturn{},
|
||||
chaos.MutateStateArgs{},
|
||||
chaos.AbortWithArgs{},
|
||||
chaos.InspectRuntimeReturn{},
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -148,6 +148,7 @@
|
||||
* [StateMinerRecoveries](#StateMinerRecoveries)
|
||||
* [StateMinerSectorCount](#StateMinerSectorCount)
|
||||
* [StateMinerSectors](#StateMinerSectors)
|
||||
* [StateMsgGasCost](#StateMsgGasCost)
|
||||
* [StateNetworkName](#StateNetworkName)
|
||||
* [StateReadState](#StateReadState)
|
||||
* [StateReplay](#StateReplay)
|
||||
@@ -211,7 +212,7 @@ Response:
|
||||
```json
|
||||
{
|
||||
"Version": "string value",
|
||||
"APIVersion": 3584,
|
||||
"APIVersion": 3840,
|
||||
"BlockDelay": 42
|
||||
}
|
||||
```
|
||||
@@ -284,6 +285,7 @@ ChainExport returns a stream of bytes with CAR dump of chain data.
|
||||
The exported chain data includes the header chain from the given tipset
|
||||
back to genesis, the entire genesis state, and the most recent 'nroots'
|
||||
state trees.
|
||||
If oldmsgskip is set, messages from before the requested roots are also not included.
|
||||
|
||||
|
||||
Perms: read
|
||||
@@ -292,6 +294,7 @@ Inputs:
|
||||
```json
|
||||
[
|
||||
10101,
|
||||
true,
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
@@ -2373,7 +2376,12 @@ There are not yet any comments for this method.
|
||||
|
||||
Perms: sign
|
||||
|
||||
Inputs: `null`
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234"
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
@@ -2397,6 +2405,7 @@ Perms: sign
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
"t01234",
|
||||
"t01234"
|
||||
]
|
||||
```
|
||||
@@ -3729,6 +3738,45 @@ Inputs:
|
||||
|
||||
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 returns the name of the network the node is synced to
|
||||
|
||||
|
||||
+1
Submodule extern/fil-blst added at 5f93488fc0
Vendored
+1
-1
Submodule extern/filecoin-ffi updated: 4056910460...f640612a1a
+1
Submodule extern/oni added at 8b7e7d438c
+51
-46
@@ -168,50 +168,34 @@ func (s *seal) unseal(t *testing.T, sb *Sealer, sp *basicfs.Provider, si abi.Sec
|
||||
}
|
||||
}
|
||||
|
||||
func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time {
|
||||
/*randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7}
|
||||
func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) {
|
||||
randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7}
|
||||
|
||||
sis := make([]abi.SectorInfo, len(seals))
|
||||
sis := make([]saproof.SectorInfo, len(seals))
|
||||
for i, s := range seals {
|
||||
sis[i] = abi.SectorInfo{
|
||||
RegisteredProof: sealProofType,
|
||||
SectorNumber: s.id.Number,
|
||||
SealedCID: s.cids.Sealed,
|
||||
sis[i] = saproof.SectorInfo{
|
||||
SealProof: sealProofType,
|
||||
SectorNumber: s.id.Number,
|
||||
SealedCID: s.cids.Sealed,
|
||||
}
|
||||
}
|
||||
|
||||
candidates, err := sealer.GenerateEPostCandidates(context.TODO(), seals[0].id.Miner, sis, randomness, []abi.SectorNumber{})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}*/
|
||||
|
||||
fmt.Println("skipping post")
|
||||
|
||||
genCandidates := time.Now()
|
||||
|
||||
/*if len(candidates) != 1 {
|
||||
t.Fatal("expected 1 candidate")
|
||||
proofs, skp, err := sealer.GenerateWindowPoSt(context.TODO(), seals[0].id.Miner, sis, randomness)
|
||||
if len(skipped) > 0 {
|
||||
require.Error(t, err)
|
||||
require.EqualValues(t, skipped, skp)
|
||||
return
|
||||
}
|
||||
|
||||
candidatesPrime := make([]abi.PoStCandidate, len(candidates))
|
||||
for idx := range candidatesPrime {
|
||||
candidatesPrime[idx] = candidates[idx].Candidate
|
||||
}
|
||||
|
||||
proofs, err := sealer.ComputeElectionPoSt(context.TODO(), seals[0].id.Miner, sis, randomness, candidatesPrime)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
ePoStChallengeCount := ElectionPostChallengeCount(uint64(len(sis)), 0)
|
||||
|
||||
ok, err := ProofVerifier.VerifyElectionPost(context.TODO(), abi.PoStVerifyInfo{
|
||||
Randomness: randomness,
|
||||
Candidates: candidatesPrime,
|
||||
Proofs: proofs,
|
||||
EligibleSectors: sis,
|
||||
Prover: seals[0].id.Miner,
|
||||
ChallengeCount: ePoStChallengeCount,
|
||||
ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{
|
||||
Randomness: randomness,
|
||||
Proofs: proofs,
|
||||
ChallengedSectors: sis,
|
||||
Prover: seals[0].id.Miner,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@@ -219,8 +203,21 @@ func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time {
|
||||
if !ok {
|
||||
t.Fatal("bad post")
|
||||
}
|
||||
*/
|
||||
return genCandidates
|
||||
}
|
||||
|
||||
func corrupt(t *testing.T, sealer *Sealer, id abi.SectorID) {
|
||||
paths, done, err := sealer.sectors.AcquireSector(context.Background(), id, stores.FTSealed, 0, stores.PathStorage)
|
||||
require.NoError(t, err)
|
||||
defer done()
|
||||
|
||||
log.Infof("corrupt %s", paths.Sealed)
|
||||
f, err := os.OpenFile(paths.Sealed, os.O_RDWR, 0664)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = f.WriteAt(bytes.Repeat([]byte{'d'}, 2048), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, f.Close())
|
||||
}
|
||||
|
||||
func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) {
|
||||
@@ -299,11 +296,11 @@ func TestSealAndVerify(t *testing.T) {
|
||||
|
||||
commit := time.Now()
|
||||
|
||||
genCandidiates := post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
epost := time.Now()
|
||||
|
||||
post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
@@ -313,8 +310,7 @@ func TestSealAndVerify(t *testing.T) {
|
||||
|
||||
fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String())
|
||||
fmt.Printf("Commit: %s\n", commit.Sub(precommit).String())
|
||||
fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(commit).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(commit).String())
|
||||
}
|
||||
|
||||
func TestSealPoStNoCommit(t *testing.T) {
|
||||
@@ -370,16 +366,15 @@ func TestSealPoStNoCommit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
genCandidiates := post(t, sb, s)
|
||||
post(t, sb, nil, s)
|
||||
|
||||
epost := time.Now()
|
||||
|
||||
fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String())
|
||||
fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(precommit).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String())
|
||||
fmt.Printf("EPoSt: %s\n", epost.Sub(precommit).String())
|
||||
}
|
||||
|
||||
func TestSealAndVerify2(t *testing.T) {
|
||||
func TestSealAndVerify3(t *testing.T) {
|
||||
defer requireFDsClosed(t, openFDs(t))
|
||||
|
||||
if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware
|
||||
@@ -419,22 +414,32 @@ func TestSealAndVerify2(t *testing.T) {
|
||||
|
||||
si1 := abi.SectorID{Miner: miner, Number: 1}
|
||||
si2 := abi.SectorID{Miner: miner, Number: 2}
|
||||
si3 := abi.SectorID{Miner: miner, Number: 3}
|
||||
|
||||
s1 := seal{id: si1}
|
||||
s2 := seal{id: si2}
|
||||
s3 := seal{id: si3}
|
||||
|
||||
wg.Add(2)
|
||||
wg.Add(3)
|
||||
go s1.precommit(t, sb, si1, wg.Done) //nolint: staticcheck
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
go s2.precommit(t, sb, si2, wg.Done) //nolint: staticcheck
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
go s3.precommit(t, sb, si3, wg.Done) //nolint: staticcheck
|
||||
wg.Wait()
|
||||
|
||||
wg.Add(2)
|
||||
wg.Add(3)
|
||||
go s1.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
go s2.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
go s3.commit(t, sb, wg.Done) //nolint: staticcheck
|
||||
wg.Wait()
|
||||
|
||||
post(t, sb, s1, s2)
|
||||
post(t, sb, nil, s1, s2, s3)
|
||||
|
||||
corrupt(t, sb, si1)
|
||||
corrupt(t, sb, si2)
|
||||
|
||||
post(t, sb, []abi.SectorID{si1, si2}, s1, s2, s3)
|
||||
}
|
||||
|
||||
func BenchmarkWriteWithAlignment(b *testing.B) {
|
||||
|
||||
+15
-2
@@ -40,8 +40,21 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s
|
||||
}
|
||||
defer done()
|
||||
|
||||
proof, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness)
|
||||
return proof, skipped, err
|
||||
if len(skipped) > 0 {
|
||||
return nil, skipped, xerrors.Errorf("pubSectorToPriv skipped some sectors")
|
||||
}
|
||||
|
||||
proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness)
|
||||
|
||||
var faultyIDs []abi.SectorID
|
||||
for _, f := range faulty {
|
||||
faultyIDs = append(faultyIDs, abi.SectorID{
|
||||
Miner: minerID,
|
||||
Number: f,
|
||||
})
|
||||
}
|
||||
|
||||
return proof, faultyIDs, err
|
||||
}
|
||||
|
||||
func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) {
|
||||
|
||||
Vendored
+30
-14
@@ -203,25 +203,26 @@ func schedFetch(sector abi.SectorID, ft stores.SectorFileType, ptype stores.Path
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, ticket abi.SealRandomness, unsealed cid.Cid) error {
|
||||
func (m *Manager) tryReadUnsealedPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) (foundUnsealed bool, readOk bool, selector WorkerSelector, returnErr error) {
|
||||
|
||||
// acquire a lock purely for reading unsealed sectors
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTSealed|stores.FTCache, stores.FTUnsealed); err != nil {
|
||||
return xerrors.Errorf("acquiring sector lock: %w", err)
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTUnsealed, stores.FTNone); err != nil {
|
||||
returnErr = xerrors.Errorf("acquiring read sector lock: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// passing 0 spt because we only need it when allowFetch is true
|
||||
best, err := m.index.StorageFindSector(ctx, sector, stores.FTUnsealed, 0, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err)
|
||||
returnErr = xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
var readOk bool
|
||||
var selector WorkerSelector
|
||||
if len(best) == 0 { // new
|
||||
selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing)
|
||||
} else { // append to existing
|
||||
foundUnsealed = len(best) > 0
|
||||
if foundUnsealed { // append to existing
|
||||
// There is unsealed sector, see if we can read from it
|
||||
|
||||
selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false)
|
||||
@@ -231,12 +232,27 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading piece from sealed sector: %w", err)
|
||||
returnErr = xerrors.Errorf("reading piece from sealed sector: %w", err)
|
||||
}
|
||||
} else {
|
||||
selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if readOk {
|
||||
return nil
|
||||
}
|
||||
func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.SectorID, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, ticket abi.SealRandomness, unsealed cid.Cid) error {
|
||||
foundUnsealed, readOk, selector, err := m.tryReadUnsealedPiece(ctx, sink, sector, offset, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if readOk {
|
||||
return nil
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := m.index.StorageLock(ctx, sector, stores.FTSealed|stores.FTCache, stores.FTUnsealed); err != nil {
|
||||
return xerrors.Errorf("acquiring unseal sector lock: %w", err)
|
||||
}
|
||||
|
||||
unsealFetch := func(ctx context.Context, worker Worker) error {
|
||||
@@ -244,7 +260,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect
|
||||
return xerrors.Errorf("copy sealed/cache sector data: %w", err)
|
||||
}
|
||||
|
||||
if len(best) > 0 {
|
||||
if foundUnsealed {
|
||||
if err := worker.Fetch(ctx, sector, stores.FTUnsealed, stores.PathSealing, stores.AcquireMove); err != nil {
|
||||
return xerrors.Errorf("copy unsealed sector data: %w", err)
|
||||
}
|
||||
|
||||
Vendored
+23
-3
@@ -66,8 +66,9 @@ const (
|
||||
)
|
||||
|
||||
type sectorState struct {
|
||||
pieces []cid.Cid
|
||||
failed bool
|
||||
pieces []cid.Cid
|
||||
failed bool
|
||||
corrupted bool
|
||||
|
||||
state int
|
||||
|
||||
@@ -251,6 +252,18 @@ func (mgr *SectorMgr) MarkFailed(sid abi.SectorID, failed bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgr *SectorMgr) MarkCorrupted(sid abi.SectorID, corrupted bool) error {
|
||||
mgr.lk.Lock()
|
||||
defer mgr.lk.Unlock()
|
||||
ss, ok := mgr.sectors[sid]
|
||||
if !ok {
|
||||
return fmt.Errorf("no such sector in storage")
|
||||
}
|
||||
|
||||
ss.corrupted = corrupted
|
||||
return nil
|
||||
}
|
||||
|
||||
func opFinishWait(ctx context.Context) {
|
||||
val, ok := ctx.Value("opfinish").(chan struct{})
|
||||
if !ok {
|
||||
@@ -275,6 +288,8 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI
|
||||
si := make([]proof.SectorInfo, 0, len(sectorInfo))
|
||||
var skipped []abi.SectorID
|
||||
|
||||
var err error
|
||||
|
||||
for _, info := range sectorInfo {
|
||||
sid := abi.SectorID{
|
||||
Miner: minerID,
|
||||
@@ -283,13 +298,18 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI
|
||||
|
||||
_, found := mgr.sectors[sid]
|
||||
|
||||
if found && !mgr.sectors[sid].failed {
|
||||
if found && !mgr.sectors[sid].failed && !mgr.sectors[sid].corrupted {
|
||||
si = append(si, info)
|
||||
} else {
|
||||
skipped = append(skipped, sid)
|
||||
err = xerrors.Errorf("skipped some sectors")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, skipped, err
|
||||
}
|
||||
|
||||
return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+6
@@ -189,6 +189,12 @@ func (m *Sealing) plan(events []statemachine.Event, state *SectorInfo) (func(sta
|
||||
state.Log = append(state.Log, l)
|
||||
}
|
||||
|
||||
if m.notifee != nil {
|
||||
defer func(before SectorInfo) {
|
||||
m.notifee(before, *state)
|
||||
}(*state) // take safe-ish copy of the before state (except for nested pointers)
|
||||
}
|
||||
|
||||
p := fsmPlanners[state.State]
|
||||
if p == nil {
|
||||
return nil, 0, xerrors.Errorf("planner for state %s not found", state.State)
|
||||
|
||||
Vendored
+14
@@ -27,6 +27,7 @@ type test struct {
|
||||
}
|
||||
|
||||
func TestHappyPath(t *testing.T) {
|
||||
var notif []struct{ before, after SectorInfo }
|
||||
ma, _ := address.NewIDAddress(55151)
|
||||
m := test{
|
||||
s: &Sealing{
|
||||
@@ -34,6 +35,9 @@ func TestHappyPath(t *testing.T) {
|
||||
stats: SectorStats{
|
||||
bySector: map[abi.SectorID]statSectorState{},
|
||||
},
|
||||
notifee: func(before, after SectorInfo) {
|
||||
notif = append(notif, struct{ before, after SectorInfo }{before, after})
|
||||
},
|
||||
},
|
||||
t: t,
|
||||
state: &SectorInfo{State: Packing},
|
||||
@@ -68,6 +72,16 @@ func TestHappyPath(t *testing.T) {
|
||||
|
||||
m.planSingle(SectorFinalized{})
|
||||
require.Equal(m.t, m.state.State, Proving)
|
||||
|
||||
expected := []SectorState{Packing, PreCommit1, PreCommit2, PreCommitting, PreCommitWait, WaitSeed, Committing, SubmitCommit, CommitWait, FinalizeSector, Proving}
|
||||
for i, n := range notif {
|
||||
if n.before.State != expected[i] {
|
||||
t.Fatalf("expected before state: %s, got: %s", expected[i], n.before.State)
|
||||
}
|
||||
if n.after.State != expected[i+1] {
|
||||
t.Fatalf("expected after state: %s, got: %s", expected[i+1], n.after.State)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedRevert(t *testing.T) {
|
||||
|
||||
Vendored
+11
-2
@@ -28,6 +28,8 @@ import (
|
||||
|
||||
const SectorStorePrefix = "/sectors"
|
||||
|
||||
var ErrTooManySectorsSealing = xerrors.New("too many sectors sealing")
|
||||
|
||||
var log = logging.Logger("sectors")
|
||||
|
||||
type SectorLocation struct {
|
||||
@@ -59,6 +61,8 @@ type SealingAPI interface {
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
}
|
||||
|
||||
type SectorStateNotifee func(before, after SectorInfo)
|
||||
|
||||
type Sealing struct {
|
||||
api SealingAPI
|
||||
feeCfg FeeConfig
|
||||
@@ -77,6 +81,8 @@ type Sealing struct {
|
||||
upgradeLk sync.Mutex
|
||||
toUpgrade map[abi.SectorNumber]struct{}
|
||||
|
||||
notifee SectorStateNotifee
|
||||
|
||||
stats SectorStats
|
||||
|
||||
getConfig GetSealingConfigFunc
|
||||
@@ -99,7 +105,7 @@ type UnsealedSectorInfo struct {
|
||||
pieceSizes []abi.UnpaddedPieceSize
|
||||
}
|
||||
|
||||
func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gc GetSealingConfigFunc) *Sealing {
|
||||
func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds datastore.Batching, sealer sectorstorage.SectorManager, sc SectorIDCounter, verif ffiwrapper.Verifier, pcp PreCommitPolicy, gc GetSealingConfigFunc, notifee SectorStateNotifee) *Sealing {
|
||||
s := &Sealing{
|
||||
api: api,
|
||||
feeCfg: fc,
|
||||
@@ -116,6 +122,9 @@ func New(api SealingAPI, fc FeeConfig, events Events, maddr address.Address, ds
|
||||
},
|
||||
|
||||
toUpgrade: map[abi.SectorNumber]struct{}{},
|
||||
|
||||
notifee: notifee,
|
||||
|
||||
getConfig: gc,
|
||||
|
||||
stats: SectorStats{
|
||||
@@ -280,7 +289,7 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) {
|
||||
|
||||
if cfg.MaxSealingSectorsForDeals > 0 {
|
||||
if m.stats.curSealing() > cfg.MaxSealingSectorsForDeals {
|
||||
return 0, xerrors.Errorf("too many sectors sealing")
|
||||
return 0, ErrTooManySectorsSealing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -67,6 +67,8 @@ func (m *Sealing) tryUpgradeSector(ctx context.Context, params *miner.SectorPreC
|
||||
params.ReplaceSectorDeadline = loc.Deadline
|
||||
params.ReplaceSectorPartition = loc.Partition
|
||||
|
||||
log.Infof("replacing sector %d with %d", *replace, params.SectorNumber)
|
||||
|
||||
ri, err := m.api.StateSectorGetInfo(ctx, m.maddr, *replace, nil)
|
||||
if err != nil {
|
||||
log.Errorf("error calling StateSectorGetInfo for replaced sector: %+v", err)
|
||||
|
||||
@@ -2,8 +2,6 @@ module github.com/filecoin-project/lotus
|
||||
|
||||
go 1.14
|
||||
|
||||
replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1
|
||||
|
||||
require (
|
||||
contrib.go.opencensus.io/exporter/jaeger v0.1.0
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.1.0
|
||||
@@ -15,7 +13,7 @@ require (
|
||||
github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
|
||||
github.com/coreos/go-systemd/v22 v22.0.0
|
||||
github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e
|
||||
github.com/dgraph-io/badger/v2 v2.0.3
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32
|
||||
github.com/drand/kyber v1.1.2
|
||||
@@ -27,18 +25,18 @@ require (
|
||||
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-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-markets v0.6.0
|
||||
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-multistore v0.0.3
|
||||
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20
|
||||
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370
|
||||
github.com/filecoin-project/go-statestore v0.1.0
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b
|
||||
github.com/filecoin-project/specs-actors v0.9.8
|
||||
github.com/filecoin-project/specs-actors v0.9.10
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.1
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
@@ -135,6 +133,8 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v
|
||||
|
||||
replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi
|
||||
|
||||
replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794
|
||||
|
||||
replace github.com/filecoin-project/test-vectors => ./extern/test-vectors
|
||||
|
||||
replace github.com/supranational/blst => ./extern/fil-blst/blst
|
||||
|
||||
replace github.com/filecoin-project/fil-blst => ./extern/fil-blst
|
||||
|
||||
@@ -91,7 +91,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0=
|
||||
github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
|
||||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
@@ -167,8 +166,10 @@ github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhY
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg=
|
||||
github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU=
|
||||
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 h1:PIPH4SLjYXMMlX/cQqV7nIRatv7556yqUfWY+KBjrtQ=
|
||||
github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
@@ -221,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-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-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGRR+LwqM8jmlZqgWuUfY=
|
||||
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 h1:Q08ABa+cOTOLoAyHeA94fPLcwu53p6eeAaxMxQb0m0A=
|
||||
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/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q=
|
||||
github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw=
|
||||
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/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/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
|
||||
github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0=
|
||||
@@ -239,10 +240,9 @@ github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h
|
||||
github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c h1:HHRMFpU8OrODDUja5NmGWNBAVGoSy4MRjxgZa+a0qIw=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc h1:1vr/LoqGq5m5g37Q3sNSAjfwF1uJY0zmiHcvnxY6hik=
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20200911004822-964d6c679cfc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c=
|
||||
github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||
@@ -251,10 +251,9 @@ github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZO
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg=
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8=
|
||||
github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4=
|
||||
github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8=
|
||||
github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU=
|
||||
github.com/filecoin-project/specs-actors v0.9.8 h1:45fnx/BsseFL3CtvSoR6CszFY26TFtsh9AHwCW2vkg8=
|
||||
github.com/filecoin-project/specs-actors v0.9.8/go.mod h1:xFObDoWPySBNTNBrGXVVrutmgSZH/mMo46Q1bec/0hw=
|
||||
github.com/filecoin-project/specs-actors v0.9.10 h1:gU0TrRhgkCsBEOP42sGDE7RQuR0Cov9hJhBqq+RJmjU=
|
||||
github.com/filecoin-project/specs-actors v0.9.10/go.mod h1:czlvLQGEX0fjLLfdNHD7xLymy6L3n7aQzRWzsYGf+ys=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus=
|
||||
@@ -504,7 +503,6 @@ github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28
|
||||
github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE=
|
||||
github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg=
|
||||
github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA=
|
||||
github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk=
|
||||
github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08=
|
||||
github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw=
|
||||
@@ -1323,8 +1321,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg=
|
||||
github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
const RFC3339nocolon = "2006-01-02T150405Z0700"
|
||||
|
||||
// fsJournal is a basic journal backed by files on a filesystem.
|
||||
type fsJournal struct {
|
||||
EventTypeRegistry
|
||||
|
||||
dir string
|
||||
sizeLimit int64
|
||||
|
||||
fi *os.File
|
||||
fSize int64
|
||||
|
||||
incoming chan *Event
|
||||
|
||||
closing chan struct{}
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
// OpenFSJournal constructs a rolling filesystem journal, with a default
|
||||
// per-file size limit of 1GiB.
|
||||
func OpenFSJournal(lr repo.LockedRepo, disabled DisabledEvents) (Journal, error) {
|
||||
dir := filepath.Join(lr.Path(), "journal")
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to mk directory %s for file journal: %w", dir, err)
|
||||
}
|
||||
|
||||
f := &fsJournal{
|
||||
EventTypeRegistry: NewEventTypeRegistry(disabled),
|
||||
dir: dir,
|
||||
sizeLimit: 1 << 30,
|
||||
incoming: make(chan *Event, 32),
|
||||
closing: make(chan struct{}),
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
|
||||
if err := f.rollJournalFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go f.runLoop()
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) RecordEvent(evtType EventType, supplier func() interface{}) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Warnf("recovered from panic while recording journal event; type=%s, err=%v", evtType, r)
|
||||
}
|
||||
}()
|
||||
|
||||
if !evtType.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
je := &Event{
|
||||
EventType: evtType,
|
||||
Timestamp: build.Clock.Now(),
|
||||
Data: supplier(),
|
||||
}
|
||||
select {
|
||||
case f.incoming <- je:
|
||||
case <-f.closing:
|
||||
log.Warnw("journal closed but tried to log event", "event", je)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fsJournal) Close() error {
|
||||
close(f.closing)
|
||||
<-f.closed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) putEvent(evt *Event) error {
|
||||
b, err := json.Marshal(evt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := f.fi.Write(append(b, '\n'))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.fSize += int64(n)
|
||||
|
||||
if f.fSize >= f.sizeLimit {
|
||||
_ = f.rollJournalFile()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) rollJournalFile() error {
|
||||
if f.fi != nil {
|
||||
_ = f.fi.Close()
|
||||
}
|
||||
|
||||
nfi, err := os.Create(filepath.Join(f.dir, fmt.Sprintf("lotus-journal-%s.ndjson", build.Clock.Now().Format(RFC3339nocolon))))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open journal file: %w", err)
|
||||
}
|
||||
|
||||
f.fi = nfi
|
||||
f.fSize = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fsJournal) runLoop() {
|
||||
defer close(f.closed)
|
||||
|
||||
for {
|
||||
select {
|
||||
case je := <-f.incoming:
|
||||
if err := f.putEvent(je); err != nil {
|
||||
log.Errorw("failed to write out journal event", "event", je, "err", err)
|
||||
}
|
||||
case <-f.closing:
|
||||
_ = f.fi.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package journal
|
||||
|
||||
var (
|
||||
// J is a globally accessible Journal. It starts being NilJournal, and early
|
||||
// during the Lotus initialization routine, it is reset to whichever Journal
|
||||
// is configured (by default, the filesystem journal). Components can safely
|
||||
// record in the journal by calling: journal.J.RecordEvent(...).
|
||||
J Journal = NilJournal() // nolint
|
||||
)
|
||||
@@ -1,152 +0,0 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
func InitializeSystemJournal(dir string) error {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
j, err := OpenFSJournal(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentJournal = j
|
||||
return nil
|
||||
}
|
||||
|
||||
func Add(sys string, val interface{}) {
|
||||
if currentJournal == nil {
|
||||
log.Warn("no journal configured")
|
||||
return
|
||||
}
|
||||
currentJournal.AddEntry(sys, val)
|
||||
}
|
||||
|
||||
var log = logging.Logger("journal")
|
||||
|
||||
var currentJournal Journal
|
||||
|
||||
type Journal interface {
|
||||
AddEntry(system string, obj interface{})
|
||||
Close() error
|
||||
}
|
||||
|
||||
// fsJournal is a basic journal backed by files on a filesystem
|
||||
type fsJournal struct {
|
||||
fi *os.File
|
||||
fSize int64
|
||||
|
||||
journalDir string
|
||||
|
||||
incoming chan *JournalEntry
|
||||
journalSizeLimit int64
|
||||
|
||||
closing chan struct{}
|
||||
}
|
||||
|
||||
func OpenFSJournal(dir string) (Journal, error) {
|
||||
fsj := &fsJournal{
|
||||
journalDir: dir,
|
||||
incoming: make(chan *JournalEntry, 32),
|
||||
journalSizeLimit: 1 << 30,
|
||||
closing: make(chan struct{}),
|
||||
}
|
||||
|
||||
if err := fsj.rollJournalFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go fsj.runLoop()
|
||||
|
||||
return fsj, nil
|
||||
}
|
||||
|
||||
type JournalEntry struct {
|
||||
System string
|
||||
Timestamp time.Time
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) putEntry(je *JournalEntry) error {
|
||||
b, err := json.Marshal(je)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := fsj.fi.Write(append(b, '\n'))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fsj.fSize += int64(n)
|
||||
|
||||
if fsj.fSize >= fsj.journalSizeLimit {
|
||||
return fsj.rollJournalFile()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const RFC3339nocolon = "2006-01-02T150405Z0700"
|
||||
|
||||
func (fsj *fsJournal) rollJournalFile() error {
|
||||
if fsj.fi != nil {
|
||||
err := fsj.fi.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
nfi, err := os.Create(filepath.Join(fsj.journalDir, fmt.Sprintf("lotus-journal-%s.ndjson", build.Clock.Now().Format(RFC3339nocolon))))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open journal file: %w", err)
|
||||
}
|
||||
|
||||
fsj.fi = nfi
|
||||
fsj.fSize = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) runLoop() {
|
||||
for {
|
||||
select {
|
||||
case je := <-fsj.incoming:
|
||||
if err := fsj.putEntry(je); err != nil {
|
||||
log.Errorw("failed to write out journal entry", "entry", je, "err", err)
|
||||
}
|
||||
case <-fsj.closing:
|
||||
if err := fsj.fi.Close(); err != nil {
|
||||
log.Errorw("failed to close journal", "err", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) AddEntry(system string, obj interface{}) {
|
||||
je := &JournalEntry{
|
||||
System: system,
|
||||
Timestamp: build.Clock.Now(),
|
||||
Val: obj,
|
||||
}
|
||||
select {
|
||||
case fsj.incoming <- je:
|
||||
case <-fsj.closing:
|
||||
log.Warnw("journal closed but tried to log event", "entry", je)
|
||||
}
|
||||
}
|
||||
|
||||
func (fsj *fsJournal) Close() error {
|
||||
close(fsj.closing)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package journal
|
||||
|
||||
type nilJournal struct{}
|
||||
|
||||
// nilj is a singleton nil journal.
|
||||
var nilj Journal = &nilJournal{}
|
||||
|
||||
func NilJournal() Journal {
|
||||
return nilj
|
||||
}
|
||||
|
||||
func (n *nilJournal) RegisterEventType(_, _ string) EventType { return EventType{} }
|
||||
|
||||
func (n *nilJournal) RecordEvent(_ EventType, _ func() interface{}) {}
|
||||
|
||||
func (n *nilJournal) Close() error { return nil }
|
||||
@@ -0,0 +1,57 @@
|
||||
package journal
|
||||
|
||||
import "sync"
|
||||
|
||||
// EventTypeRegistry is a component that constructs tracked EventType tokens,
|
||||
// for usage with a Journal.
|
||||
type EventTypeRegistry interface {
|
||||
|
||||
// RegisterEventType introduces a new event type to a journal, and
|
||||
// returns an EventType token that components can later use to check whether
|
||||
// journalling for that type is enabled/suppressed, and to tag journal
|
||||
// entries appropriately.
|
||||
RegisterEventType(system, event string) EventType
|
||||
}
|
||||
|
||||
// eventTypeRegistry is an embeddable mixin that takes care of tracking disabled
|
||||
// event types, and returning initialized/safe EventTypes when requested.
|
||||
type eventTypeRegistry struct {
|
||||
sync.Mutex
|
||||
|
||||
m map[string]EventType
|
||||
}
|
||||
|
||||
var _ EventTypeRegistry = (*eventTypeRegistry)(nil)
|
||||
|
||||
func NewEventTypeRegistry(disabled DisabledEvents) EventTypeRegistry {
|
||||
ret := &eventTypeRegistry{
|
||||
m: make(map[string]EventType, len(disabled)+32), // + extra capacity.
|
||||
}
|
||||
|
||||
for _, et := range disabled {
|
||||
et.enabled, et.safe = false, true
|
||||
ret.m[et.System+":"+et.Event] = et
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (d *eventTypeRegistry) RegisterEventType(system, event string) EventType {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
key := system + ":" + event
|
||||
if et, ok := d.m[key]; ok {
|
||||
return et
|
||||
}
|
||||
|
||||
et := EventType{
|
||||
System: system,
|
||||
Event: event,
|
||||
enabled: true,
|
||||
safe: true,
|
||||
}
|
||||
|
||||
d.m[key] = et
|
||||
return et
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDisabledEvents(t *testing.T) {
|
||||
req := require.New(t)
|
||||
|
||||
test := func(dis DisabledEvents) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
registry := NewEventTypeRegistry(dis)
|
||||
|
||||
reg1 := registry.RegisterEventType("system1", "disabled1")
|
||||
reg2 := registry.RegisterEventType("system2", "disabled2")
|
||||
|
||||
req.False(reg1.Enabled())
|
||||
req.False(reg2.Enabled())
|
||||
req.True(reg1.safe)
|
||||
req.True(reg2.safe)
|
||||
|
||||
reg3 := registry.RegisterEventType("system3", "enabled3")
|
||||
req.True(reg3.Enabled())
|
||||
req.True(reg3.safe)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("direct", test(DisabledEvents{
|
||||
EventType{System: "system1", Event: "disabled1"},
|
||||
EventType{System: "system2", Event: "disabled2"},
|
||||
}))
|
||||
|
||||
dis, err := ParseDisabledEvents("system1:disabled1,system2:disabled2")
|
||||
req.NoError(err)
|
||||
|
||||
t.Run("parsed", test(dis))
|
||||
|
||||
dis, err = ParseDisabledEvents(" system1:disabled1 , system2:disabled2 ")
|
||||
req.NoError(err)
|
||||
|
||||
t.Run("parsed_spaces", test(dis))
|
||||
}
|
||||
|
||||
func TestParseDisableEvents(t *testing.T) {
|
||||
_, err := ParseDisabledEvents("system1:disabled1:failed,system2:disabled2")
|
||||
require.Error(t, err)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
)
|
||||
|
||||
var log = logging.Logger("journal")
|
||||
|
||||
var (
|
||||
// DefaultDisabledEvents lists the journal events disabled by
|
||||
// default, usually because they are considered noisy.
|
||||
DefaultDisabledEvents = DisabledEvents{
|
||||
EventType{System: "mpool", Event: "add"},
|
||||
EventType{System: "mpool", Event: "remove"},
|
||||
}
|
||||
)
|
||||
|
||||
// DisabledEvents is the set of event types whose journaling is suppressed.
|
||||
type DisabledEvents []EventType
|
||||
|
||||
// ParseDisabledEvents parses a string of the form: "system1:event1,system2:event2[,...]"
|
||||
// into a DisabledEvents object, returning an error if the string failed to parse.
|
||||
//
|
||||
// It sanitizes strings via strings.TrimSpace.
|
||||
func ParseDisabledEvents(s string) (DisabledEvents, error) {
|
||||
s = strings.TrimSpace(s) // sanitize
|
||||
evts := strings.Split(s, ",")
|
||||
ret := make(DisabledEvents, 0, len(evts))
|
||||
for _, evt := range evts {
|
||||
evt = strings.TrimSpace(evt) // sanitize
|
||||
s := strings.Split(evt, ":")
|
||||
if len(s) != 2 {
|
||||
return nil, fmt.Errorf("invalid event type: %s", s)
|
||||
}
|
||||
ret = append(ret, EventType{System: s[0], Event: s[1]})
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// EventType represents the signature of an event.
|
||||
type EventType struct {
|
||||
System string
|
||||
Event string
|
||||
|
||||
// enabled stores whether this event type is enabled.
|
||||
enabled bool
|
||||
|
||||
// safe is a sentinel marker that's set to true if this EventType was
|
||||
// constructed correctly (via Journal#RegisterEventType).
|
||||
safe bool
|
||||
}
|
||||
|
||||
func (et EventType) String() string {
|
||||
return et.System + ":" + et.Event
|
||||
}
|
||||
|
||||
// Enabled returns whether this event type is enabled in the journaling
|
||||
// subsystem. Users are advised to check this before actually attempting to
|
||||
// add a journal entry, as it helps bypass object construction for events that
|
||||
// would be discarded anyway.
|
||||
//
|
||||
// All event types are enabled by default, and specific event types can only
|
||||
// be disabled at Journal construction time.
|
||||
func (et EventType) Enabled() bool {
|
||||
return et.safe && et.enabled
|
||||
}
|
||||
|
||||
// Journal represents an audit trail of system actions.
|
||||
//
|
||||
// Every entry is tagged with a timestamp, a system name, and an event name.
|
||||
// The supplied data can be any type, as long as it is JSON serializable,
|
||||
// including structs, map[string]interface{}, or primitive types.
|
||||
//
|
||||
// For cleanliness and type safety, we recommend to use typed events. See the
|
||||
// *Evt struct types in this package for more info.
|
||||
type Journal interface {
|
||||
EventTypeRegistry
|
||||
|
||||
// RecordEvent records this event to the journal, if and only if the
|
||||
// EventType is enabled. If so, it calls the supplier function to obtain
|
||||
// the payload to record.
|
||||
//
|
||||
// Implementations MUST recover from panics raised by the supplier function.
|
||||
RecordEvent(evtType EventType, supplier func() interface{})
|
||||
|
||||
// Close closes this journal for further writing.
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Event represents a journal entry.
|
||||
//
|
||||
// See godocs on Journal for more information.
|
||||
type Event struct {
|
||||
EventType
|
||||
|
||||
Timestamp time.Time
|
||||
Data interface{}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package markets
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
)
|
||||
|
||||
type StorageClientEvt struct {
|
||||
Event string
|
||||
Deal storagemarket.ClientDeal
|
||||
}
|
||||
|
||||
type StorageProviderEvt struct {
|
||||
Event string
|
||||
Deal storagemarket.MinerDeal
|
||||
}
|
||||
|
||||
type RetrievalClientEvt struct {
|
||||
Event string
|
||||
Deal retrievalmarket.ClientDealState
|
||||
}
|
||||
|
||||
type RetrievalProviderEvt struct {
|
||||
Event string
|
||||
Deal retrievalmarket.ProviderDealState
|
||||
}
|
||||
|
||||
// StorageClientJournaler records journal events from the storage client.
|
||||
func StorageClientJournaler(evtType journal.EventType) func(event storagemarket.ClientEvent, deal storagemarket.ClientDeal) {
|
||||
return func(event storagemarket.ClientEvent, deal storagemarket.ClientDeal) {
|
||||
journal.J.RecordEvent(evtType, func() interface{} {
|
||||
return StorageClientEvt{
|
||||
Event: storagemarket.ClientEvents[event],
|
||||
Deal: deal,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// StorageProviderJournaler records journal events from the storage provider.
|
||||
func StorageProviderJournaler(evtType journal.EventType) func(event storagemarket.ProviderEvent, deal storagemarket.MinerDeal) {
|
||||
return func(event storagemarket.ProviderEvent, deal storagemarket.MinerDeal) {
|
||||
journal.J.RecordEvent(evtType, func() interface{} {
|
||||
return StorageProviderEvt{
|
||||
Event: storagemarket.ProviderEvents[event],
|
||||
Deal: deal,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// RetrievalClientJournaler records journal events from the retrieval client.
|
||||
func RetrievalClientJournaler(evtType journal.EventType) func(event retrievalmarket.ClientEvent, deal retrievalmarket.ClientDealState) {
|
||||
return func(event retrievalmarket.ClientEvent, deal retrievalmarket.ClientDealState) {
|
||||
journal.J.RecordEvent(evtType, func() interface{} {
|
||||
return RetrievalClientEvt{
|
||||
Event: retrievalmarket.ClientEvents[event],
|
||||
Deal: deal,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// RetrievalProviderJournaler records journal events from the retrieval provider.
|
||||
func RetrievalProviderJournaler(evtType journal.EventType) func(event retrievalmarket.ProviderEvent, deal retrievalmarket.ProviderDealState) {
|
||||
return func(event retrievalmarket.ProviderEvent, deal retrievalmarket.ProviderDealState) {
|
||||
journal.J.RecordEvent(evtType, func() interface{} {
|
||||
return RetrievalProviderEvt{
|
||||
Event: retrievalmarket.ProviderEvents[event],
|
||||
Deal: deal,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (rcn *retrievalClientNode) WaitForPaymentChannelReady(ctx context.Context,
|
||||
|
||||
func (rcn *retrievalClientNode) CheckAvailableFunds(ctx context.Context, paymentChannel address.Address) (retrievalmarket.ChannelAvailableFunds, error) {
|
||||
|
||||
channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(paymentChannel)
|
||||
channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(ctx, paymentChannel)
|
||||
if err != nil {
|
||||
return retrievalmarket.ChannelAvailableFunds{}, err
|
||||
}
|
||||
|
||||
@@ -501,12 +501,12 @@ func (c *ClientNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToke
|
||||
return head.Key().Bytes(), head.Height(), nil
|
||||
}
|
||||
|
||||
func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error {
|
||||
func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error {
|
||||
receipt, err := c.StateWaitMsg(ctx, mcid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return cb(0, nil, err)
|
||||
return cb(0, nil, cid.Undef, err)
|
||||
}
|
||||
return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil)
|
||||
return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil)
|
||||
}
|
||||
|
||||
func (c *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*storagemarket.StorageProviderInfo, error) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -35,6 +36,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||
)
|
||||
|
||||
var addPieceRetryWait = 5 * time.Minute
|
||||
var addPieceRetryTimeout = 6 * time.Hour
|
||||
var log = logging.Logger("storageadapter")
|
||||
|
||||
type ProviderNodeAdapter struct {
|
||||
@@ -91,7 +94,7 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema
|
||||
return nil, xerrors.Errorf("deal.PublishCid can't be nil")
|
||||
}
|
||||
|
||||
p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sealing.DealInfo{
|
||||
sdInfo := sealing.DealInfo{
|
||||
DealID: deal.DealID,
|
||||
PublishCid: deal.PublishCid,
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
@@ -99,7 +102,23 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema
|
||||
EndEpoch: deal.ClientDealProposal.Proposal.EndEpoch,
|
||||
},
|
||||
KeepUnsealed: deal.FastRetrieval,
|
||||
})
|
||||
}
|
||||
|
||||
p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo)
|
||||
curTime := time.Now()
|
||||
for time.Since(curTime) < addPieceRetryTimeout {
|
||||
if !xerrors.Is(err, sealing.ErrTooManySectorsSealing) {
|
||||
log.Errorf("failed to addPiece for deal %d, err: %w", deal.DealID, err)
|
||||
break
|
||||
}
|
||||
select {
|
||||
case <-time.After(addPieceRetryWait):
|
||||
p, offset, err = n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo)
|
||||
case <-ctx.Done():
|
||||
return nil, xerrors.New("context expired while waiting to retry AddPiece")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("AddPiece failed: %s", err)
|
||||
}
|
||||
@@ -355,12 +374,12 @@ func (n *ProviderNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetTo
|
||||
return head.Key().Bytes(), head.Height(), nil
|
||||
}
|
||||
|
||||
func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error {
|
||||
func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error {
|
||||
receipt, err := n.StateWaitMsg(ctx, mcid, 2*build.MessageConfidence)
|
||||
if err != nil {
|
||||
return cb(0, nil, err)
|
||||
return cb(0, nil, cid.Undef, err)
|
||||
}
|
||||
return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil)
|
||||
return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil)
|
||||
}
|
||||
|
||||
func (n *ProviderNodeAdapter) GetDataCap(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*verifreg.DataCap, error) {
|
||||
|
||||
+31
-10
@@ -33,6 +33,11 @@ import (
|
||||
|
||||
var log = logging.Logger("miner")
|
||||
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeBlockMined = iota
|
||||
)
|
||||
|
||||
// returns a callback reporting whether we mined a blocks in this round
|
||||
type waitFunc func(ctx context.Context, baseTime uint64) (func(bool, abi.ChainEpoch, error), abi.ChainEpoch, error)
|
||||
|
||||
@@ -68,6 +73,9 @@ func NewMiner(api api.FullNode, epp gen.WinningPoStProver, addr address.Address,
|
||||
|
||||
sf: sf,
|
||||
minedBlockHeights: arc,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeBlockMined: journal.J.RegisterEventType("miner", "block_mined"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +95,8 @@ type Miner struct {
|
||||
|
||||
sf *slashfilter.SlashFilter
|
||||
minedBlockHeights *lru.ARCCache
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
}
|
||||
|
||||
func (m *Miner) Address() address.Address {
|
||||
@@ -129,6 +139,7 @@ func (m *Miner) niceSleep(d time.Duration) bool {
|
||||
case <-build.Clock.After(d):
|
||||
return true
|
||||
case <-m.stop:
|
||||
log.Infow("received interrupt while trying to sleep in mining cycle")
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -159,7 +170,9 @@ func (m *Miner) mine(ctx context.Context) {
|
||||
prebase, err := m.GetBestMiningCandidate(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get best mining candidate: %s", err)
|
||||
m.niceSleep(time.Second * 5)
|
||||
if !m.niceSleep(time.Second * 5) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -189,7 +202,9 @@ func (m *Miner) mine(ctx context.Context) {
|
||||
_, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1)
|
||||
if err != nil {
|
||||
log.Errorf("failed getting beacon entry: %s", err)
|
||||
m.niceSleep(time.Second)
|
||||
if !m.niceSleep(time.Second) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -198,7 +213,9 @@ func (m *Miner) mine(ctx context.Context) {
|
||||
|
||||
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)
|
||||
m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second)
|
||||
if !m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -207,7 +224,9 @@ func (m *Miner) mine(ctx context.Context) {
|
||||
b, err := m.mineOne(ctx, base)
|
||||
if err != nil {
|
||||
log.Errorf("mining block failed: %+v", err)
|
||||
m.niceSleep(time.Second)
|
||||
if !m.niceSleep(time.Second) {
|
||||
break
|
||||
}
|
||||
onDone(false, 0, err)
|
||||
continue
|
||||
}
|
||||
@@ -220,12 +239,14 @@ func (m *Miner) mine(ctx context.Context) {
|
||||
onDone(b != nil, h, nil)
|
||||
|
||||
if b != nil {
|
||||
journal.Add("blockMined", map[string]interface{}{
|
||||
"parents": base.TipSet.Cids(),
|
||||
"nulls": base.NullRounds,
|
||||
"epoch": b.Header.Height,
|
||||
"timestamp": b.Header.Timestamp,
|
||||
"cid": b.Header.Cid(),
|
||||
journal.J.RecordEvent(m.evtTypes[evtTypeBlockMined], func() interface{} {
|
||||
return map[string]interface{}{
|
||||
"parents": base.TipSet.Cids(),
|
||||
"nulls": base.NullRounds,
|
||||
"epoch": b.Header.Height,
|
||||
"timestamp": b.Header.Timestamp,
|
||||
"cid": b.Header.Cid(),
|
||||
}
|
||||
})
|
||||
|
||||
btime := time.Unix(int64(b.Header.Timestamp), 0)
|
||||
|
||||
+45
-13
@@ -3,6 +3,7 @@ package node
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
@@ -44,6 +45,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
@@ -67,6 +69,10 @@ import (
|
||||
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
||||
)
|
||||
|
||||
// EnvJournalDisabledEvents is the environment variable through which disabled
|
||||
// journal events can be customized.
|
||||
const EnvJournalDisabledEvents = "LOTUS_JOURNAL_DISABLED_EVENTS"
|
||||
|
||||
//nolint:deadcode,varcheck
|
||||
var log = logging.Logger("builder")
|
||||
|
||||
@@ -91,11 +97,16 @@ var (
|
||||
|
||||
type invoke int
|
||||
|
||||
// Invokes are called in the order they are defined.
|
||||
//nolint:golint
|
||||
const (
|
||||
// InitJournal at position 0 initializes the journal global var as soon as
|
||||
// the system starts, so that it's available for all other components.
|
||||
InitJournalKey = invoke(iota)
|
||||
|
||||
// libp2p
|
||||
|
||||
PstoreAddSelfKeysKey = invoke(iota)
|
||||
PstoreAddSelfKeysKey
|
||||
StartListeningKey
|
||||
BootstrapKey
|
||||
|
||||
@@ -123,7 +134,6 @@ const (
|
||||
HeadMetricsKey
|
||||
SettlePaymentChannelsKey
|
||||
RunPeerTaggerKey
|
||||
JournalKey
|
||||
|
||||
SetApiEndpointKey
|
||||
|
||||
@@ -151,11 +161,25 @@ type Settings struct {
|
||||
|
||||
func defaults() []Option {
|
||||
return []Option{
|
||||
// global system journal.
|
||||
Override(new(journal.DisabledEvents), func() journal.DisabledEvents {
|
||||
if env, ok := os.LookupEnv(EnvJournalDisabledEvents); ok {
|
||||
if ret, err := journal.ParseDisabledEvents(env); err == nil {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
// fallback if env variable is not set, or if it failed to parse.
|
||||
return journal.DefaultDisabledEvents
|
||||
}),
|
||||
Override(new(journal.Journal), modules.OpenFilesystemJournal),
|
||||
Override(InitJournalKey, func(j journal.Journal) {
|
||||
journal.J = j // eagerly sets the global journal through fx.Invoke.
|
||||
}),
|
||||
|
||||
Override(new(helpers.MetricsCtx), context.Background),
|
||||
Override(new(record.Validator), modules.RecordValidator),
|
||||
Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(false)),
|
||||
Override(new(dtypes.ShutdownChan), make(chan struct{})),
|
||||
Override(JournalKey, modules.SetupJournal),
|
||||
|
||||
// Filecoin modules
|
||||
|
||||
@@ -242,6 +266,9 @@ func Online() Option {
|
||||
Override(new(dtypes.ChainBlockService), modules.ChainBlockService),
|
||||
|
||||
// Filecoin services
|
||||
// We don't want the SyncManagerCtor to be used as an fx constructor, but rather as a value.
|
||||
// It will be called implicitly by the Syncer constructor.
|
||||
Override(new(chain.SyncManagerCtor), func() chain.SyncManagerCtor { return chain.NewSyncManager }),
|
||||
Override(new(*chain.Syncer), modules.NewSyncer),
|
||||
Override(new(exchange.Client), exchange.NewClient),
|
||||
Override(new(*messagepool.MessagePool), modules.MessagePool),
|
||||
@@ -355,7 +382,7 @@ func StorageMiner(out *api.StorageMiner) Option {
|
||||
|
||||
func(s *Settings) error {
|
||||
resAPI := &impl.StorageMinerAPI{}
|
||||
s.invokes[ExtractApiKey] = fx.Extract(resAPI)
|
||||
s.invokes[ExtractApiKey] = fx.Populate(resAPI)
|
||||
*out = resAPI
|
||||
return nil
|
||||
},
|
||||
@@ -475,12 +502,18 @@ func Repo(r repo.Repo) Option {
|
||||
}
|
||||
|
||||
func FullAPI(out *api.FullNode) Option {
|
||||
return func(s *Settings) error {
|
||||
resAPI := &impl.FullNodeAPI{}
|
||||
s.invokes[ExtractApiKey] = fx.Extract(resAPI)
|
||||
*out = resAPI
|
||||
return nil
|
||||
}
|
||||
return Options(
|
||||
func(s *Settings) error {
|
||||
s.nodeType = repo.FullNode
|
||||
return nil
|
||||
},
|
||||
func(s *Settings) error {
|
||||
resAPI := &impl.FullNodeAPI{}
|
||||
s.invokes[ExtractApiKey] = fx.Populate(resAPI)
|
||||
*out = resAPI
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type StopFunc func(context.Context) error
|
||||
@@ -488,9 +521,8 @@ type StopFunc func(context.Context) error
|
||||
// New builds and starts new Filecoin node
|
||||
func New(ctx context.Context, opts ...Option) (StopFunc, error) {
|
||||
settings := Settings{
|
||||
modules: map[interface{}]fx.Option{},
|
||||
invokes: make([]fx.Option, _nInvokes),
|
||||
nodeType: repo.FullNode,
|
||||
modules: map[interface{}]fx.Option{},
|
||||
invokes: make([]fx.Option, _nInvokes),
|
||||
}
|
||||
|
||||
// apply module options in the right order
|
||||
|
||||
@@ -300,7 +300,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
||||
return nil, nil, xerrors.Errorf("parsing int64: %w", err)
|
||||
}
|
||||
|
||||
ik := adt.IntKey(i)
|
||||
ik := abi.IntKey(i)
|
||||
|
||||
names[0] = "@H:" + ik.Key()
|
||||
}
|
||||
@@ -311,7 +311,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod
|
||||
return nil, nil, xerrors.Errorf("parsing uint64: %w", err)
|
||||
}
|
||||
|
||||
ik := adt.UIntKey(i)
|
||||
ik := abi.UIntKey(i)
|
||||
|
||||
names[0] = "@H:" + ik.Key()
|
||||
}
|
||||
@@ -495,7 +495,7 @@ func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Mess
|
||||
return cm.VMMessage(), nil
|
||||
}
|
||||
|
||||
func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
ts, err := a.Chain.GetTipSetFromKey(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
@@ -508,7 +508,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t
|
||||
bw := bufio.NewWriterSize(w, 1<<20)
|
||||
defer bw.Flush() //nolint:errcheck // it is a write to a pipe
|
||||
|
||||
if err := a.Chain.Export(ctx, ts, nroots, bw); err != nil {
|
||||
if err := a.Chain.Export(ctx, ts, nroots, skipoldmsgs, bw); err != nil {
|
||||
log.Errorf("chain export call failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
+2
-18
@@ -204,30 +204,14 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message,
|
||||
}
|
||||
|
||||
if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 {
|
||||
feeCap, err := a.GasEstimateFeeCap(ctx, msg, 10, types.EmptyTSK)
|
||||
feeCap, err := a.GasEstimateFeeCap(ctx, msg, 20, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("estimating fee cap: %w", err)
|
||||
}
|
||||
msg.GasFeeCap = feeCap
|
||||
}
|
||||
|
||||
capGasFee(msg, spec.Get().MaxFee)
|
||||
messagepool.CapGasFee(msg, spec.Get().MaxFee)
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
func capGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||
if maxFee.Equals(big.Zero()) {
|
||||
maxFee = types.NewInt(build.FilecoinPrecision / 10)
|
||||
}
|
||||
|
||||
gl := types.NewInt(uint64(msg.GasLimit))
|
||||
totalFee := types.BigMul(msg.GasFeeCap, gl)
|
||||
|
||||
if totalFee.LessThanEqual(maxFee) {
|
||||
return
|
||||
}
|
||||
|
||||
msg.GasFeeCap = big.Div(maxFee, gl)
|
||||
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
|
||||
}
|
||||
|
||||
+54
-6
@@ -509,7 +509,7 @@ func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSet
|
||||
return err
|
||||
}
|
||||
|
||||
if found, err := locked.Get(adt.AddrKey(a), &lk); err != nil {
|
||||
if found, err := locked.Get(abi.AddrKey(a), &lk); err != nil {
|
||||
return err
|
||||
} else if !found {
|
||||
return fmt.Errorf("locked funds not found")
|
||||
@@ -604,7 +604,7 @@ func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.
|
||||
return xerrors.Errorf("address in state tree was not valid: %w", err)
|
||||
}
|
||||
|
||||
found, err := oh.Get(adt.AddrKey(addr), &ocval)
|
||||
found, err := oh.Get(abi.AddrKey(addr), &ocval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -883,9 +883,8 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add
|
||||
return act.Balance, nil
|
||||
}
|
||||
|
||||
minBalance := types.BigDiv(st.InitialBalance, types.NewInt(uint64(st.UnlockDuration)))
|
||||
minBalance = types.BigMul(minBalance, types.NewInt(uint64(offset)))
|
||||
return types.BigSub(act.Balance, minBalance), nil
|
||||
al := st.AmountLocked(offset)
|
||||
return types.BigSub(act.Balance, al), nil
|
||||
}
|
||||
|
||||
func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||
@@ -1150,7 +1149,7 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A
|
||||
}
|
||||
|
||||
var dcap verifreg.DataCap
|
||||
if found, err := vh.Get(adt.AddrKey(aid), &dcap); err != nil {
|
||||
if found, err := vh.Get(abi.AddrKey(aid), &dcap); err != nil {
|
||||
return nil, err
|
||||
} else if !found {
|
||||
return nil, nil
|
||||
@@ -1226,3 +1225,52 @@ func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetK
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -39,11 +39,11 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
func (a *PaychAPI) PaychAvailableFunds(ctx context.Context, ch address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return a.PaychMgr.AvailableFunds(ch)
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
func (a *PaychAPI) PaychAvailableFundsByFromTo(ctx context.Context, from, to address.Address) (*api.ChannelAvailableFunds, error) {
|
||||
return a.PaychMgr.AvailableFundsByFromTo(from, to)
|
||||
}
|
||||
|
||||
|
||||
+25
-2
@@ -163,8 +163,31 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore,
|
||||
return netName, err
|
||||
}
|
||||
|
||||
func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*chain.Syncer, error) {
|
||||
syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier)
|
||||
type SyncerParams struct {
|
||||
fx.In
|
||||
|
||||
Lifecycle fx.Lifecycle
|
||||
MetadataDS dtypes.MetadataDS
|
||||
StateManager *stmgr.StateManager
|
||||
ChainXchg exchange.Client
|
||||
SyncMgrCtor chain.SyncManagerCtor
|
||||
Host host.Host
|
||||
Beacon beacon.Schedule
|
||||
Verifier ffiwrapper.Verifier
|
||||
}
|
||||
|
||||
func NewSyncer(params SyncerParams) (*chain.Syncer, error) {
|
||||
var (
|
||||
lc = params.Lifecycle
|
||||
ds = params.MetadataDS
|
||||
sm = params.StateManager
|
||||
ex = params.ChainXchg
|
||||
smCtor = params.SyncMgrCtor
|
||||
h = params.Host
|
||||
b = params.Beacon
|
||||
v = params.Verifier
|
||||
)
|
||||
syncer, err := chain.NewSyncer(ds, sm, ex, smCtor, h.ConnManager(), h.ID(), b, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ import (
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/markets"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/lotus/markets/retrievaladapter"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
@@ -119,6 +121,10 @@ func StorageClient(lc fx.Lifecycle, h host.Host, ibs dtypes.ClientBlockstore, md
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(ctx context.Context) error {
|
||||
c.SubscribeToEvents(marketevents.StorageClientLogger)
|
||||
|
||||
evtType := journal.J.RegisterEventType("markets/storage/client", "state_change")
|
||||
c.SubscribeToEvents(markets.StorageClientJournaler(evtType))
|
||||
|
||||
return c.Start(ctx)
|
||||
},
|
||||
OnStop: func(context.Context) error {
|
||||
@@ -140,6 +146,10 @@ func RetrievalClient(lc fx.Lifecycle, h host.Host, mds dtypes.ClientMultiDstore,
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(ctx context.Context) error {
|
||||
client.SubscribeToEvents(marketevents.RetrievalClientLogger)
|
||||
|
||||
evtType := journal.J.RegisterEventType("markets/retrieval/client", "state_change")
|
||||
client.SubscribeToEvents(markets.RetrievalClientJournaler(evtType))
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gbrlsnchs/jwt/v3"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -20,7 +19,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/addrutil"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
@@ -107,7 +105,3 @@ func DrandBootstrap(ds dtypes.DrandSchedule) (dtypes.DrandBootstrap, error) {
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func SetupJournal(lr repo.LockedRepo) error {
|
||||
return journal.InitializeSystemJournal(filepath.Join(lr.Path(), "journal"))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package modules
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
eventbus "github.com/libp2p/go-eventbus"
|
||||
@@ -22,10 +24,12 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/sub"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/peermgr"
|
||||
"github.com/filecoin-project/lotus/node/hello"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.Service) error {
|
||||
@@ -150,3 +154,16 @@ func RandomSchedule(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.Sche
|
||||
|
||||
return shd, nil
|
||||
}
|
||||
|
||||
func OpenFilesystemJournal(lr repo.LockedRepo, lc fx.Lifecycle, disabled journal.DisabledEvents) (journal.Journal, error) {
|
||||
jrnl, err := journal.OpenFSJournal(lr, disabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(_ context.Context) error { return jrnl.Close() },
|
||||
})
|
||||
|
||||
return jrnl, err
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/markets"
|
||||
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -142,8 +144,34 @@ func SectorIDCounter(ds dtypes.MetadataDS) sealing.SectorIDCounter {
|
||||
return &sidsc{sc}
|
||||
}
|
||||
|
||||
func StorageMiner(fc config.MinerFeeConfig) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc) (*storage.Miner, error) {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, api lapi.FullNode, h host.Host, ds dtypes.MetadataDS, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc) (*storage.Miner, error) {
|
||||
type StorageMinerParams struct {
|
||||
fx.In
|
||||
|
||||
Lifecycle fx.Lifecycle
|
||||
MetricsCtx helpers.MetricsCtx
|
||||
API lapi.FullNode
|
||||
Host host.Host
|
||||
MetadataDS dtypes.MetadataDS
|
||||
Sealer sectorstorage.SectorManager
|
||||
SectorIDCounter sealing.SectorIDCounter
|
||||
Verifier ffiwrapper.Verifier
|
||||
GetSealingConfigFn dtypes.GetSealingConfigFunc
|
||||
}
|
||||
|
||||
func StorageMiner(fc config.MinerFeeConfig) func(params StorageMinerParams) (*storage.Miner, error) {
|
||||
return func(params StorageMinerParams) (*storage.Miner, error) {
|
||||
var (
|
||||
ds = params.MetadataDS
|
||||
mctx = params.MetricsCtx
|
||||
lc = params.Lifecycle
|
||||
api = params.API
|
||||
sealer = params.Sealer
|
||||
h = params.Host
|
||||
sc = params.SectorIDCounter
|
||||
verif = params.Verifier
|
||||
gsd = params.GetSealingConfigFn
|
||||
)
|
||||
|
||||
maddr, err := minerAddrFromDS(ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -187,6 +215,10 @@ func HandleRetrieval(host host.Host, lc fx.Lifecycle, m retrievalmarket.Retrieva
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
m.SubscribeToEvents(marketevents.RetrievalProviderLogger)
|
||||
|
||||
evtType := journal.J.RegisterEventType("markets/retrieval/provider", "state_change")
|
||||
m.SubscribeToEvents(markets.RetrievalProviderJournaler(evtType))
|
||||
|
||||
return m.Start()
|
||||
},
|
||||
OnStop: func(context.Context) error {
|
||||
@@ -201,6 +233,10 @@ func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h sto
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
h.SubscribeToEvents(marketevents.StorageProviderLogger)
|
||||
|
||||
evtType := journal.J.RegisterEventType("markets/storage/provider", "state_change")
|
||||
h.SubscribeToEvents(markets.StorageProviderJournaler(evtType))
|
||||
|
||||
return h.Start(ctx)
|
||||
},
|
||||
OnStop: func(context.Context) error {
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ func (fsr *FsRepo) Init(t RepoType) error {
|
||||
}
|
||||
|
||||
log.Infof("Initializing repo at '%s'", fsr.path)
|
||||
err = os.Mkdir(fsr.path, 0755) //nolint: gosec
|
||||
err = os.MkdirAll(fsr.path, 0755) //nolint: gosec
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a
|
||||
}
|
||||
|
||||
var pci miner.SectorPreCommitOnChainInfo
|
||||
ok, err := precommits.Get(adt.UIntKey(uint64(sectorNumber)), &pci)
|
||||
ok, err := precommits.Get(abi.UIntKey(uint64(sectorNumber)), &pci)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func AddressFor(ctx context.Context, a addrSelectApi, mi api.MinerInfo, use Addr
|
||||
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
|
||||
|
||||
+29
-4
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
@@ -50,6 +51,17 @@ type Miner struct {
|
||||
|
||||
getSealConfig dtypes.GetSealingConfigFunc
|
||||
sealing *sealing.Sealing
|
||||
|
||||
sealingEvtType journal.EventType
|
||||
}
|
||||
|
||||
// SealingStateEvt is a journal event that records a sector state transition.
|
||||
type SealingStateEvt struct {
|
||||
SectorNumber abi.SectorNumber
|
||||
SectorType abi.RegisteredSealProof
|
||||
From sealing.SectorState
|
||||
After sealing.SectorState
|
||||
Error string
|
||||
}
|
||||
|
||||
type storageMinerApi interface {
|
||||
@@ -103,9 +115,10 @@ func NewMiner(api storageMinerApi, maddr, worker address.Address, h host.Host, d
|
||||
sc: sc,
|
||||
verif: verif,
|
||||
|
||||
maddr: maddr,
|
||||
worker: worker,
|
||||
getSealConfig: gsd,
|
||||
maddr: maddr,
|
||||
worker: worker,
|
||||
getSealConfig: gsd,
|
||||
sealingEvtType: journal.J.RegisterEventType("storage", "sealing_states"),
|
||||
}
|
||||
|
||||
return m, nil
|
||||
@@ -129,13 +142,25 @@ func (m *Miner) Run(ctx context.Context) error {
|
||||
evts := events.NewEvents(ctx, m.api)
|
||||
adaptedAPI := NewSealingAPIAdapter(m.api)
|
||||
pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, miner.MaxSectorExpirationExtension-(miner.WPoStProvingPeriod*2), md.PeriodStart%miner.WPoStProvingPeriod)
|
||||
m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingConfigFunc(m.getSealConfig))
|
||||
m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingConfigFunc(m.getSealConfig), m.handleSealingNotifications)
|
||||
|
||||
go m.sealing.Run(ctx) //nolint:errcheck // logged intside the function
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Miner) handleSealingNotifications(before, after sealing.SectorInfo) {
|
||||
journal.J.RecordEvent(m.sealingEvtType, func() interface{} {
|
||||
return SealingStateEvt{
|
||||
SectorNumber: before.SectorNumber,
|
||||
SectorType: before.SectorType,
|
||||
From: before.State,
|
||||
After: after.State,
|
||||
Error: after.LastErr,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Miner) Stop(ctx context.Context) error {
|
||||
return m.sealing.Stop(ctx)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// SchedulerState defines the possible states in which the scheduler could be,
|
||||
// for the purposes of journalling.
|
||||
type SchedulerState string
|
||||
|
||||
const (
|
||||
// SchedulerStateStarted gets recorded when a WdPoSt cycle for an
|
||||
// epoch begins.
|
||||
SchedulerStateStarted = SchedulerState("started")
|
||||
// SchedulerStateAborted gets recorded when a WdPoSt cycle for an
|
||||
// epoch is aborted, normally because of a chain reorg or advancement.
|
||||
SchedulerStateAborted = SchedulerState("aborted")
|
||||
// SchedulerStateFaulted gets recorded when a WdPoSt cycle for an
|
||||
// epoch terminates abnormally, in which case the error is also recorded.
|
||||
SchedulerStateFaulted = SchedulerState("faulted")
|
||||
// SchedulerStateSucceeded gets recorded when a WdPoSt cycle for an
|
||||
// epoch ends successfully.
|
||||
SchedulerStateSucceeded = SchedulerState("succeeded")
|
||||
)
|
||||
|
||||
// Journal event types.
|
||||
const (
|
||||
evtTypeWdPoStScheduler = iota
|
||||
evtTypeWdPoStProofs
|
||||
evtTypeWdPoStRecoveries
|
||||
evtTypeWdPoStFaults
|
||||
)
|
||||
|
||||
// evtCommon is a common set of attributes for Windowed PoSt journal events.
|
||||
type evtCommon struct {
|
||||
Deadline *dline.Info
|
||||
Height abi.ChainEpoch
|
||||
TipSet []cid.Cid
|
||||
Error error `json:",omitempty"`
|
||||
}
|
||||
|
||||
// WdPoStSchedulerEvt is the journal event that gets recorded on scheduler
|
||||
// actions.
|
||||
type WdPoStSchedulerEvt struct {
|
||||
evtCommon
|
||||
State SchedulerState
|
||||
}
|
||||
|
||||
// WdPoStProofsProcessedEvt is the journal event that gets recorded when
|
||||
// Windowed PoSt proofs have been processed.
|
||||
type WdPoStProofsProcessedEvt struct {
|
||||
evtCommon
|
||||
Partitions []miner.PoStPartition
|
||||
MessageCID cid.Cid `json:",omitempty"`
|
||||
}
|
||||
|
||||
// WdPoStRecoveriesProcessedEvt is the journal event that gets recorded when
|
||||
// Windowed PoSt recoveries have been processed.
|
||||
type WdPoStRecoveriesProcessedEvt struct {
|
||||
evtCommon
|
||||
Declarations []miner.RecoveryDeclaration
|
||||
MessageCID cid.Cid `json:",omitempty"`
|
||||
}
|
||||
|
||||
// WdPoStFaultsProcessedEvt is the journal event that gets recorded when
|
||||
// Windowed PoSt faults have been processed.
|
||||
type WdPoStFaultsProcessedEvt struct {
|
||||
evtCommon
|
||||
Declarations []miner.FaultDeclaration
|
||||
MessageCID cid.Cid `json:",omitempty"`
|
||||
}
|
||||
+311
-146
@@ -3,7 +3,6 @@ package storage
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
@@ -18,6 +17,8 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -25,11 +26,17 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
)
|
||||
|
||||
var errNoPartitions = errors.New("no partitions")
|
||||
func (s *WindowPoStScheduler) failPost(err error, deadline *dline.Info) {
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStScheduler], func() interface{} {
|
||||
return WdPoStSchedulerEvt{
|
||||
evtCommon: s.getEvtCommon(err),
|
||||
State: SchedulerStateFaulted,
|
||||
}
|
||||
})
|
||||
|
||||
func (s *WindowPoStScheduler) failPost(deadline *dline.Info) {
|
||||
log.Errorf("TODO")
|
||||
/*s.failLk.Lock()
|
||||
if eps > s.failed {
|
||||
@@ -44,27 +51,60 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info,
|
||||
s.abort = abort
|
||||
s.activeDeadline = deadline
|
||||
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStScheduler], func() interface{} {
|
||||
return WdPoStSchedulerEvt{
|
||||
evtCommon: s.getEvtCommon(nil),
|
||||
State: SchedulerStateStarted,
|
||||
}
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer abort()
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "WindowPoStScheduler.doPost")
|
||||
defer span.End()
|
||||
|
||||
proof, err := s.runPost(ctx, *deadline, ts)
|
||||
switch err {
|
||||
case errNoPartitions:
|
||||
return
|
||||
case nil:
|
||||
if err := s.submitPost(ctx, proof); err != nil {
|
||||
log.Errorf("submitPost failed: %+v", err)
|
||||
s.failPost(deadline)
|
||||
return
|
||||
}
|
||||
default:
|
||||
log.Errorf("runPost failed: %+v", err)
|
||||
s.failPost(deadline)
|
||||
// recordProofsEvent records a successful proofs_processed event in the
|
||||
// journal, even if it was a noop (no partitions).
|
||||
recordProofsEvent := func(partitions []miner.PoStPartition, mcid cid.Cid) {
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStProofs], func() interface{} {
|
||||
return &WdPoStProofsProcessedEvt{
|
||||
evtCommon: s.getEvtCommon(nil),
|
||||
Partitions: partitions,
|
||||
MessageCID: mcid,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
posts, err := s.runPost(ctx, *deadline, ts)
|
||||
if err != nil {
|
||||
log.Errorf("run window post failed: %+v", err)
|
||||
s.failPost(err, deadline)
|
||||
return
|
||||
}
|
||||
|
||||
if len(posts) == 0 {
|
||||
recordProofsEvent(nil, cid.Undef)
|
||||
return
|
||||
}
|
||||
|
||||
for i := range posts {
|
||||
post := &posts[i]
|
||||
sm, err := s.submitPost(ctx, post)
|
||||
if err != nil {
|
||||
log.Errorf("submit window post failed: %+v", err)
|
||||
s.failPost(err, deadline)
|
||||
} else {
|
||||
recordProofsEvent(post.Partitions, sm.Cid())
|
||||
}
|
||||
}
|
||||
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStScheduler], func() interface{} {
|
||||
return WdPoStSchedulerEvt{
|
||||
evtCommon: s.getEvtCommon(nil),
|
||||
State: SchedulerStateSucceeded,
|
||||
}
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -113,25 +153,24 @@ func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.B
|
||||
return sbf, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) error {
|
||||
func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) ([]miner.RecoveryDeclaration, *types.SignedMessage, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "storage.checkNextRecoveries")
|
||||
defer span.End()
|
||||
|
||||
faulty := uint64(0)
|
||||
params := &miner.DeclareFaultsRecoveredParams{
|
||||
Recoveries: []miner.RecoveryDeclaration{},
|
||||
}
|
||||
|
||||
faulty := uint64(0)
|
||||
|
||||
for partIdx, partition := range partitions {
|
||||
unrecovered, err := bitfield.SubtractBitField(partition.Faults, partition.Recoveries)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("subtracting recovered set from fault set: %w", err)
|
||||
return nil, nil, xerrors.Errorf("subtracting recovered set from fault set: %w", err)
|
||||
}
|
||||
|
||||
uc, err := unrecovered.Count()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("counting unrecovered sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("counting unrecovered sectors: %w", err)
|
||||
}
|
||||
|
||||
if uc == 0 {
|
||||
@@ -142,13 +181,13 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin
|
||||
|
||||
recovered, err := s.checkSectors(ctx, unrecovered)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking unrecovered sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("checking unrecovered sectors: %w", err)
|
||||
}
|
||||
|
||||
// if all sectors failed to recover, don't declare recoveries
|
||||
recoveredCount, err := recovered.Count()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("counting recovered sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("counting recovered sectors: %w", err)
|
||||
}
|
||||
|
||||
if recoveredCount == 0 {
|
||||
@@ -162,17 +201,18 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin
|
||||
})
|
||||
}
|
||||
|
||||
if len(params.Recoveries) == 0 {
|
||||
recoveries := params.Recoveries
|
||||
if len(recoveries) == 0 {
|
||||
if faulty != 0 {
|
||||
log.Warnw("No recoveries to declare", "deadline", dlIdx, "faulty", faulty)
|
||||
}
|
||||
|
||||
return nil
|
||||
return recoveries, nil, nil
|
||||
}
|
||||
|
||||
enc, aerr := actors.SerializeParams(params)
|
||||
if aerr != nil {
|
||||
return xerrors.Errorf("could not serialize declare recoveries parameters: %w", aerr)
|
||||
return recoveries, nil, xerrors.Errorf("could not serialize declare recoveries parameters: %w", aerr)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
@@ -187,52 +227,51 @@ func (s *WindowPoStScheduler) checkNextRecoveries(ctx context.Context, dlIdx uin
|
||||
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
return recoveries, sm, xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
}
|
||||
|
||||
log.Warnw("declare faults recovered Message CID", "cid", sm.Cid())
|
||||
|
||||
rec, err := s.api.StateWaitMsg(context.TODO(), sm.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("declare faults recovered wait error: %w", err)
|
||||
return recoveries, sm, xerrors.Errorf("declare faults recovered wait error: %w", err)
|
||||
}
|
||||
|
||||
if rec.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("declare faults recovered wait non-0 exit code: %d", rec.Receipt.ExitCode)
|
||||
return recoveries, sm, xerrors.Errorf("declare faults recovered wait non-0 exit code: %d", rec.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
return recoveries, sm, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) error {
|
||||
func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, partitions []*miner.Partition) ([]miner.FaultDeclaration, *types.SignedMessage, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "storage.checkNextFaults")
|
||||
defer span.End()
|
||||
|
||||
bad := uint64(0)
|
||||
params := &miner.DeclareFaultsParams{
|
||||
Faults: []miner.FaultDeclaration{},
|
||||
}
|
||||
|
||||
bad := uint64(0)
|
||||
|
||||
for partIdx, partition := range partitions {
|
||||
toCheck, err := partition.ActiveSectors()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting active sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("getting active sectors: %w", err)
|
||||
}
|
||||
|
||||
good, err := s.checkSectors(ctx, toCheck)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("checking sectors: %w", err)
|
||||
}
|
||||
|
||||
faulty, err := bitfield.SubtractBitField(toCheck, good)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("calculating faulty sector set: %w", err)
|
||||
return nil, nil, xerrors.Errorf("calculating faulty sector set: %w", err)
|
||||
}
|
||||
|
||||
c, err := faulty.Count()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("counting faulty sectors: %w", err)
|
||||
return nil, nil, xerrors.Errorf("counting faulty sectors: %w", err)
|
||||
}
|
||||
|
||||
if c == 0 {
|
||||
@@ -248,15 +287,16 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64,
|
||||
})
|
||||
}
|
||||
|
||||
if len(params.Faults) == 0 {
|
||||
return nil
|
||||
faults := params.Faults
|
||||
if len(faults) == 0 {
|
||||
return faults, nil, nil
|
||||
}
|
||||
|
||||
log.Errorw("DETECTED FAULTY SECTORS, declaring faults", "count", bad)
|
||||
|
||||
enc, aerr := actors.SerializeParams(params)
|
||||
if aerr != nil {
|
||||
return xerrors.Errorf("could not serialize declare faults parameters: %w", aerr)
|
||||
return faults, nil, xerrors.Errorf("could not serialize declare faults parameters: %w", aerr)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
@@ -271,24 +311,24 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64,
|
||||
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, spec)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
return faults, sm, xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
}
|
||||
|
||||
log.Warnw("declare faults Message CID", "cid", sm.Cid())
|
||||
|
||||
rec, err := s.api.StateWaitMsg(context.TODO(), sm.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("declare faults wait error: %w", err)
|
||||
return faults, sm, xerrors.Errorf("declare faults wait error: %w", err)
|
||||
}
|
||||
|
||||
if rec.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("declare faults wait non-0 exit code: %d", rec.Receipt.ExitCode)
|
||||
return faults, sm, xerrors.Errorf("declare faults wait non-0 exit code: %d", rec.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
return faults, sm, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) {
|
||||
func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *types.TipSet) ([]miner.SubmitWindowedPoStParams, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "storage.runPost")
|
||||
defer span.End()
|
||||
|
||||
@@ -305,15 +345,49 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *ty
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.checkNextRecoveries(context.TODO(), declDeadline, partitions); err != nil {
|
||||
var (
|
||||
sigmsg *types.SignedMessage
|
||||
recoveries []miner.RecoveryDeclaration
|
||||
faults []miner.FaultDeclaration
|
||||
|
||||
// optionalCid returns the CID of the message, or cid.Undef is the
|
||||
// message is nil. We don't need the argument (could capture the
|
||||
// pointer), but it's clearer and purer like that.
|
||||
optionalCid = func(sigmsg *types.SignedMessage) cid.Cid {
|
||||
if sigmsg == nil {
|
||||
return cid.Undef
|
||||
}
|
||||
return sigmsg.Cid()
|
||||
}
|
||||
)
|
||||
|
||||
if recoveries, sigmsg, err = s.checkNextRecoveries(context.TODO(), declDeadline, partitions); err != nil {
|
||||
// TODO: This is potentially quite bad, but not even trying to post when this fails is objectively worse
|
||||
log.Errorf("checking sector recoveries: %v", err)
|
||||
}
|
||||
|
||||
if err := s.checkNextFaults(context.TODO(), declDeadline, partitions); err != nil {
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStRecoveries], func() interface{} {
|
||||
j := WdPoStRecoveriesProcessedEvt{
|
||||
evtCommon: s.getEvtCommon(err),
|
||||
Declarations: recoveries,
|
||||
MessageCID: optionalCid(sigmsg),
|
||||
}
|
||||
j.Error = err
|
||||
return j
|
||||
})
|
||||
|
||||
if faults, sigmsg, err = s.checkNextFaults(context.TODO(), declDeadline, partitions); err != nil {
|
||||
// TODO: This is also potentially really bad, but we try to post anyways
|
||||
log.Errorf("checking sector faults: %v", err)
|
||||
}
|
||||
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStFaults], func() interface{} {
|
||||
return WdPoStFaultsProcessedEvt{
|
||||
evtCommon: s.getEvtCommon(err),
|
||||
Declarations: faults,
|
||||
MessageCID: optionalCid(sigmsg),
|
||||
}
|
||||
})
|
||||
}()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
@@ -323,119 +397,207 @@ 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())
|
||||
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
|
||||
partitions, err := s.api.StateMinerPartitions(ctx, s.actor, di.Index, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting partitions: %w", err)
|
||||
}
|
||||
|
||||
params := &miner.SubmitWindowedPoStParams{
|
||||
Deadline: di.Index,
|
||||
Partitions: make([]miner.PoStPartition, 0, len(partitions)),
|
||||
Proofs: nil,
|
||||
}
|
||||
|
||||
var sinfos []proof.SectorInfo
|
||||
sidToPart := map[abi.SectorNumber]uint64{}
|
||||
skipCount := uint64(0)
|
||||
|
||||
for partIdx, partition := range partitions {
|
||||
// TODO: Can do this in parallel
|
||||
toProve, err := partition.ActiveSectors()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting active sectors: %w", err)
|
||||
}
|
||||
|
||||
toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err)
|
||||
}
|
||||
|
||||
good, err := s.checkSectors(ctx, toProve)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("checking sectors to skip: %w", err)
|
||||
}
|
||||
|
||||
skipped, err := bitfield.SubtractBitField(toProve, good)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("toProve - good: %w", err)
|
||||
}
|
||||
|
||||
sc, err := skipped.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting skipped sector count: %w", err)
|
||||
}
|
||||
|
||||
skipCount += sc
|
||||
|
||||
ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting sorted sector info: %w", err)
|
||||
}
|
||||
|
||||
if len(ssi) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sinfos = append(sinfos, ssi...)
|
||||
for _, si := range ssi {
|
||||
sidToPart[si.SectorNumber] = uint64(partIdx)
|
||||
}
|
||||
|
||||
params.Partitions = append(params.Partitions, miner.PoStPartition{
|
||||
Index: uint64(partIdx),
|
||||
Skipped: skipped,
|
||||
})
|
||||
}
|
||||
|
||||
if len(sinfos) == 0 {
|
||||
// nothing to prove..
|
||||
return nil, errNoPartitions
|
||||
}
|
||||
|
||||
log.Infow("running windowPost",
|
||||
"chain-random", rand,
|
||||
"deadline", di,
|
||||
"height", ts.Height(),
|
||||
"skipped", skipCount)
|
||||
|
||||
tsStart := build.Clock.Now()
|
||||
|
||||
mid, err := address.IDFromAddress(s.actor)
|
||||
// Split partitions into batches, so as not to exceed the number of sectors
|
||||
// allowed in a single message
|
||||
partitionBatches, err := s.batchPartitions(partitions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
postOut, postSkipped, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("running post failed: %w", err)
|
||||
// Generate proofs in batches
|
||||
posts := make([]miner.SubmitWindowedPoStParams, 0, len(partitionBatches))
|
||||
for batchIdx, batch := range partitionBatches {
|
||||
batchPartitionStartIdx := 0
|
||||
for _, batch := range partitionBatches[:batchIdx] {
|
||||
batchPartitionStartIdx += len(batch)
|
||||
}
|
||||
|
||||
params := miner.SubmitWindowedPoStParams{
|
||||
Deadline: di.Index,
|
||||
Partitions: make([]miner.PoStPartition, 0, len(batch)),
|
||||
Proofs: nil,
|
||||
}
|
||||
|
||||
skipCount := uint64(0)
|
||||
postSkipped := bitfield.New()
|
||||
var postOut []proof.PoStProof
|
||||
somethingToProve := true
|
||||
|
||||
for retries := 0; retries < 5; retries++ {
|
||||
var partitions []miner.PoStPartition
|
||||
var sinfos []proof.SectorInfo
|
||||
for partIdx, partition := range batch {
|
||||
// TODO: Can do this in parallel
|
||||
toProve, err := partition.ActiveSectors()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting active sectors: %w", err)
|
||||
}
|
||||
|
||||
toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err)
|
||||
}
|
||||
|
||||
good, err := s.checkSectors(ctx, toProve)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("checking sectors to skip: %w", err)
|
||||
}
|
||||
|
||||
good, err = bitfield.SubtractBitField(good, postSkipped)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("toProve - postSkipped: %w", err)
|
||||
}
|
||||
|
||||
skipped, err := bitfield.SubtractBitField(toProve, good)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("toProve - good: %w", err)
|
||||
}
|
||||
|
||||
sc, err := skipped.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting skipped sector count: %w", err)
|
||||
}
|
||||
|
||||
skipCount += sc
|
||||
|
||||
ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting sorted sector info: %w", err)
|
||||
}
|
||||
|
||||
if len(ssi) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sinfos = append(sinfos, ssi...)
|
||||
partitions = append(partitions, miner.PoStPartition{
|
||||
Index: uint64(batchPartitionStartIdx + partIdx),
|
||||
Skipped: skipped,
|
||||
})
|
||||
}
|
||||
|
||||
if len(sinfos) == 0 {
|
||||
// nothing to prove for this batch
|
||||
somethingToProve = false
|
||||
break
|
||||
}
|
||||
|
||||
// Generate proof
|
||||
log.Infow("running window post",
|
||||
"chain-random", rand,
|
||||
"deadline", di,
|
||||
"height", ts.Height(),
|
||||
"skipped", skipCount)
|
||||
|
||||
tsStart := build.Clock.Now()
|
||||
|
||||
mid, err := address.IDFromAddress(s.actor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ps []abi.SectorID
|
||||
postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand))
|
||||
elapsed := time.Since(tsStart)
|
||||
|
||||
log.Infow("computing window post", "batch", batchIdx, "elapsed", elapsed)
|
||||
|
||||
if err == nil {
|
||||
// Proof generation successful, stop retrying
|
||||
params.Partitions = append(params.Partitions, partitions...)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// Proof generation failed, so retry
|
||||
|
||||
if len(ps) == 0 {
|
||||
return nil, xerrors.Errorf("running window post failed: %w", err)
|
||||
}
|
||||
|
||||
log.Warnw("generate window post skipped sectors", "sectors", ps, "error", err, "try", retries)
|
||||
|
||||
skipCount += uint64(len(ps))
|
||||
for _, sector := range ps {
|
||||
postSkipped.Set(uint64(sector.Number))
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to prove for this batch, try the next batch
|
||||
if !somethingToProve {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(postOut) == 0 {
|
||||
return nil, xerrors.Errorf("received no proofs back from generate window post")
|
||||
}
|
||||
|
||||
params.Proofs = postOut
|
||||
|
||||
posts = append(posts, params)
|
||||
}
|
||||
|
||||
if len(postOut) == 0 {
|
||||
return nil, xerrors.Errorf("received proofs back from generate window post")
|
||||
}
|
||||
|
||||
params.Proofs = postOut
|
||||
|
||||
for _, sector := range postSkipped {
|
||||
params.Partitions[sidToPart[sector.Number]].Skipped.Set(uint64(sector.Number))
|
||||
}
|
||||
|
||||
elapsed := time.Since(tsStart)
|
||||
|
||||
// Compute randomness after generating proofs so as to reduce the impact
|
||||
// of chain reorgs (which change randomness)
|
||||
commEpoch := di.Open
|
||||
commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, 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(), commEpoch, err)
|
||||
}
|
||||
params.ChainCommitEpoch = commEpoch
|
||||
params.ChainCommitRand = commRand
|
||||
|
||||
log.Infow("submitting window PoSt", "elapsed", elapsed)
|
||||
for i := range posts {
|
||||
posts[i].ChainCommitEpoch = commEpoch
|
||||
posts[i].ChainCommitRand = commRand
|
||||
}
|
||||
|
||||
return params, nil
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) batchPartitions(partitions []*miner.Partition) ([][]*miner.Partition, error) {
|
||||
// Get the number of sectors allowed in a partition, for this proof size
|
||||
sectorsPerPartition, err := builtin.PoStProofWindowPoStPartitionSectors(s.proofType)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting sectors per partition: %w", err)
|
||||
}
|
||||
|
||||
// We don't want to exceed the number of sectors allowed in a message.
|
||||
// So given the number of sectors in a partition, work out the number of
|
||||
// partitions that can be in a message without exceeding sectors per
|
||||
// message:
|
||||
// floor(number of sectors allowed in a message / sectors per partition)
|
||||
// eg:
|
||||
// max sectors per message 7: ooooooo
|
||||
// sectors per partition 3: ooo
|
||||
// partitions per message 2: oooOOO
|
||||
// <1><2> (3rd doesn't fit)
|
||||
partitionsPerMsg := int(miner.AddressedSectorsMax / sectorsPerPartition)
|
||||
|
||||
// The number of messages will be:
|
||||
// ceiling(number of partitions / partitions per message)
|
||||
batchCount := len(partitions) / partitionsPerMsg
|
||||
if len(partitions)%partitionsPerMsg != 0 {
|
||||
batchCount++
|
||||
}
|
||||
|
||||
// Split the partitions into batches
|
||||
batches := make([][]*miner.Partition, 0, batchCount)
|
||||
for i := 0; i < len(partitions); i += partitionsPerMsg {
|
||||
end := i + partitionsPerMsg
|
||||
if end > len(partitions) {
|
||||
end = len(partitions)
|
||||
}
|
||||
batches = append(batches, partitions[i:end])
|
||||
}
|
||||
return batches, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors bitfield.BitField, ts *types.TipSet) ([]proof.SectorInfo, error) {
|
||||
@@ -478,13 +640,15 @@ func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors,
|
||||
return proofSectors, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.SubmitWindowedPoStParams) error {
|
||||
func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.SubmitWindowedPoStParams) (*types.SignedMessage, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "storage.commitPost")
|
||||
defer span.End()
|
||||
|
||||
var sm *types.SignedMessage
|
||||
|
||||
enc, aerr := actors.SerializeParams(proof)
|
||||
if aerr != nil {
|
||||
return 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{
|
||||
@@ -499,8 +663,9 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
|
||||
|
||||
// TODO: consider maybe caring about the output
|
||||
sm, err := s.api.MpoolPushMessage(ctx, msg, spec)
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
return nil, xerrors.Errorf("pushing message to mpool: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Submitted window post: %s", sm.Cid())
|
||||
@@ -519,7 +684,7 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi
|
||||
log.Errorf("Submitting window post %s failed: exit %d", sm.Cid(), rec.Receipt.ExitCode)
|
||||
}()
|
||||
|
||||
return nil
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) {
|
||||
@@ -544,7 +709,7 @@ func (s *WindowPoStScheduler) setSender(ctx context.Context, msg *types.Message,
|
||||
|
||||
pa, err := AddressFor(ctx, s.api, mi, PoStAddr, minFunds)
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
tutils "github.com/filecoin-project/specs-actors/support/testing"
|
||||
)
|
||||
|
||||
type mockStorageMinerAPI struct {
|
||||
partitions []*miner.Partition
|
||||
pushedMessages chan *types.Message
|
||||
}
|
||||
|
||||
func newMockStorageMinerAPI() *mockStorageMinerAPI {
|
||||
return &mockStorageMinerAPI{
|
||||
pushedMessages: make(chan *types.Message),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
return abi.Randomness("ticket rand"), nil
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
||||
return abi.Randomness("beacon rand"), nil
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) setPartitions(ps []*miner.Partition) {
|
||||
m.partitions = append(m.partitions, ps...)
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerPartitions(ctx context.Context, address address.Address, u uint64, key types.TipSetKey) ([]*miner.Partition, error) {
|
||||
return m.partitions, nil
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, field *bitfield.BitField, b bool, key types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
var sis []*api.ChainSectorInfo
|
||||
_ = field.ForEach(func(i uint64) error {
|
||||
sis = append(sis, &api.ChainSectorInfo{
|
||||
Info: miner.SectorOnChainInfo{
|
||||
SectorNumber: abi.SectorNumber(i),
|
||||
},
|
||||
ID: abi.SectorNumber(i),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return sis, nil
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerInfo(ctx context.Context, address address.Address, key types.TipSetKey) (api.MinerInfo, error) {
|
||||
return api.MinerInfo{}, xerrors.Errorf("err")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) MpoolPushMessage(ctx context.Context, message *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
||||
m.pushedMessages <- message
|
||||
return &types.SignedMessage{
|
||||
Message: *message,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return &api.MsgLookup{
|
||||
Receipt: types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type mockProver struct {
|
||||
}
|
||||
|
||||
func (m *mockProver) GenerateWinningPoSt(context.Context, abi.ActorID, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockProver) GenerateWindowPoSt(ctx context.Context, aid abi.ActorID, sis []proof.SectorInfo, pr abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) {
|
||||
return []proof.PoStProof{
|
||||
{
|
||||
PoStProof: abi.RegisteredPoStProof_StackedDrgWindow2KiBV1,
|
||||
ProofBytes: []byte("post-proof"),
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
type mockFaultTracker struct {
|
||||
}
|
||||
|
||||
func (m mockFaultTracker) CheckProvable(ctx context.Context, spt abi.RegisteredSealProof, sectors []abi.SectorID) ([]abi.SectorID, error) {
|
||||
// Returns "bad" sectors so just return nil meaning all sectors are good
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// TestWDPostDoPost verifies that doPost will send the correct number of window
|
||||
// PoST messages for a given number of partitions
|
||||
func TestWDPostDoPost(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
expectedMsgCount := 5
|
||||
|
||||
proofType := abi.RegisteredPoStProof_StackedDrgWindow2KiBV1
|
||||
postAct := tutils.NewIDAddr(t, 100)
|
||||
workerAct := tutils.NewIDAddr(t, 101)
|
||||
|
||||
mockStgMinerAPI := newMockStorageMinerAPI()
|
||||
|
||||
// Get the number of sectors allowed in a partition for this proof type
|
||||
sectorsPerPartition, err := builtin.PoStProofWindowPoStPartitionSectors(proofType)
|
||||
require.NoError(t, err)
|
||||
// Work out the number of partitions that can be included in a message
|
||||
// without exceeding the message sector limit
|
||||
partitionsPerMsg := int(miner.AddressedSectorsMax / sectorsPerPartition)
|
||||
|
||||
// Enough partitions to fill expectedMsgCount-1 messages
|
||||
partitionCount := (expectedMsgCount - 1) * partitionsPerMsg
|
||||
// Add an extra partition that should be included in the last message
|
||||
partitionCount++
|
||||
|
||||
var partitions []*miner.Partition
|
||||
for p := 0; p < partitionCount; p++ {
|
||||
sectors := bitfield.New()
|
||||
for s := uint64(0); s < sectorsPerPartition; s++ {
|
||||
sectors.Set(s)
|
||||
}
|
||||
partitions = append(partitions, &miner.Partition{
|
||||
Sectors: sectors,
|
||||
})
|
||||
}
|
||||
mockStgMinerAPI.setPartitions(partitions)
|
||||
|
||||
// Run window PoST
|
||||
scheduler := &WindowPoStScheduler{
|
||||
api: mockStgMinerAPI,
|
||||
prover: &mockProver{},
|
||||
faultTracker: &mockFaultTracker{},
|
||||
proofType: proofType,
|
||||
actor: postAct,
|
||||
worker: workerAct,
|
||||
}
|
||||
|
||||
di := &dline.Info{}
|
||||
ts := mockTipSet(t)
|
||||
scheduler.doPost(ctx, di, ts)
|
||||
|
||||
// Read the window PoST messages
|
||||
for i := 0; i < expectedMsgCount; i++ {
|
||||
msg := <-mockStgMinerAPI.pushedMessages
|
||||
require.Equal(t, builtin.MethodsMiner.SubmitWindowedPoSt, msg.Method)
|
||||
var params miner.SubmitWindowedPoStParams
|
||||
err := params.UnmarshalCBOR(bytes.NewReader(msg.Params))
|
||||
require.NoError(t, err)
|
||||
|
||||
if i == expectedMsgCount-1 {
|
||||
// In the last message we only included a single partition (see above)
|
||||
require.Len(t, params.Partitions, 1)
|
||||
} else {
|
||||
// All previous messages should include the full number of partitions
|
||||
require.Len(t, params.Partitions, partitionsPerMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mockTipSet(t *testing.T) *types.TipSet {
|
||||
minerAct := tutils.NewActorAddr(t, "miner")
|
||||
c, err := cid.Decode("QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH")
|
||||
require.NoError(t, err)
|
||||
blks := []*types.BlockHeader{
|
||||
{
|
||||
Miner: minerAct,
|
||||
Height: abi.ChainEpoch(1),
|
||||
ParentStateRoot: c,
|
||||
ParentMessageReceipts: c,
|
||||
Messages: c,
|
||||
},
|
||||
}
|
||||
ts, err := types.NewTipSet(blks)
|
||||
require.NoError(t, err)
|
||||
return ts
|
||||
}
|
||||
|
||||
//
|
||||
// All the mock methods below here are unused
|
||||
//
|
||||
|
||||
func (m *mockStorageMinerAPI) StateCall(ctx context.Context, message *types.Message, key types.TipSetKey) (*api.InvocResult, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) ([]*miner.Deadline, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateSectorPreCommitInfo(ctx context.Context, address address.Address, number abi.SectorNumber, key types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateSectorGetInfo(ctx context.Context, address address.Address, number abi.SectorNumber, key types.TipSetKey) (*miner.SectorOnChainInfo, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerProvingDeadline(ctx context.Context, address address.Address, key types.TipSetKey) (*dline.Info, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerPreCommitDepositForPower(ctx context.Context, address address.Address, info miner.SectorPreCommitInfo, key types.TipSetKey) (types.BigInt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerInitialPledgeCollateral(ctx context.Context, address address.Address, info miner.SectorPreCommitInfo, key types.TipSetKey) (types.BigInt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateSearchMsg(ctx context.Context, cid cid.Cid) (*api.MsgLookup, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateGetReceipt(ctx context.Context, cid cid.Cid, key types.TipSetKey) (*types.MessageReceipt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMarketStorageDeal(ctx context.Context, id abi.DealID, key types.TipSetKey) (*api.MarketDeal, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerFaults(ctx context.Context, address address.Address, key types.TipSetKey) (bitfield.BitField, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateMinerRecoveries(ctx context.Context, address address.Address, key types.TipSetKey) (bitfield.BitField, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) StateAccountKey(ctx context.Context, address address.Address, key types.TipSetKey) (address.Address, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) GasEstimateMessageGas(ctx context.Context, message *types.Message, spec *api.MessageSendSpec, key types.TipSetKey) (*types.Message, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainGetBlockMessages(ctx context.Context, cid cid.Cid) (*api.BlockMessages, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainReadObj(ctx context.Context, cid cid.Cid) ([]byte, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainHasObj(ctx context.Context, cid cid.Cid) (bool, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) WalletSign(ctx context.Context, address address.Address, bytes []byte) (*crypto.Signature, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) WalletBalance(ctx context.Context, address address.Address) (types.BigInt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (m *mockStorageMinerAPI) WalletHas(ctx context.Context, address address.Address) (bool, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
+41
-12
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
@@ -41,8 +42,10 @@ type WindowPoStScheduler struct {
|
||||
activeDeadline *dline.Info
|
||||
abort context.CancelFunc
|
||||
|
||||
//failed abi.ChainEpoch // eps
|
||||
//failLk sync.Mutex
|
||||
evtTypes [4]journal.EventType
|
||||
|
||||
// failed abi.ChainEpoch // eps
|
||||
// failLk sync.Mutex
|
||||
}
|
||||
|
||||
func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb storage.Prover, ft sectorstorage.FaultTracker, actor address.Address, worker address.Address) (*WindowPoStScheduler, error) {
|
||||
@@ -66,6 +69,12 @@ func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb
|
||||
|
||||
actor: actor,
|
||||
worker: worker,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeWdPoStScheduler: journal.J.RegisterEventType("wdpost", "scheduler"),
|
||||
evtTypeWdPoStProofs: journal.J.RegisterEventType("wdpost", "proofs_processed"),
|
||||
evtTypeWdPoStRecoveries: journal.J.RegisterEventType("wdpost", "recoveries_processed"),
|
||||
evtTypeWdPoStFaults: journal.J.RegisterEventType("wdpost", "faults_processed"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -101,7 +110,7 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) {
|
||||
select {
|
||||
case changes, ok := <-notifs:
|
||||
if !ok {
|
||||
log.Warn("WindowPoStScheduler notifs channel closed")
|
||||
log.Warn("window post scheduler notifs channel closed")
|
||||
notifs = nil
|
||||
continue
|
||||
}
|
||||
@@ -111,12 +120,13 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) {
|
||||
log.Errorf("expected first notif to have len = 1")
|
||||
continue
|
||||
}
|
||||
if changes[0].Type != store.HCCurrent {
|
||||
chg := changes[0]
|
||||
if chg.Type != store.HCCurrent {
|
||||
log.Errorf("expected first notif to tell current ts")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := s.update(ctx, changes[0].Val); err != nil {
|
||||
if err := s.update(ctx, chg.Val); err != nil {
|
||||
log.Errorf("%+v", err)
|
||||
}
|
||||
|
||||
@@ -141,10 +151,10 @@ func (s *WindowPoStScheduler) Run(ctx context.Context) {
|
||||
}
|
||||
|
||||
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 {
|
||||
log.Error("handling head updates in windowPost sched: %+v", err)
|
||||
log.Error("handling head updates in window post sched: %+v", err)
|
||||
}
|
||||
|
||||
span.End()
|
||||
@@ -174,7 +184,7 @@ func (s *WindowPoStScheduler) revert(ctx context.Context, newLowest *types.TipSe
|
||||
|
||||
func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) error {
|
||||
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())
|
||||
@@ -196,7 +206,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err
|
||||
// (Need to get correct deadline above, which is tricky)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -206,7 +216,7 @@ func (s *WindowPoStScheduler) update(ctx context.Context, new *types.TipSet) err
|
||||
s.activeEPS = 0
|
||||
}
|
||||
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)
|
||||
|
||||
@@ -220,10 +230,29 @@ func (s *WindowPoStScheduler) abortActivePoSt() {
|
||||
|
||||
if s.abort != nil {
|
||||
s.abort()
|
||||
}
|
||||
|
||||
log.Warnf("Aborting Window PoSt (Deadline: %+v)", s.activeDeadline)
|
||||
journal.J.RecordEvent(s.evtTypes[evtTypeWdPoStScheduler], func() interface{} {
|
||||
return WdPoStSchedulerEvt{
|
||||
evtCommon: s.getEvtCommon(nil),
|
||||
State: SchedulerStateAborted,
|
||||
}
|
||||
})
|
||||
|
||||
log.Warnf("Aborting window post (Deadline: %+v)", s.activeDeadline)
|
||||
}
|
||||
|
||||
s.activeDeadline = nil
|
||||
s.abort = nil
|
||||
}
|
||||
|
||||
// getEvtCommon populates and returns common attributes from state, for a
|
||||
// WdPoSt journal event.
|
||||
func (s *WindowPoStScheduler) getEvtCommon(err error) evtCommon {
|
||||
c := evtCommon{Error: err}
|
||||
if s.cur != nil {
|
||||
c.Deadline = s.activeDeadline
|
||||
c.Height = s.cur.Height()
|
||||
c.TipSet = s.cur.Cids()
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user