Compare commits

...
179 Commits
Author SHA1 Message Date
Aayush Rajasekaran 4121063ca4 Merge pull request #3905 from filecoin-project/asr/changelog
Lotus version 0.7.1
2020-09-17 21:32:04 -04:00
Aayush Rajasekaran aa081dbc6d Lotus version 0.7.1 2020-09-17 21:31:47 -04:00
Łukasz Magiera 984eee8cd6 Merge pull request #3909 from filecoin-project/fix/post-no-skip
wdpost: Only add proven partitions to message params
2020-09-18 03:14:05 +02:00
Łukasz Magiera 26bbd9fb9d wdpost: append is hard 2020-09-18 03:00:31 +02:00
Łukasz Magiera 57c1eac37a gofmt 2020-09-18 02:40:01 +02:00
Łukasz Magiera 8419dda84b wdpost: Only add proven partitions to message params 2020-09-18 02:39:08 +02:00
Łukasz Magiera dcc5643473 shed: Even more bitfield utils 2020-09-18 02:38:30 +02:00
Aayush Rajasekaran 1a101e53a6 Merge pull request #3906 from filecoin-project/feat/upgrade-markets-v0.6.1
Upgrade markets v0.6.1
2020-09-17 15:45:53 -04:00
hannahhoward a894c1e8e6 feat(markets): upgrade markets v0.6.1 2020-09-17 12:30:26 -07:00
Łukasz Magiera b85b50afbc shed: bitfield intersect command 2020-09-17 20:37:35 +02:00
Łukasz Magiera 97064f1d15 Merge pull request #3886 from filecoin-project/feat/retrieval-set-get-ask
Add get-ask, set-ask retrieval commands
2020-09-17 10:32:41 +02:00
Ingar Shu f56602c588 Specify retrieval price in FIL/GiB 2020-09-16 14:30:04 -07:00
Łukasz Magiera c66ebc50c1 Merge pull request #3875 from filecoin-project/feat/break-on-stop-sleep
break out of mining loop when stop is called during niceSleep
2020-09-16 23:11:04 +02:00
Ingar Shu 2aef7f7c07 Clarify help text units 2020-09-16 13:56:46 -07:00
Ingar Shu 665d23cb8e Add set-ask, get-ask retrieval CLI 2020-09-16 13:56:46 -07:00
Łukasz Magiera 3b00c6838a Merge remote-tracking branch 'origin/master' into feat/break-on-stop-sleep 2020-09-16 22:56:21 +02:00
Łukasz Magiera a6b7791d32 lint 2020-09-16 22:56:04 +02:00
Łukasz Magiera 34d31d8124 Merge pull request #3856 from filecoin-project/compile-lotus-soup-testplan
add filecoin-project oni as submodule and compile lotus-soup
2020-09-16 22:54:34 +02:00
Łukasz Magiera 6656e5a6c8 circle: test-lotus-soup -> build-lotus-soup 2020-09-16 22:47:06 +02:00
Łukasz Magiera 487765548e Merge remote-tracking branch 'origin/master' into compile-lotus-soup-testplan 2020-09-16 22:42:54 +02:00
Łukasz Magiera ecd115c002 Merge pull request #3862 from filecoin-project/compile-with-build-flag-testground
make sure lotus compiles with +testground build flag
2020-09-16 22:41:24 +02:00
Raúl Kripalani 5a8ee0dd2a Merge pull request #3861 from filecoin-project/feat/chaos-inspect-runtime 2020-09-16 15:50:08 +01:00
Raúl Kripalani 4fbb322fa2 Merge branch 'master' into feat/chaos-inspect-runtime 2020-09-16 15:37:28 +01:00
Anton Evangelatov 56f223bfc3 add go mod edit for blst deps 2020-09-16 15:19:17 +02:00
Anton Evangelatov 0ff5a71114 update oni to master 2020-09-16 15:13:28 +02:00
Anton Evangelatov b0677ab38e replace lotus and filecoin-ffi deps 2020-09-16 15:12:41 +02:00
Anton Evangelatov f4f80b25d1 add test-lotus-soup to workflows 2020-09-16 15:12:41 +02:00
Anton Evangelatov 3f67c4524e add filecoin-project oni as submodule and compile lotus-soup 2020-09-16 15:12:41 +02:00
Anton Evangelatov b4115021c5 make sure lotus compiles with +testground build flag 2020-09-16 13:43:28 +02:00
Łukasz Magiera b78ffd18c6 Merge pull request #3883 from filcloud/Update-ignore
add lotus-pcr to ignore
2020-09-16 13:39:01 +02:00
Łukasz Magiera c9a8f3b8a0 Merge pull request #3874 from filecoin-project/asr/deal-duration
Make interactive deal CLI reject deals shorter than minimum duration
2020-09-16 13:08:47 +02:00
Frank d870c74a5e add lotus-pcr to ignore 2020-09-16 19:08:47 +08:00
Łukasz Magiera 3d61a37fcf Merge pull request #3880 from filecoin-project/fix/gas-outputs-regression
fix a regression caused by #3800 (GasOutputs zero values)
2020-09-16 12:24:22 +02:00
Łukasz Magiera 0c41522ebf Merge pull request #3873 from filecoin-project/unify-wdpost-log
Use `window post` for window PoSt related log messages.
2020-09-16 12:00:45 +02:00
Raúl Kripalani 362fc180ec fix a regression caused by #3800. 2020-09-16 10:54:26 +01:00
Łukasz Magiera 2db7b8c998 Merge pull request #3872 from zgfzgf/master
Replace fx.Extract with fx.Populate
2020-09-16 11:50:59 +02:00
Aayush Rajasekaran e04331b07c Merge pull request #3682 from filecoin-project/asr/chainstore-state-tree
Sever chainstore's dependence on the state tree
2020-09-16 00:39:26 -04:00
Travis Person 808051d34e break out of mining loop when stop is called during niceSleep 2020-09-16 02:06:40 +00:00
Aayush Rajasekaran e2cf0c4d4c Make interactive deal CLI reject deals shorter than minimum duration 2020-09-15 21:24:30 -04:00
jennijuju 5c69249ba3 Use window post for window PoSt related log messages. 2020-09-15 21:22:29 -04:00
zgfzgf fa9be9a627 Replace fx.Extract with fx.Populate 2020-09-16 09:14:56 +08:00
Aayush Rajasekaran 937ff4e9ae Add a sync test around blocks with bad nonce messages 2020-09-15 20:55:11 -04:00
Aayush Rajasekaran 952f2c2f1e Sever chainstore's dependence on the state tree 2020-09-15 20:41:34 -04:00
Alan Shaw ed4caac9bf fix: remove network version and total fil 2020-09-15 22:24:09 +01:00
Jakub Sztandera 0c1c19c6ef Merge pull request #3867 from filecoin-project/feat/lotus-bench-repo-dir
allow specification of repo directory in lotus-bench
2020-09-15 23:21:04 +02:00
whyrusleeping 24756ac056 allow specification of repo directory in lotus-bench 2020-09-15 11:55:54 -07:00
Łukasz Magiera d4a7732d0a Merge pull request #3800 from filecoin-project/asr/gascost
Add an API to get detailed gas costs for a message
2020-09-15 19:13:20 +02:00
Alan Shaw ae326ce65d feat: add inspect runtime method to chaos actor 2020-09-15 15:43:37 +01:00
Łukasz Magiera 531b7bf92d Merge pull request #3848 from filecoin-project/feat/state-sector-cli
cli: state sector command
2020-09-15 15:30:04 +02:00
Łukasz Magiera 84fa22110f fix lint 2020-09-15 12:09:43 +02:00
Łukasz Magiera e22aa74865 Merge pull request #3780 from filecoin-project/feat/lotus-gateway
implement initial lotus-gateway program
2020-09-15 12:07:59 +02:00
Łukasz Magiera 285fc69f6a gateway: address review 2020-09-15 11:50:08 +02:00
Łukasz Magiera 72216fe917 Merge pull request #3647 from filecoin-project/fix/enable-strict-basefee-check
re-enable baseFee lower bound check
2020-09-15 11:38:28 +02:00
Łukasz Magiera 692027f625 Merge pull request #3819 from zgfzgf/zgfzgf
optimize Settings.nodeType
2020-09-15 10:42:23 +02:00
Łukasz Magiera 801e01bca0 Merge pull request #3778 from filecoin-project/feat/less-restrictive-read-piece-lock
Allow retrievals while sealing
2020-09-15 10:34:00 +02:00
Łukasz Magiera 6665a9ca69 Merge pull request #3845 from filecoin-project/sync-manager
syncer: make SyncManager an interface.
2020-09-15 10:28:48 +02:00
Łukasz Magiera 1c02a417db Merge pull request #3850 from filecoin-project/asr/msig-avail
Fix MsigGetAvailableBalance
2020-09-15 10:22:27 +02:00
Łukasz Magiera 9ec26e776d Merge pull request #3851 from filecoin-project/fix/paych-status-commands
Fix payment channel status commands
2020-09-15 10:21:16 +02:00
Łukasz Magiera cf82483420 Merge pull request #3689 from filecoin-project/feat/batch-window-PoST
storage: split window PoST submission into multiple messages
2020-09-15 10:17:22 +02:00
Dirk McCormick db998e9c0f fix: storage - move rand generation after proofs 2020-09-15 09:52:55 +02:00
Dirk McCormick f0f15f899c feat: split window PoST messages into batches 2020-09-15 09:43:18 +02:00
hannahhoward 7dc091052a feat(manager): less restrictive storage lock
Use initial less restrictive storage lock when trying to read unsealed data before acquiring more
restrictive lock needed for unsealing
2020-09-14 18:48:14 -07:00
hannahhoward 17e44af542 docs(api): fix api docs 2020-09-14 18:44:45 -07:00
hannahhoward ac8ef29d35 fix(paych): add paych status from to cmd
add missing from to status to list
2020-09-14 18:42:10 -07:00
hannahhoward 48e47ddc23 fix(paych): fix paych status command line 2020-09-14 18:42:10 -07:00
Aayush Rajasekaran 6acd3d6028 Fix MsigGetAvailableBalance 2020-09-14 21:12:32 -04:00
Łukasz Magiera 7fd5c81674 cli: state sector command 2020-09-15 01:36:49 +02:00
Steven Allen f9ea3935ff Merge pull request #3846 from filecoin-project/steb/specs-actors-0.9.10
Update specs-actors to 0.9.10
2020-09-14 14:45:04 -07:00
Steven Allen 9804310cc8 Update specs-actors to 0.9.10
Moves the Keyer type (and helpers) into go-state-types.
2020-09-14 14:32:57 -07:00
Aayush Rajasekaran 07e574db44 Merge pull request #3844 from filecoin-project/steb/specs-actors-0.9.9
Update to specs-actors 0.9.9
2020-09-14 17:19:03 -04:00
Raúl Kripalani dd841f32db syncer: make SyncManager an interface. 2020-09-14 21:58:59 +01:00
Łukasz Magiera 665f93bbb7 Merge pull request #3839 from filecoin-project/fix/skipped-skipping
wdpost: Skip sectors correctly
2020-09-14 21:56:43 +02:00
Steven Allen 32eeb96ce7 Update to specs-actors 0.9.9
This patch changes the runtime interfaces, to make it possible to abstract over them.
2020-09-14 12:47:39 -07:00
vyzo 172bfacae0 compute baseFee for check even in null rounds 2020-09-14 22:20:26 +03:00
vyzo 0a5494dd79 use the factor in getBaseFeeLowerBound 2020-09-14 22:13:37 +03:00
vyzo 044202b37f use conservative base fee lower bound factor for strict checks 2020-09-14 22:13:37 +03:00
vyzo d68ec37942 reenable baseFee lower bound check 2020-09-14 22:13:37 +03:00
Aayush Rajasekaran 0edcae9e04 Fixup new command 2020-09-14 14:40:38 -04:00
Aayush Rajasekaran d1850ea27d Add an API to get detailed gas costs for a message 2020-09-14 14:40:13 -04:00
Aayush Rajasekaran 60a031a713 Lower devnet block time 2020-09-14 14:40:13 -04:00
Łukasz Magiera 8a05fe86d6 wdpost: Skip sectors correctly 2020-09-14 20:33:54 +02:00
Mike Greenberg 8a21198f56 Merge pull request #3765 from ggq89/master
optimize definition of state_heights
2020-09-14 14:19:31 -04:00
Whyrusleeping b212368a70 Merge pull request #2455 from filecoin-project/inmem-journal
make journal pluggable; record deals, sealing, wdpost, mempool events
2020-09-14 11:17:21 -07:00
Raúl Kripalani 954ff32503 fix transitive api dependency on ffi. 2020-09-14 19:01:35 +01:00
Raúl Kripalani 7c13fa95d1 Merge branch 'master' into inmem-journal 2020-09-14 17:01:36 +01:00
Raúl Kripalani 09e9d6d778 deal journal events: wire into markets subscriptions. 2020-09-14 16:20:01 +01:00
Raúl Kripalani 86607452d7 circleci: make lint expend all cores. (#3831)
* circleci: make lint expend all cores.

* i hate yaml.

* now i hate it even more.
2020-09-14 14:18:53 +02:00
Raúl Kripalani 05aa5f2d38 allow customizing disabled journal events + tests. 2020-09-14 13:01:03 +01:00
Raúl Kripalani 6d29d75724 Merge branch 'master' into inmem-journal 2020-09-14 12:17:45 +01:00
Łukasz Magiera 3a34856dfe Merge pull request #3822 from filcloud/issue-2495-make-nested-dir
make nested dir
2020-09-14 13:06:14 +02:00
Aarsh Shah 973738d30f Merge pull request #3767 from filecoin-project/fix/addpiece-retry
Retry Add Piece.
2020-09-14 15:44:48 +05:30
Albert·Gou 747b34c2c8 Update sync.go 2020-09-14 18:00:17 +08:00
Frank dcae513487 make nested dir 2020-09-14 16:49:35 +08:00
Łukasz Magiera 18c025f10e Merge pull request #3777 from filecoin-project/feat/plan-20-blocks
Increase the FeeCap estimation to 20 blocks in a future
2020-09-14 10:20:17 +02:00
Albert·Gou e45a7749b0 Update sync.go 2020-09-14 16:20:01 +08:00
Albert·Gou b7ea145f38 Merge remote-tracking branch 'upstream/master' into master 2020-09-14 16:17:10 +08:00
Aarsh Shah 6c61ff0e9e log error 2020-09-14 12:04:50 +05:30
zgfzgf 45a5eaf913 optimize Settings.nodeType 2020-09-14 11:00:08 +08:00
whyrusleeping 3401cb349b add mpool push and chainHead 2020-09-11 23:07:20 -07:00
whyrusleeping 8b9a3ea6c3 implement initial lotus-gateway program 2020-09-11 20:01:37 -07:00
Jakub Sztandera d5aef296ea Increase the FeeCap estimation to 20 blocks in a future
FeeCap will be set to 10x the current running rate

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-09-11 21:59:51 +02:00
Łukasz Magiera aa83a4c1f5 Merge pull request #3772 from filecoin-project/fix/prune-protect-local
don't prune locally published messages
2020-09-11 21:46:21 +02:00
Łukasz Magiera b83463ca76 Merge pull request #3774 from filecoin-project/fix/paych-status-missing
add paych status command to list
2020-09-11 21:45:25 +02:00
Łukasz Magiera c1ca24e8bc Merge pull request #3775 from filecoin-project/fix/markets-message-cid-update
Fix for PublishDeals message cid changing due to gas
2020-09-11 21:44:56 +02:00
vyzo b78fe0b898 fix deadlock 2020-09-11 21:40:25 +03:00
vyzo bf1036c78f rename priority variable to protected 2020-09-11 21:12:11 +03:00
Ingar Shu 2e3ff9e401 Update market client/provider adapters to WaitForMessage API 2020-09-11 11:00:42 -07:00
Aarsh Shah eabdf74946 changes as per review 2020-09-11 23:15:57 +05:30
vyzo cf9820137c don't prune locally published messages 2020-09-11 20:32:52 +03:00
Raúl Kripalani c017d0fbaf Merge pull request #3768 from filecoin-project/fix/chaos-tests
fix: chaos tests
2020-09-11 15:45:02 +01:00
Alan Shaw 16f7d5801b fix: chaos tests 2020-09-11 15:25:59 +01:00
Aarsh Shah 62b2963781 retry add piece 2020-09-11 16:58:09 +05:30
Raúl Kripalani cd9858420f Merge pull request #3736 from filecoin-project/test/chaos-tests 2020-09-11 12:18:27 +01:00
Łukasz Magiera 4410da98be Merge pull request #3766 from filecoin-project/fix/mpool-prune
refactor getBaseFeeLowerBound, use it to prune less aggressively
2020-09-11 11:40:26 +02:00
Łukasz Magiera b89aa02d77 Merge pull request #3710 from filecoin-project/feat/window-post-faulty-sectors
windowed post generation now returns faulty sectors
2020-09-11 11:15:32 +02:00
vyzo 3dfb3e641b refactor getBaseFeeLowerBound, use it to prune less aggressively 2020-09-11 12:15:03 +03:00
Łukasz Magiera a3f228d05a Merge pull request #3739 from filecoin-project/upd/badger
Upgrade badger
2020-09-11 11:14:39 +02:00
Łukasz Magiera eaf9ebc2ca Merge pull request #3752 from filecoin-project/fix/mpool-replace-auto
Fix mpool replace --auto
2020-09-11 11:12:35 +02:00
Łukasz Magiera 55e4183825 Merge pull request #3754 from filecoin-project/feat/shed-export
Add faster and slimmer option to chain export via lotus-shed
2020-09-11 11:10:41 +02:00
Łukasz Magiera aeb3437a9f lint, docsgen 2020-09-11 10:55:10 +02:00
Albert·Gou 6e7de3c8d9 optimize definition of state_heights
In the same parentstateroot, the one with the smallest height should be selected
2020-09-11 16:52:48 +08:00
Łukasz Magiera d0175392c0 Merge remote-tracking branch 'origin/master' into feat/window-post-faulty-sectors 2020-09-11 10:47:39 +02:00
Łukasz Magiera c4b3970c70 mod tidy 2020-09-11 10:41:24 +02:00
whyrusleeping 72eb17d314 wire skip old messages option through the api 2020-09-10 17:40:47 -07:00
whyrusleeping 0efe5ee7d5 include some other changes 2020-09-10 17:32:30 -07:00
whyrusleeping 0e3dd3cb3b Add faster and slimmer option to chain export via lotus-shed 2020-09-10 17:28:25 -07:00
hannahhoward 56b237e7b8 fix(paych): add status command to list
Add paych status cmd to list of payment channel sub commands
2020-09-10 16:00:23 -07:00
Jakub Sztandera 2865a0367b Fix mpool replace --auto
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-09-11 00:59:57 +02:00
Jakub Sztandera df5750a21c go mod tidy
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-09-10 23:15:56 +02:00
Łukasz Magiera e996a5246b Merge remote-tracking branch 'origin/master' into feat/window-post-faulty-sectors 2020-09-10 22:18:17 +02:00
Łukasz Magiera bbac86f745 gofmt, mod tidy 2020-09-10 22:07:20 +02:00
Łukasz Magiera 22556fb24c Add fil-blst submodule 2020-09-10 22:04:08 +02:00
Łukasz Magiera 2374cb1bc5 Update ffi 2020-09-10 21:44:01 +02:00
Łukasz Magiera c7b0241a48 ffiwrapper: Test skipping corrupted sectors in PoSt 2020-09-10 21:19:26 +02:00
Jakub Sztandera dc85a276cd Upgrade badger
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-09-10 19:17:48 +02:00
Alan Shaw c94ff3430c refactor: use nil value 2020-09-10 14:51:30 +01:00
Alan Shaw a214069586 chore: appease linter 2020-09-10 14:30:52 +01:00
Alan Shaw d4b185be5e test: add chaos actor tests 2020-09-10 14:23:39 +01:00
Łukasz Magiera 5e7737f55d wdpost: Handle skipped sectors correctly 2020-09-10 02:59:37 +02:00
whyrusleeping 7a6ceebb34 windowed post generation now returns faulty sectors 2020-09-09 14:00:15 -07:00
Raúl Kripalani 35a8f7ebca Merge branch 'master' into inmem-journal 2020-09-04 21:02:28 +01:00
Raúl Kripalani 0a4c473a7c fix dangling import. 2020-09-04 12:14:27 +01:00
Raúl Kripalani 1ec534d607 Merge branch 'master' into inmem-journal 2020-09-04 10:55:40 +01:00
Raúl Kripalani 905168e72e fix lint errors. 2020-09-04 10:54:56 +01:00
Raúl Kripalani d46f684bb8 fix test following merge. 2020-09-04 00:05:44 +01:00
Raúl Kripalani 97ff90f8fa fix imports. 2020-09-03 15:51:26 +01:00
Raúl Kripalani 4554c4bda9 fix lotus-bench stale import. 2020-09-02 19:54:13 +01:00
Raúl Kripalani 3206f92063 Merge branch 'master' into inmem-journal 2020-09-02 19:50:52 +01:00
Raúl Kripalani fd04a19544 go mod tidy. 2020-09-02 19:46:57 +01:00
Raúl Kripalani f046af337a split wdpost event into finer-grained ones. 2020-09-02 19:45:25 +01:00
Raúl Kripalani ac152abc75 shuffle code to journal wdpost events. 2020-09-02 19:15:25 +01:00
Raúl Kripalani 0b6a182a44 move InitJournalKey to the top; add godcs on invoke order. 2020-09-02 19:15:07 +01:00
Raúl Kripalani cb8e105a94 reduce diff noise. 2020-08-26 16:44:06 +01:00
Raúl Kripalani efdfd3ee3e Merge branch 'master' into inmem-journal 2020-08-26 16:38:23 +01:00
Raúl Kripalani 4e1ef09751 make journal a global var. 2020-08-26 16:09:37 +01:00
Raúl Kripalani cc859d3948 journal: wdpost: record proofs_processed even if no eligible partitions. 2020-08-11 16:49:18 +01:00
Raúl Kripalani 200b0f72cc mpool/repub: only record in journal if actually repubbing. 2020-08-11 15:06:13 +01:00
Raúl Kripalani 8f19fff1ec fix tests. 2020-08-11 14:47:02 +01:00
Raúl Kripalani b534ab9d3c panic recovery in MaybeRecordEvent; handle nil current tipsets in wdpost. 2020-08-11 14:28:00 +01:00
Raúl Kripalani 2ea5abdfb5 wire journal into miner. 2020-08-11 13:48:32 +01:00
Raúl Kripalani d53c6f2599 storage-fsm: emit sealing state transition notifications. 2020-08-11 13:23:40 +01:00
Raúl Kripalani 5e2c28d7e9 add comment. 2020-08-11 13:10:22 +01:00
Raúl Kripalani bca516b028 Merge remote-tracking branch 'origin/next' into inmem-journal 2020-08-11 12:42:39 +01:00
Raúl Kripalani 92598237c3 Merge branch 'next' into inmem-journal 2020-08-11 12:41:11 +01:00
Raúl Kripalani 5074ce5a38 move in-mem journal to Project Oni. 2020-08-10 15:02:15 +01:00
Raúl Kripalani b8475114ba Merge branch 'next' into inmem-journal 2020-07-21 17:42:51 +01:00
Raúl Kripalani 443473f833 fix tests. 2020-07-21 17:37:06 +01:00
Raúl Kripalani 4e82cf369c rename journal entries to journal events. 2020-07-21 17:32:01 +01:00
Raúl Kripalani d547c2588c record deals events in journal. 2020-07-21 17:26:44 +01:00
Raúl Kripalani cb8e209f78 journal: disable noisy message pool events. 2020-07-21 13:13:09 +01:00
Raúl Kripalani 3bd9d55a15 message pool: write message(s) in journal entries. 2020-07-21 13:10:29 +01:00
Raúl Kripalani d6e6eedd58 pipe sealing events to the journal. 2020-07-21 13:02:51 +01:00
Raúl Kripalani 7459ec6bba add mpool journal events; fix dependency injection. 2020-07-20 16:37:32 +01:00
Raúl Kripalani 226786c1da wip 2020-07-20 14:45:17 +01:00
Raúl Kripalani 4d2d8b2d11 Merge branch 'next' into inmem-journal 2020-07-20 10:38:58 +01:00
Raúl Kripalani becbff0b13 add NilJournal; fix call sites to ChainStore constructor. 2020-07-17 19:10:47 +01:00
Raúl Kripalani 4bcf01938c use new journal from chain/store pkg. 2020-07-17 18:54:26 +01:00
Raúl Kripalani bef7d64e66 refactor EventType construction. 2020-07-17 18:35:15 +01:00
Raúl Kripalani 695f6cfe45 wip in-memory journal. 2020-07-17 14:34:42 +01:00
101 changed files with 3420 additions and 825 deletions
+22 -1
View File
@@ -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:
+2
View File
@@ -10,6 +10,8 @@
/lotus-fountain
/lotus-stats
/lotus-bench
/lotus-gateway
/lotus-pcr
/bench.json
/lotuspond/front/node_modules
/lotuspond/front/build
+6
View File
@@ -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
+24
View File
@@ -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:
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
@@ -29,7 +29,7 @@ func init() {
BuildType |= Build2k
}
const BlockDelaySecs = uint64(30)
const BlockDelaySecs = uint64(4)
const PropagationDelaySecs = uint64(1)
+2 -2
View File
@@ -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)
)
+2 -4
View File
@@ -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()
+2 -1
View File
@@ -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
+17 -16
View File
@@ -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
}
+4 -4
View File
@@ -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 {
+5 -4
View File
@@ -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
+91 -15
View File
@@ -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
}
+15 -7
View File
@@ -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...)
}
+15 -5
View File
@@ -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 -3
View File
@@ -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
}
}
+3 -3
View File
@@ -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 {
+2 -2
View File
@@ -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 {
+3 -3
View File
@@ -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
View File
@@ -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 {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+7 -7
View File
@@ -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)
+43
View File
@@ -662,6 +662,49 @@ func TestDuplicateNonce(t *testing.T) {
require.Equal(t, includedMsg, mft[0].VMMessage().Cid(), "messages for tipset didn't contain expected message")
}
// 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
View File
@@ -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
View File
@@ -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
View File
@@ -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...)
}
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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")
}
+13 -3
View File
@@ -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)
+2 -2
View File
@@ -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()
+1 -1
View File
@@ -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
}
+2 -1
View File
@@ -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);
+90
View File
@@ -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)
}
+112
View File
@@ -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
View File
@@ -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)
}
+123
View File
@@ -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
},
}
+1
View File
@@ -34,6 +34,7 @@ func main() {
genesisVerifyCmd,
mathCmd,
mpoolStatsCmd,
exportChainCmd,
}
app := &cli.App{
+2 -1
View File
@@ -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")
+7
View File
@@ -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 {
+6 -22
View File
@@ -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",
+114
View File
@@ -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
View File
@@ -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,
}
}
+179
View File
@@ -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()
}
+145 -3
View File
@@ -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
}
+1
View File
@@ -15,6 +15,7 @@ func main() {
chaos.SendReturn{},
chaos.MutateStateArgs{},
chaos.AbortWithArgs{},
chaos.InspectRuntimeReturn{},
); err != nil {
panic(err)
}
+50 -2
View File
@@ -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
Vendored Submodule
+1
Submodule extern/fil-blst added at 5f93488fc0
Vendored Submodule
+1
Submodule extern/oni added at 8b7e7d438c
+51 -46
View File
@@ -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
View File
@@ -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) {
+30 -14
View File
@@ -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)
}
+23 -3
View File
@@ -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
}
+6
View File
@@ -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)
+14
View File
@@ -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) {
+11 -2
View File
@@ -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
View File
@@ -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)
+9 -9
View File
@@ -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
+12 -16
View File
@@ -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
View File
@@ -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
}
}
}
+9
View File
@@ -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
)
-152
View File
@@ -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
}
+16
View File
@@ -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 }
+57
View File
@@ -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
}
+49
View File
@@ -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)
}
+102
View File
@@ -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{}
}
+76
View File
@@ -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,
}
})
}
}
+1 -1
View File
@@ -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
}
+3 -3
View File
@@ -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) {
+24 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+2 -2
View File
@@ -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
View File
@@ -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
}
+10
View File
@@ -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
View File
@@ -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"))
}
+17
View File
@@ -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
}
+38 -2
View File
@@ -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
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
View File
@@ -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)
}
+75
View File
@@ -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
View File
@@ -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
}
+305
View File
@@ -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
View File
@@ -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