Compare commits

...
Author SHA1 Message Date
Aayush Rajasekaran 570773259a Merge pull request #10377 from filecoin-project/asr/merge-release-into-master
chore: merge releases into master
2023-03-01 16:13:19 -05:00
Aayush 19f1ad2762 Merge branch 'releases' into asr/merge-release-into-master 2023-03-01 14:18:35 -05:00
Łukasz Magiera 9a2b83064b Merge pull request #10364 from filecoin-project/chore/rm-market-info-lsm
chore: Remove legacy market info from lotus-miner info
2023-03-01 14:21:29 +01:00
ZenGround0andzenground0 544af751cb Fix the overzealous fix (#10366)
Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com>
2023-02-28 09:22:18 -05:00
Łukasz Magiera 807610131a Merge pull request #10331 from filecoin-project/fix/deprecate-wait-quiet
fix: worker: Hide `wait-quiet` cmd
2023-02-28 14:18:54 +01:00
Łukasz Magiera 8142aaa9c8 Merge pull request #10365 from filecoin-project/fix/tune-down-post-parallel-reads
fix: post: Tune down default post-parallel-reads
2023-02-28 12:44:07 +01:00
Phi 4c7d9ad30e Tune down ParallelCheckLimit
Tune down ParallelCheckLimit config default
2023-02-28 11:46:11 +01:00
Phi dd0c4a0a34 Tune down parallel reads
Tuning down the default post-parallel-reads to a conservative number.
2023-02-28 10:25:33 +01:00
Łukasz Magiera 9aba7dc17a chore: Remove legacy market info from lotus-miner info 2023-02-28 09:55:47 +01:00
ZenGround0andzenground0 0c9f697bf6 Two fixes, better logging and comments (#10332)
Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com>
2023-02-23 10:05:18 -05:00
Łukasz Magiera aa7b5c40b8 Merge pull request #10319 from filecoin-project/fix/allinfo-test
fix: tests: Fix TestMinerAllInfo test
2023-02-23 14:16:40 +01:00
Łukasz Magiera abaa53c6a3 Merge pull request #10145 from filecoin-project/hsanjuan/chain-export-range-rebased
perf: chain: export-range
2023-02-23 13:35:12 +01:00
Łukasz Magiera ea57a1aec3 Merge remote-tracking branch 'origin/master' into hsanjuan/chain-export-range-rebased 2023-02-23 13:08:14 +01:00
Phi ab6aaf5013 Hide wait-quiet cmd
Hide `wait-quiet` cmd
2023-02-23 09:46:06 +01:00
Travis Person bf2ac13609 Merge pull request #10283 from filecoin-project/feat/disable-pre-migrations
feat: stmgr: add env to disable premigrations
2023-02-21 09:23:13 -08:00
Aayush Rajasekaran 392d3d4b8a Merge pull request #10320 from filecoin-project/fix/flaky-workerkeychange
fix: tests: Make TestWorkerKeyChange not flaky
2023-02-20 12:47:16 -05:00
Łukasz Magiera 51aecb6b17 fix: tests: Make TestWorkerKeyChange not flaky 2023-02-20 17:38:18 +01:00
Łukasz Magiera d2c0603717 fix: tests: Fix TestMinerAllInfo test 2023-02-20 14:11:49 +01:00
Łukasz Magiera 3841e5444f Merge pull request #10308 from filecoin-project/asr/merge-release-into-master
chore: merge release/v1.20.0 into master
2023-02-20 14:05:15 +01:00
Travis Person 2dcaddf61d feat: stmgr: add env to disable premigrations
Setting the environment variable `LOTUS_DISABLE_PRE_MIGRATIONS=1` will
discard premigrations for all upgrade.
2023-02-17 23:12:26 +00:00
Steven Allen e51f3e9b15 fix: eth: incorrect struct tags (#10309) 2023-02-17 15:06:58 -08:00
Steven Allen 73102e9432 test: eth: make sure we can deploy a new placeholder on transfer (#10281)
We have a test that triggers smart-contract logic on "transfers", but nothing that tries to create a new actor as a side-effect of a transfer.

fixes https://github.com/filecoin-project/ref-fvm/issues/1670
2023-02-17 13:29:53 -08:00
Aayush 984b4c78cb Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-02-17 16:08:22 -05:00
Łukasz Magiera 8f1c23296e Merge pull request #10169 from filecoin-project/feat/shed-read-sector
feat: shed: Add a tool to read data from sectors
2023-02-16 17:11:37 +01:00
Łukasz Magiera 12656b05fe feat: shed: Add a tool for removing sector data 2023-02-16 16:47:13 +01:00
Łukasz Magiera 285dfed338 Merge pull request #10202 from filecoin-project/feat/faster-sectors-list
sp cli: make sectors list much faster
2023-02-15 19:59:17 +01:00
Łukasz Magiera 6028d7ba18 sectors list: Explain http mode 2023-02-15 19:41:46 +01:00
Aayush Rajasekaran 29a82cdf0f Merge pull request #10272 from filecoin-project/asr/merge-release-into-master
chore: merge release branch into master
2023-02-15 09:47:54 -05:00
Aayush 75c744a438 Merge branch 'release/v1.20.0' 2023-02-14 20:29:14 -05:00
Hector Sanjuan 7ecc00090e range-export: make gen 2023-02-14 21:08:10 +01:00
Hector Sanjuan a2475bca94 range-export: write files to lotus repo path 2023-02-14 21:08:10 +01:00
Hector Sanjuan be1614a042 range-export: check serverside that head > tail 2023-02-14 21:08:10 +01:00
Hector Sanjuan ec01036871 Ranged export: remove non-internal ranged export method
Additionally, per feedback:

* Set "admin" permissions
* Remove from v0api
2023-02-14 21:08:10 +01:00
Hector Sanjuan 1bb698619c Ranged-export: Remove CachingBlockstore
The improvements in the range-export code lead to avoid reading most blocks
twice, as well as to allowing some blocks to be written to disk multiple times.

The cache hit-rate went down from being close to 50% to a maximum of 12% at
the very end of the export. The reason is that most CIDs are never read twice
since they are correctly tracked in the CID set.

These numbers do not support the maintenance of the CachingBlockstore
code. Additional testing shows that removing it has similar memory-usage
behaviour and about 5 minute-faster execution (around 10%).

Less code to maintain and less options to mess up with.
2023-02-14 21:08:10 +01:00
Hector Sanjuan fa93c23813 Chain ranged export: rework and address current shortcomings
This commit moderately refactors the ranged export code. It addresses several
problems:
  * Code does not finish cleanly and things hang on ctrl-c
  * Same block is read multiple times in a row (artificially increasing cached
    blockstore metrics to 50%)
  * It is unclear whether there are additional races (a single worker quits
    when reaching height 0)
  * CARs produced have duplicated blocks (~400k for an 80M-blocks CAR or
    so). Some blocks appear up to 5 times.
  * Using pointers for tasks where it is not necessary.

The changes:

  * Use a FIFO instead of stack: simpler implementation as its own type. This
has not proven to be much more memory-friendly, but it has not made things
worse either.
  * We avoid a probably not small amount of allocations by not using
    unnecessary pointers.
  * Fix duplicated blocks by atomically checking+adding to CID set.
  * Context-termination now works correctly. Worker lifetime is correctly tracked and all channels
  are closed, avoiding any memory leaks and deadlocks.
  * We ensure all work is finished before finishing, something that might have
  been broken in some edge cases previously. In practice, we would not have
  seen this except perhaps in very early snapshots close to genesis.

Initial testing shows the code is currently about 5% faster. Resulting
snapshots do not have duplicates so they are a bit smaller. We have manually
verified that no CID is lost versus previous results, with both old and recent
snapshots.
2023-02-14 21:08:10 +01:00
frrist 21efd481d8 First efficient ranged-export implementation by @frisst
This first commit contains the first and second implementation stabs (after
primary review by @hsanjuan), using a stack for task buffering.

Known issues: ctrl-c (context cancellation) results in the export code getting
deadlocked. Duplicate blocks in exports. Duplicate block reads from store.

Original commit messages:

works

works against mainnet and calibnet

feat: add internal export api method

- will hopfully make things faster by not streaming the export over the json rpc api

polish: better file nameing

fix: potential race in marking cids as seen

chore: improve logging

feat: front export with cache

fix: give hector a good channel buffer on this shit

docsgen
2023-02-14 15:41:10 +01:00
Łukasz Magiera 61f29a84b5 Merge pull request #10238 from filecoin-project/asr/merge-release-into-master
chore: merge release/v1.20.0 into master
2023-02-13 15:25:23 +01:00
Łukasz Magiera d108565ea2 Merge remote-tracking branch 'origin/master' into asr/merge-release-into-master 2023-02-13 13:40:32 +01:00
Łukasz Magiera 7486227c27 Merge remote-tracking branch 'origin/release/v1.20.0' into asr/merge-release-into-master 2023-02-13 13:14:09 +01:00
Łukasz Magiera 4d20011b78 Merge pull request #10249 from filecoin-project/jen/bumpmaster
build: bump version to v1.21.0-dev
2023-02-13 13:05:03 +01:00
Łukasz Magiera e6b0ee7e4a Merge pull request #10247 from filecoin-project/jen/ipld
dep: ipld: update ipld prime to v0.20.0
2023-02-13 13:03:44 +01:00
Raúl Kripalani 8ff55c027e Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-02-13 11:45:09 +00:00
Jennifer Wang e73a038fe8 bump version to v1.21.0-dev 2023-02-13 00:00:07 -05:00
Jennifer Wang 94063ea4d1 update ipld prime 2023-02-12 23:33:19 -05:00
Aayush 63b03a48d0 Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-02-10 18:39:51 -05:00
Łukasz Magiera 7aa6663127 Merge pull request #10232 from filecoin-project/worker-all-task-flag2
fix: worker: add all tasks flag
2023-02-10 12:59:47 +01:00
Łukasz Magiera ec1b2b959a Merge pull request #9973 from placer14/mg/chore/expose-compaction-poolsize-envvar
feat: blockstore: Envvar can adjust badger compaction worker poolsize
2023-02-10 11:38:08 +01:00
Phi-rjan 9848e0467e Merge pull request #10209 from filecoin-project/fix-check-backupfile
fix: cli: error if backup file already exists
2023-02-09 18:39:17 +01:00
Łukasz Magiera 17adcb77c3 sp cli: correct order in parallel sectors list 2023-02-09 17:02:41 +01:00
Łukasz Magiera 81e056be1a sp cli: make sectors list much faster 2023-02-09 16:57:08 +01:00
Łukasz Magiera 25babace8f Merge pull request #10208 from filecoin-project/fix/seal-delay-seconds
fix: cli: option to set-seal-delay in seconds
2023-02-09 16:51:20 +01:00
Phi-rjanandŁukasz Magiera 0e7cf61888 Update cli/backup.go
Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com>
2023-02-09 16:50:15 +01:00
Łukasz Magiera cb8e2836bb Merge pull request #10184 from filecoin-project/asr/merge-release-into-master
chore: merge release/v1.20.0 into master
2023-02-09 16:41:58 +01:00
Phi b78cbcbb99 Error if backup file exists
Error out if backup file already exists
2023-02-08 11:33:48 +01:00
Phi bd4dc217af make docsgen-cli
make docsgen-cli
2023-02-08 09:36:52 +01:00
Phi 662fc37976 Option to set-seal-delay seconds
Add the option to set-seal-delay in seconds
2023-02-08 09:34:44 +01:00
Phi 4823322154 retry make docsgen-cli
retry make docsgen-cli with the new usage
2023-02-07 17:44:54 +01:00
Phi b217eec84d Merge branch 'worker-all-task-flag' of https://github.com/filecoin-project/lotus into worker-all-task-flag 2023-02-07 17:12:56 +01:00
Phi d75f77b4c5 make docsgen-cli
make docsgen-cli
2023-02-07 17:12:42 +01:00
Aayush Rajasekaran 693f230fbb Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-02-07 11:03:01 -05:00
Phi-rjanandŁukasz Magiera 21d6020179 Update cmd/lotus-worker/tasks.go
Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com>
2023-02-07 16:47:30 +01:00
Phi-rjanandŁukasz Magiera 3fc1346d5b Update cmd/lotus-worker/tasks.go
Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com>
2023-02-07 16:47:23 +01:00
Phi-rjanandŁukasz Magiera 58c7c514c6 Update cmd/lotus-worker/tasks.go
Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com>
2023-02-07 16:47:16 +01:00
Phi cf0997b434 fix: worker: add all task type flag
Add all flag for the `lotus-worker tasks enable/disable` cmd
2023-02-07 16:12:31 +01:00
Łukasz Magiera 8066833b3a Merge pull request #10198 from filecoin-project/asr/gas-limit
chain: explicitly check that gasLimit is above zero
2023-02-07 03:38:58 +01:00
Łukasz Magiera e0d92a13a7 Merge pull request #10172 from ribasushi/fix/respect_nofsync
fix: extend LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC to the markset
2023-02-07 03:18:58 +01:00
Aayush Rajasekaran 6a268cfb63 chain: explicitly check that gasLimit is above zero 2023-02-06 17:53:00 -05:00
Aayush f291572b4a Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-02-03 09:27:04 -05:00
Geoff Stuart 9b071bc96b Merge pull request #10182 from 0x5459/fix-louts-miner-extend-cmd
fix: cli: extend cmd to get the right sector number
2023-02-03 06:36:19 -05:00
0x5459 e1c00bdbba cli: fix extend cmd to get the right sector number 2023-02-03 14:56:54 +08:00
Geoff Stuart f88fc0719f Merge pull request #10155 from omahs/patch-1
Fix: typos
2023-02-01 17:47:17 -05:00
Peter Rabbitson 818b3b8daf fix: extend LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC to the markset
Without doing this walking a badger markset on a non-nvme knocks the
node hopelessly out of sync during a compaction.
2023-02-01 21:00:39 +01:00
Łukasz Magiera 7060150bdc Merge pull request #10149 from FlattestWhite/richard/make-user-agent-dependency-injectable
feat: Allow libp2p user agent to be overriden
2023-02-01 19:12:08 +01:00
Łukasz Magiera 0a35e9659b feat: shed: Add a tool to read data from sectors 2023-02-01 17:51:12 +01:00
omahs 28101be1b7 Fix: typos
Fix: typos
2023-01-31 23:33:11 +01:00
omahs 7d5c7f5fec Fix: typos
Fix: typos
2023-01-31 23:30:09 +01:00
omahs ed63798082 Fix: typo
Fix: typo
2023-01-31 23:28:24 +01:00
omahs 05c5e18899 Fix: typo
Fix: typo
2023-01-31 23:27:40 +01:00
omahs 0c17d78356 Fix: typo
Fix: typo
2023-01-31 23:25:26 +01:00
omahs fa97016573 Fix: typos
Fix: typos
2023-01-31 23:23:42 +01:00
omahs 37d41f3f83 Fix: typo
Fix: typo
2023-01-31 23:20:20 +01:00
Richard Guan 45ceb5d297 move UserAgentOption upwards 2023-01-31 21:46:24 +09:00
Richard Guan a8dace0f23 make libp2p user agent overridable 2023-01-31 21:40:55 +09:00
Phi-rjan b8e7262b14 Merge pull request #10147 from filecoin-project/fix/add-args-usage 2023-01-31 13:03:13 +01:00
Phi b334b2055f fix: cli: add ArgsUsage
fix: cli: add ArgsUsage
2023-01-31 11:56:55 +01:00
Łukasz Magiera 13fc5b688f Merge pull request #10028 from filecoin-project/gstuart/cli-color-cleanup
chore: cli: Remove unneeded individual color flags
2023-01-31 09:23:16 +01:00
Łukasz Magiera beb70a3db1 Merge pull request #10116 from filecoin-project/fix/rpcenc-hang
fix: rpcenc: Don't hang when source dies
2023-01-31 09:18:51 +01:00
Łukasz Magiera 482e13706f Merge pull request #10138 from Jorropo/go-bitswap-to-libipfs
chore: node: migrate go-bitswap to go-libipfs/bitswap
2023-01-30 22:52:13 +01:00
Jorropo d060df2fb9 chore: node: migrate go-bitswap to go-libipfs/bitswap
This was migrated in https://github.com/ipfs/go-libipfs/pull/63.
2023-01-27 23:10:44 +01:00
Łukasz Magiera 62326b243f Merge pull request #10126 from Jorropo/migrate-go-block-format
chore: all: bump go-libipfs to replace go-block-format
2023-01-27 14:12:23 +01:00
Łukasz Magiera a0771b12eb Merge pull request #9878 from filecoin-project/gstuart/check-allocation-expiry
feat: Check for allocation expiry when waiting to seal sectors
2023-01-27 13:05:09 +01:00
Jorropo f572852d06 chore: all: bump go-libipfs to replace go-block-format
Includes changes from:
- https://github.com/ipfs/go-block-format/pull/37
- https://github.com/ipfs/go-libipfs/pull/58
2023-01-26 17:03:18 +01:00
Łukasz Magiera db9c516429 Merge pull request #10125 from filecoin-project/fix-docker-git-dirty-state
_ci_ / _build_ : Fix dirty git state when building docker images
2023-01-26 16:57:46 +01:00
Ian Davis 0f6003fd68 Check git state in Dockerfile to catch .dockerignore bugs 2023-01-26 15:18:12 +00:00
Ian Davis 17d220524c Always include checked in files in docker context
The .dockerignore file is symlinked to the .gitignore file, and checked
in files should not be removed from our docker context otherwise they
result in dirty git state when we build our images.
2023-01-26 15:18:12 +00:00
Ian Davis 98a9c8310b Remove old Snapcraft and AppDir folders 2023-01-26 15:16:41 +00:00
Ian Davis 7cfb2529ac init git submodules in build-docker CI 2023-01-26 15:16:41 +00:00
Geoff Stuart 5740f17037 Merge pull request #10121 from filecoin-project/feat/better-post-errors
feat: wdpost: Emit more detailed errors
2023-01-26 09:36:11 -05:00
Geoff Stuart c45df789ea Merge pull request #10114 from filecoin-project/fix/cli-cleanup
chore: cli: cleanup cli
2023-01-26 09:25:40 -05:00
Łukasz Magiera aa0d47078f Merge pull request #10120 from filecoin-project/gstuart/update-codeql
chore: ci: Update codeql to v2
2023-01-26 13:50:50 +01:00
Łukasz Magiera fc6721cff7 feat: wdpost: Emit more detailed errors 2023-01-26 11:57:16 +01:00
Phi a0b25b9136 less strict ArgsCheck
Less strict ArgsCheck
2023-01-26 10:13:39 +01:00
Geoff Stuart 0cc63f6896 Enable code ql for release branches 2023-01-26 02:46:45 -05:00
Geoff Stuart 291deaa017 Update codeql to v2 2023-01-26 01:58:29 -05:00
Phi 38dc034499 make docsgen-cli
make docsgen-cli
2023-01-25 17:24:53 +01:00
Łukasz Magiera 128bdc63db fix: rpcenc: Don't hang when source dies 2023-01-25 17:14:37 +01:00
Phi 34f376eb23 chore: cli
Standarize cli/code functions similar to: https://github.com/filecoin-project/lotus/pull/9317

- cctx.NArg() instead of cctx.Args().xxx
- Add check for args and print help on functions that did not have it
2023-01-25 13:13:56 +01:00
Łukasz Magiera 4682e8f326 Merge pull request #10105 from filecoin-project/addr-encode
chore:shed:encode address to bytes
2023-01-24 10:34:47 +01:00
zenground0 f03c7a8880 encode address into byte 2023-01-24 20:18:04 +13:00
Aayush Rajasekaran 4fd81e0c58 Merge pull request #10030 from filecoin-project/asr/merge-release-into-master
chore: merge release/v1.20.0 into master
2023-01-23 13:24:24 -05:00
Aayush 65ac5669a9 Merge branch 'master' into asr/merge-release-into-master 2023-01-23 12:37:24 -05:00
Aayush e9f665214a Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-01-23 12:23:47 -05:00
Geoff Stuart 807a60b4e4 Remove unneeded individual color flags 2023-01-23 11:11:12 -05:00
Łukasz Magiera dd12cad1ef Merge pull request #10100 from filecoin-project/fix/paych-itest-syncwait
fix: itests: Fix flaky paych test
2023-01-23 16:24:42 +01:00
Łukasz Magiera 53015dc3ee Merge pull request #9981 from filecoin-project/masih/dep-up-dixprov
chore: market: Upgrade to index-provider 0.10.0
2023-01-23 12:53:23 +01:00
Łukasz Magiera c8a692046f fix: itests: Fix flaky paych test 2023-01-23 12:02:42 +01:00
Geoff Stuart c8156d0f46 Merge pull request #10096 from filecoin-project/fix-mainnet-docker-ci
Add back <<network>> parameter for docker push
2023-01-22 15:12:14 -05:00
Ian Davis 9d967b084a Add back <<network>> parameter for docker push
This commit reverts a change with the previous fix for this flow:
- https://github.com/filecoin-project/lotus/pull/10088
2023-01-22 16:39:40 +00:00
Aayush 4f199ada40 Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-01-20 17:32:29 -05:00
Geoff Stuart 6d53d0d533 Merge pull request #10088 from filecoin-project/fix-mainnet-docker-ci
Properly balance <<?>> in circleci docker config
2023-01-20 14:36:35 -05:00
Ian Davis d1fa22244f Properly balance <<?>> in circleci docker config 2023-01-20 19:12:22 +00:00
Travis Person 91a6eabab5 Merge pull request #9982 from filecoin-project/feat/obj-stats
feat: add toolshed commands to inspect statetree size
2023-01-19 08:37:32 -08:00
Łukasz Magiera 1dfd08a0dd Merge pull request #10066 from filecoin-project/jen/cherrypic
fix: should not serve non v0 api in v0
2023-01-19 17:26:18 +01:00
Jennifer Wang 901bb153d0 fix: should not serve non v0 api in v1 2023-01-19 11:06:04 -05:00
Travis Person a0c58b5582 feat: add toolshed commands to inspect statetree size 2023-01-19 00:48:22 +00:00
Geoff Stuart 70db738bff Merge pull request #10037 from filecoin-project/feat/lotus-shed-beneficiary-cli
feat: shed: Add beneficiary commands
2023-01-18 18:04:22 -05:00
Łukasz Magiera 0934cf034d Merge pull request #10032 from filecoin-project/feat/cbor-cid
feat:shed:add cid to cbor serialization command
2023-01-18 12:51:05 +01:00
zenground0 72baa3d916 cid -> bytes command 2023-01-17 12:19:04 -07:00
zenground0 14d921f64f Err handle 2023-01-17 09:56:17 -07:00
Łukasz Magiera 2d3f1e0365 Merge pull request #10035 from aschmahmann/fix/filesize-prevents-windows-lib
fix: sealing: stub out the FileSize function on Windows
2023-01-17 12:48:38 +01:00
Phi 51d2a883f0 Beneficiary cmd in lotus-shed
Add `ProposeChangeBeneficiary` and `ConfirmChangeBeneficiary` to lotus-shed
2023-01-17 12:39:55 +01:00
Adin Schmahmann d35818293a fix: stub out the FileSize command so lotus libraries can build on Windows 2023-01-17 01:03:10 -05:00
zenground0 7383a761f6 Fix 2023-01-16 17:54:38 -07:00
zenground0 39ae4b04be Add cid to cbor cmd 2023-01-16 17:50:47 -07:00
Geoff Stuart 34576d0c64 Merge pull request #10003 from filecoin-project/deprecate-snapcraft-appimage
_build_: Remove AppImage and Snapcraft build automation
2023-01-16 11:27:38 -05:00
Ian Davis b60aeccfdc Remove AppImage and Snapcraft build automation 2023-01-16 16:03:35 +00:00
Aayush e715384173 Merge branch 'release/v1.20.0' into asr/merge-release-into-master 2023-01-16 10:51:22 -05:00
Łukasz Magiera 67023886c8 Merge pull request #9920 from filecoin-project/gstuart/extend-or-renew
feat: cli: Refactor renew and remove extend
2023-01-16 16:31:11 +01:00
Geoff Stuart 00a73fd88f Merge pull request #10022 from FlattestWhite/richard/color-flag
feat: lotus-cli: Add global color flag
2023-01-16 10:15:12 -05:00
Richard Guan fc82aab74b add bool flag and gen documentation 2023-01-16 16:14:19 +11:00
Łukasz Magiera bb800fd78d Merge pull request #9910 from filecoin-project/gstuart/deps-caching
feat: ci: make ci more efficient
2023-01-13 20:08:20 +01:00
Łukasz Magiera 287d410fe8 Merge pull request #9995 from filecoin-project/gstuart/remove-workaround
fix: Remove workaround that is no longer needed
2023-01-12 21:01:17 +01:00
Geoff Stuart 923d4128bb Merge pull request #9875 from filecoin-project/gstuart/remove-expired-claim
feat: cli: list claims and remove expired claims
2023-01-12 12:44:21 -05:00
Geoff Stuart 787470c2b4 Remove workaround that is no longer needed 2023-01-12 12:39:57 -05:00
Łukasz Magiera 7a509cf0d8 Merge pull request #9711 from filecoin-project/feat/gomod-diff-script
feat: scripts: go.mod dep diff script
2023-01-12 18:07:14 +01:00
Geoff Stuart 12a06defd1 Check sectors for allocation expiry before committing 2023-01-11 16:24:34 -05:00
Geoff Stuart 0ebdbed30b Refactor renew and remove extend 2023-01-11 14:44:08 -05:00
Łukasz Magiera 9a46682d9d Merge pull request #9481 from consensus-shipyard/adlrocha/cns-iface-master
IPC: Abstract common consensus functions and consensus interface
2023-01-11 14:49:27 +01:00
Geoff Stuart fd1e0ad7a3 rerun fails 2023-01-10 12:55:36 -05:00
Geoff Stuart 3bae3a3bea Reorg some jobs 2023-01-10 12:55:36 -05:00
Geoff Stuart f9404aa55e Try medium+ 2023-01-10 12:55:36 -05:00
Geoff Stuart 7c448afda8 make build step 2023-01-10 12:55:36 -05:00
Geoff Stuart 8519bc21f9 Merge pull request #9969 from filecoin-project/feat/remove-requirements
fix: cli: remove requirements in helptext
2023-01-10 12:52:23 -05:00
Dirk McCormick a02c783f0e fix: dagstore miner api test 2023-01-10 14:50:38 +01:00
Dirk McCormick fea879088c feat: update to go-fil-markets v1.26.0 2023-01-10 14:43:32 +01:00
Masih H. Derkani 45667b7391 Upgrade to index-provider 0.10.0
Upgrade to the latest index-provider and as a result also upgrade
go-fil-markets.

Note that the index-provider go module is renamed and moved to `ipni`
GitHub org.
2023-01-10 13:08:04 +00:00
Mike Greenberg a4a4e04c5e feat(blockstore): Envvar can adjust badger compaction worker poolsize 2023-01-06 17:33:25 -05:00
Phi f8195deb54 fix: cli: remove requirements
Remove the requirements from the `lotus-worker run` cli
2023-01-06 12:43:12 +01:00
Geoff Stuart 6ca975e83a Add cli command to get a list of claims 2022-12-15 01:07:47 -05:00
Geoff Stuart 754f294992 Add cli command for removing expired claims 2022-12-15 01:07:47 -05:00
Alfonso de la Rocha 25edb23c3f minor fix after rebase 2022-12-05 18:22:10 +01:00
Alfonso de la Rocha 075216d9da Merge remote-tracking branch 'upstream/master' into adlrocha/cns-iface-master 2022-12-05 18:16:14 +01:00
Łukasz Magiera db6532c9d7 moddiff: Nicer diff 2022-11-23 21:24:00 +01:00
Łukasz Magiera 985a4bd730 feat: scripts: go.mod dep diff script 2022-11-23 17:41:39 +01:00
Alfonso de la Rocha 0b9b89bf2b minor fix 2022-11-22 10:59:43 +01:00
Alfonso de la Rocha f5b027eda3 address review 2022-11-22 10:52:11 +01:00
Alfonso de la Rocha 0f92bced9d Merge branch 'master' into adlrocha/cns-iface-master 2022-11-22 10:28:18 +01:00
Alfonso de la Rocha c65ab1b277 minor fix 2022-10-14 11:28:43 +02:00
Alfonso de la Rocha 5c2949b59d fix linter 2022-10-14 11:23:05 +02:00
Alfonso de la Rocha ef2200c28e make gen 2022-10-13 17:51:42 +02:00
Alfonso de la Rocha fe675b6fa1 minor fix 2022-10-13 17:16:01 +02:00
Alfonso de la Rocha fa71ed607b more cleaning 2022-10-13 17:07:34 +02:00
Alfonso de la Rocha 3105596c9e Clean pending files from rebase 2022-10-13 17:03:18 +02:00
Alfonso de la Rocha 9bfb73211e fixed RewardFunc 2022-10-13 16:43:02 +02:00
Alfonso de la Rocha 88d3de7afc run make gen to make ci happy 2022-10-13 16:43:02 +02:00
Alfonso de la Rocha 95c0afb99b minor fixes 2022-10-13 16:43:02 +02:00
raulk 653af01235 Eth JSON-RPC API: implement eth_getCode and eth_getStorageAt (#9397) 2022-10-13 16:41:35 +02:00
Kevin LiandRaúl Kripalani 9d1208c9ff api: ethrpc: implement eth_sendRawTransaction (#9334)
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
2022-10-13 16:39:14 +02:00
Alfonso de la Rocha c3ee957cc6 rm signature fns from cns iface 2022-10-13 16:30:25 +02:00
Alfonso de la Rocha 536600c95c added comments to consensus interface 2022-10-13 16:30:25 +02:00
Alfonso de la Rocha 627d6e70a6 parametrized reward function for consensus 2022-10-13 16:30:14 +02:00
Alfonso de la Rocha 43d557e0f4 minor fix 2022-10-13 16:28:45 +02:00
Alfonso de la Rocha 5626c69ce5 wip: abstract common fns required for consensus 2022-10-13 16:28:45 +02:00
120 changed files with 4039 additions and 1785 deletions
+276 -145
View File
@@ -5,6 +5,11 @@ orbs:
executors:
golang:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.18.8
resource_class: medium+
golang-2xl:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.18.8
@@ -14,7 +19,7 @@ executors:
- image: ubuntu:20.04
commands:
prepare:
build-platform-specific:
parameters:
linux:
default: true
@@ -31,22 +36,13 @@ commands:
steps:
- checkout
- git_fetch_all_tags
- run: git submodule sync
- run: git submodule update --init
- when:
condition: <<parameters.linux>>
steps:
- run:
name: Check Go Version
command: |
v=`go version | { read _ _ v _; echo ${v#go}; }`
if [[ $v != `cat GO_VERSION_MIN` ]]; then
echo "GO_VERSION_MIN file does not match the go version being used."
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
exit 1
fi
- run: sudo apt-get update
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
- run: sudo apt-get install python-is-python3
- install-ubuntu-deps
- check-go-version
- when:
condition: <<parameters.darwin>>
steps:
@@ -67,8 +63,7 @@ commands:
name: Install Rust
command: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
- run: git submodule sync
- run: git submodule update --init
- run: make deps lotus
download-params:
steps:
- restore_cache:
@@ -77,7 +72,7 @@ commands:
- 'v26-2k-lotus-params'
paths:
- /var/tmp/filecoin-proof-parameters/
- run: ./lotus fetch-params 2048
- run: ./lotus fetch-params 2048
- save_cache:
name: Save parameters cache
key: 'v26-2k-lotus-params'
@@ -99,12 +94,43 @@ commands:
name: fetch all tags
command: |
git fetch --all
install-ubuntu-deps:
steps:
- run: sudo apt-get update
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
check-go-version:
steps:
- run: |
v=`go version | { read _ _ v _; echo ${v#go}; }`
if [[ $v != `cat GO_VERSION_MIN` ]]; then
echo "GO_VERSION_MIN file does not match the go version being used."
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
exit 1
fi
jobs:
build:
executor: golang
working_directory: ~/lotus
steps:
- checkout
- git_fetch_all_tags
- run: git submodule sync
- run: git submodule update --init
- install-ubuntu-deps
- check-go-version
- run: make deps lotus
- persist_to_workspace:
root: ~/
paths:
- "lotus"
mod-tidy-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go mod tidy -v
- run:
name: Check git diff
@@ -115,13 +141,14 @@ jobs:
test:
description: |
Run tests with gotestsum.
working_directory: ~/lotus
parameters: &test-params
executor:
type: executor
default: golang
go-test-flags:
type: string
default: "-timeout 30m"
default: "-timeout 20m"
description: Flags passed to go test.
target:
type: string
@@ -130,21 +157,22 @@ jobs:
proofs-log-test:
type: string
default: "0"
get-params:
type: boolean
default: false
suite:
type: string
default: unit
description: Test suite name to report to CircleCI.
gotestsum-format:
type: string
default: standard-verbose
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps lotus
no_output_timeout: 30m
- download-params
- install-ubuntu-deps
- attach_workspace:
at: ~/
- when:
condition: << parameters.get-params >>
steps:
- download-params
- run:
name: go test
environment:
@@ -155,12 +183,11 @@ jobs:
mkdir -p /tmp/test-reports/<< parameters.suite >>
mkdir -p /tmp/test-artifacts
gotestsum \
--format << parameters.gotestsum-format >> \
--format standard-verbose \
--junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \
--jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \
-- \
<< parameters.go-test-flags >> \
<< parameters.target >>
--packages="<< parameters.target >>" \
-- << parameters.go-test-flags >>
no_output_timeout: 30m
- store_test_results:
path: /tmp/test-reports
@@ -168,6 +195,7 @@ jobs:
path: /tmp/test-artifacts/<< parameters.suite >>.json
test-conformance:
working_directory: ~/lotus
description: |
Run tests using a corpus of interoperable test vectors for Filecoin
implementations to test their correctness and compliance with the Filecoin
@@ -183,10 +211,9 @@ jobs:
submodule is used.
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps lotus
no_output_timeout: 30m
- install-ubuntu-deps
- attach_workspace:
at: ~/
- download-params
- when:
condition:
@@ -229,7 +256,7 @@ jobs:
build-linux-amd64:
executor: golang
steps:
- prepare
- build-platform-specific
- run: make lotus lotus-miner lotus-worker
- run:
name: check tag and version output match
@@ -248,7 +275,7 @@ jobs:
macos:
xcode: "13.4.1"
steps:
- prepare:
- build-platform-specific:
linux: false
darwin: true
darwin-architecture: amd64
@@ -272,7 +299,7 @@ jobs:
resource_class: filecoin-project/self-hosted-m1
steps:
- run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV"
- prepare:
- build-platform-specific:
linux: false
darwin: true
darwin-architecture: arm64
@@ -330,16 +357,18 @@ jobs:
gofmt:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- run:
command: "! go fmt ./... 2>&1 | read"
gen-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- run: make deps
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go install golang.org/x/tools/cmd/goimports
- run: go install github.com/hannahhoward/cbor-gen-for
- run: make gen
@@ -349,32 +378,29 @@ jobs:
docs-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go install golang.org/x/tools/cmd/goimports
- run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full
- run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner
- run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker
- run: make deps
- run: make docsgen
- run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full
- run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner
- run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker
- run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet
lint: &lint
lint-all:
description: |
Run golangci-lint.
working_directory: ~/lotus
parameters:
executor:
type: executor
default: golang
concurrency:
type: string
default: '2'
description: |
Concurrency used to run linters. Defaults to 2 because NumCPU is not
aware of container CPU limits.
args:
type: string
default: ''
@@ -382,17 +408,14 @@ jobs:
Arguments to pass to golangci-lint
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps
no_output_timeout: 30m
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run:
name: Lint
command: |
golangci-lint run -v --timeout 2m \
--concurrency << parameters.concurrency >> << parameters.args >>
lint-all:
<<: *lint
golangci-lint run -v --timeout 10m \
--concurrency 4 << parameters.args >>
build-docker:
description: >
@@ -494,437 +517,545 @@ jobs:
extra_build_args: --target <<parameters.image>> --build-arg GOFLAGS=-tags=<<parameters.network>>
workflows:
version: 2.1
ci:
jobs:
- build
- lint-all:
concurrency: "16" # expend all docker 2xlarge CPUs.
- mod-tidy-check
- gofmt
- gen-check
- docs-check
requires:
- build
- mod-tidy-check:
requires:
- build
- gofmt:
requires:
- build
- gen-check:
requires:
- build
- docs-check:
requires:
- build
- test:
name: test-itest-api
requires:
- build
suite: itest-api
target: "./itests/api_test.go"
- test:
name: test-itest-batch_deal
requires:
- build
suite: itest-batch_deal
target: "./itests/batch_deal_test.go"
- test:
name: test-itest-ccupgrade
requires:
- build
suite: itest-ccupgrade
target: "./itests/ccupgrade_test.go"
- test:
name: test-itest-cli
requires:
- build
suite: itest-cli
target: "./itests/cli_test.go"
- test:
name: test-itest-deadlines
requires:
- build
suite: itest-deadlines
target: "./itests/deadlines_test.go"
- test:
name: test-itest-deals_512mb
requires:
- build
suite: itest-deals_512mb
target: "./itests/deals_512mb_test.go"
- test:
name: test-itest-deals_anycid
requires:
- build
suite: itest-deals_anycid
target: "./itests/deals_anycid_test.go"
- test:
name: test-itest-deals_concurrent
requires:
- build
suite: itest-deals_concurrent
target: "./itests/deals_concurrent_test.go"
executor: golang-2xl
- test:
name: test-itest-deals_invalid_utf8_label
requires:
- build
suite: itest-deals_invalid_utf8_label
target: "./itests/deals_invalid_utf8_label_test.go"
- test:
name: test-itest-deals_max_staging_deals
requires:
- build
suite: itest-deals_max_staging_deals
target: "./itests/deals_max_staging_deals_test.go"
- test:
name: test-itest-deals_offline
requires:
- build
suite: itest-deals_offline
target: "./itests/deals_offline_test.go"
- test:
name: test-itest-deals_padding
requires:
- build
suite: itest-deals_padding
target: "./itests/deals_padding_test.go"
- test:
name: test-itest-deals_partial_retrieval_dm-level
requires:
- build
suite: itest-deals_partial_retrieval_dm-level
target: "./itests/deals_partial_retrieval_dm-level_test.go"
- test:
name: test-itest-deals_partial_retrieval
requires:
- build
suite: itest-deals_partial_retrieval
target: "./itests/deals_partial_retrieval_test.go"
- test:
name: test-itest-deals_power
requires:
- build
suite: itest-deals_power
target: "./itests/deals_power_test.go"
- test:
name: test-itest-deals_pricing
requires:
- build
suite: itest-deals_pricing
target: "./itests/deals_pricing_test.go"
- test:
name: test-itest-deals_publish
requires:
- build
suite: itest-deals_publish
target: "./itests/deals_publish_test.go"
- test:
name: test-itest-deals_remote_retrieval
requires:
- build
suite: itest-deals_remote_retrieval
target: "./itests/deals_remote_retrieval_test.go"
- test:
name: test-itest-deals_retry_deal_no_funds
requires:
- build
suite: itest-deals_retry_deal_no_funds
target: "./itests/deals_retry_deal_no_funds_test.go"
- test:
name: test-itest-deals
requires:
- build
suite: itest-deals
target: "./itests/deals_test.go"
- test:
name: test-itest-decode_params
requires:
- build
suite: itest-decode_params
target: "./itests/decode_params_test.go"
- test:
name: test-itest-dup_mpool_messages
requires:
- build
suite: itest-dup_mpool_messages
target: "./itests/dup_mpool_messages_test.go"
- test:
name: test-itest-eth_account_abstraction
requires:
- build
suite: itest-eth_account_abstraction
target: "./itests/eth_account_abstraction_test.go"
- test:
name: test-itest-eth_api
requires:
- build
suite: itest-eth_api
target: "./itests/eth_api_test.go"
- test:
name: test-itest-eth_balance
requires:
- build
suite: itest-eth_balance
target: "./itests/eth_balance_test.go"
- test:
name: test-itest-eth_block_hash
requires:
- build
suite: itest-eth_block_hash
target: "./itests/eth_block_hash_test.go"
- test:
name: test-itest-eth_bytecode
requires:
- build
suite: itest-eth_bytecode
target: "./itests/eth_bytecode_test.go"
- test:
name: test-itest-eth_config
requires:
- build
suite: itest-eth_config
target: "./itests/eth_config_test.go"
- test:
name: test-itest-eth_conformance
requires:
- build
suite: itest-eth_conformance
target: "./itests/eth_conformance_test.go"
- test:
name: test-itest-eth_deploy
requires:
- build
suite: itest-eth_deploy
target: "./itests/eth_deploy_test.go"
- test:
name: test-itest-eth_fee_history
requires:
- build
suite: itest-eth_fee_history
target: "./itests/eth_fee_history_test.go"
- test:
name: test-itest-eth_filter
requires:
- build
suite: itest-eth_filter
target: "./itests/eth_filter_test.go"
- test:
name: test-itest-eth_hash_lookup
requires:
- build
suite: itest-eth_hash_lookup
target: "./itests/eth_hash_lookup_test.go"
- test:
name: test-itest-eth_transactions
requires:
- build
suite: itest-eth_transactions
target: "./itests/eth_transactions_test.go"
- test:
name: test-itest-fevm_address
requires:
- build
suite: itest-fevm_address
target: "./itests/fevm_address_test.go"
- test:
name: test-itest-fevm_events
requires:
- build
suite: itest-fevm_events
target: "./itests/fevm_events_test.go"
- test:
name: test-itest-fevm
requires:
- build
suite: itest-fevm
target: "./itests/fevm_test.go"
- test:
name: test-itest-gas_estimation
requires:
- build
suite: itest-gas_estimation
target: "./itests/gas_estimation_test.go"
- test:
name: test-itest-gateway
requires:
- build
suite: itest-gateway
target: "./itests/gateway_test.go"
- test:
name: test-itest-get_messages_in_ts
requires:
- build
suite: itest-get_messages_in_ts
target: "./itests/get_messages_in_ts_test.go"
- test:
name: test-itest-lite_migration
requires:
- build
suite: itest-lite_migration
target: "./itests/lite_migration_test.go"
- test:
name: test-itest-lookup_robust_address
requires:
- build
suite: itest-lookup_robust_address
target: "./itests/lookup_robust_address_test.go"
- test:
name: test-itest-mempool
requires:
- build
suite: itest-mempool
target: "./itests/mempool_test.go"
- test:
name: test-itest-migration_nv17
requires:
- build
suite: itest-migration_nv17
target: "./itests/migration_nv17_test.go"
- test:
name: test-itest-migration_nv18
requires:
- build
suite: itest-migration_nv18
target: "./itests/migration_nv18_test.go"
- test:
name: test-itest-mpool_msg_uuid
requires:
- build
suite: itest-mpool_msg_uuid
target: "./itests/mpool_msg_uuid_test.go"
- test:
name: test-itest-mpool_push_with_uuid
requires:
- build
suite: itest-mpool_push_with_uuid
target: "./itests/mpool_push_with_uuid_test.go"
- test:
name: test-itest-multisig
requires:
- build
suite: itest-multisig
target: "./itests/multisig_test.go"
- test:
name: test-itest-net
requires:
- build
suite: itest-net
target: "./itests/net_test.go"
- test:
name: test-itest-nonce
requires:
- build
suite: itest-nonce
target: "./itests/nonce_test.go"
- test:
name: test-itest-path_detach_redeclare
requires:
- build
suite: itest-path_detach_redeclare
target: "./itests/path_detach_redeclare_test.go"
- test:
name: test-itest-path_type_filters
requires:
- build
suite: itest-path_type_filters
target: "./itests/path_type_filters_test.go"
- test:
name: test-itest-paych_api
requires:
- build
suite: itest-paych_api
target: "./itests/paych_api_test.go"
- test:
name: test-itest-paych_cli
requires:
- build
suite: itest-paych_cli
target: "./itests/paych_cli_test.go"
- test:
name: test-itest-pending_deal_allocation
requires:
- build
suite: itest-pending_deal_allocation
target: "./itests/pending_deal_allocation_test.go"
- test:
name: test-itest-raft_messagesigner
requires:
- build
suite: itest-raft_messagesigner
target: "./itests/raft_messagesigner_test.go"
- test:
name: test-itest-remove_verifreg_datacap
requires:
- build
suite: itest-remove_verifreg_datacap
target: "./itests/remove_verifreg_datacap_test.go"
- test:
name: test-itest-sdr_upgrade
requires:
- build
suite: itest-sdr_upgrade
target: "./itests/sdr_upgrade_test.go"
- test:
name: test-itest-sector_finalize_early
requires:
- build
suite: itest-sector_finalize_early
target: "./itests/sector_finalize_early_test.go"
- test:
name: test-itest-sector_import_full
requires:
- build
suite: itest-sector_import_full
target: "./itests/sector_import_full_test.go"
- test:
name: test-itest-sector_import_simple
requires:
- build
suite: itest-sector_import_simple
target: "./itests/sector_import_simple_test.go"
- test:
name: test-itest-sector_make_cc_avail
requires:
- build
suite: itest-sector_make_cc_avail
target: "./itests/sector_make_cc_avail_test.go"
- test:
name: test-itest-sector_miner_collateral
requires:
- build
suite: itest-sector_miner_collateral
target: "./itests/sector_miner_collateral_test.go"
- test:
name: test-itest-sector_numassign
requires:
- build
suite: itest-sector_numassign
target: "./itests/sector_numassign_test.go"
- test:
name: test-itest-sector_pledge
requires:
- build
suite: itest-sector_pledge
target: "./itests/sector_pledge_test.go"
- test:
name: test-itest-sector_prefer_no_upgrade
requires:
- build
suite: itest-sector_prefer_no_upgrade
target: "./itests/sector_prefer_no_upgrade_test.go"
- test:
name: test-itest-sector_revert_available
requires:
- build
suite: itest-sector_revert_available
target: "./itests/sector_revert_available_test.go"
- test:
name: test-itest-sector_terminate
requires:
- build
suite: itest-sector_terminate
target: "./itests/sector_terminate_test.go"
- test:
name: test-itest-sector_unseal
requires:
- build
suite: itest-sector_unseal
target: "./itests/sector_unseal_test.go"
- test:
name: test-itest-self_sent_txn
requires:
- build
suite: itest-self_sent_txn
target: "./itests/self_sent_txn_test.go"
- test:
name: test-itest-splitstore
requires:
- build
suite: itest-splitstore
target: "./itests/splitstore_test.go"
- test:
name: test-itest-tape
requires:
- build
suite: itest-tape
target: "./itests/tape_test.go"
- test:
name: test-itest-verifreg
requires:
- build
suite: itest-verifreg
target: "./itests/verifreg_test.go"
- test:
name: test-itest-wdpost_config
requires:
- build
suite: itest-wdpost_config
target: "./itests/wdpost_config_test.go"
- test:
name: test-itest-wdpost_dispute
requires:
- build
suite: itest-wdpost_dispute
target: "./itests/wdpost_dispute_test.go"
- test:
name: test-itest-wdpost_no_miner_storage
requires:
- build
suite: itest-wdpost_no_miner_storage
target: "./itests/wdpost_no_miner_storage_test.go"
- test:
name: test-itest-wdpost
requires:
- build
suite: itest-wdpost
target: "./itests/wdpost_test.go"
- test:
name: test-itest-wdpost_worker_config
requires:
- build
suite: itest-wdpost_worker_config
target: "./itests/wdpost_worker_config_test.go"
executor: golang-2xl
- test:
name: test-itest-worker
requires:
- build
suite: itest-worker
target: "./itests/worker_test.go"
executor: golang-2xl
- test:
name: test-itest-worker_upgrade
requires:
- build
suite: itest-worker_upgrade
target: "./itests/worker_upgrade_test.go"
- test:
name: test-unit-cli
requires:
- build
suite: utest-unit-cli
target: "./cli/... ./cmd/... ./api/..."
get-params: true
- test:
name: test-unit-node
requires:
- build
suite: utest-unit-node
target: "./node/..."
- test:
name: test-unit-rest
requires:
- build
suite: utest-unit-rest
target: "./api/... ./blockstore/... ./build/... ./chain/... ./cli/... ./cmd/... ./conformance/... ./extern/... ./gateway/... ./journal/... ./lib/... ./markets/... ./node/... ./paychmgr/... ./storage/... ./tools/..."
executor: golang-2xl
- test:
name: test-unit-storage
requires:
- build
suite: utest-unit-storage
target: "./storage/... ./extern/..."
- test:
go-test-flags: "-run=TestMulticoreSDR"
requires:
- build
suite: multicore-sdr-check
target: "./storage/sealer/ffiwrapper"
proofs-log-test: "1"
- test-conformance:
requires:
- build
suite: conformance
target: "./conformance"
+112 -68
View File
@@ -5,6 +5,11 @@ orbs:
executors:
golang:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.18.8
resource_class: medium+
golang-2xl:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.18.8
@@ -14,7 +19,7 @@ executors:
- image: ubuntu:20.04
commands:
prepare:
build-platform-specific:
parameters:
linux:
default: true
@@ -31,22 +36,13 @@ commands:
steps:
- checkout
- git_fetch_all_tags
- run: git submodule sync
- run: git submodule update --init
- when:
condition: <<parameters.linux>>
steps:
- run:
name: Check Go Version
command: |
v=`go version | { read _ _ v _; echo ${v#go}; }`
if [["[[ $v != `cat GO_VERSION_MIN` ]]"]]; then
echo "GO_VERSION_MIN file does not match the go version being used."
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
exit 1
fi
- run: sudo apt-get update
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
- run: sudo apt-get install python-is-python3
- install-ubuntu-deps
- check-go-version
- when:
condition: <<parameters.darwin>>
steps:
@@ -67,8 +63,7 @@ commands:
name: Install Rust
command: |
curl https://sh.rustup.rs -sSf | sh -s -- -y
- run: git submodule sync
- run: git submodule update --init
- run: make deps lotus
download-params:
steps:
- restore_cache:
@@ -77,7 +72,7 @@ commands:
- 'v26-2k-lotus-params'
paths:
- /var/tmp/filecoin-proof-parameters/
- run: ./lotus fetch-params 2048
- run: ./lotus fetch-params 2048
- save_cache:
name: Save parameters cache
key: 'v26-2k-lotus-params'
@@ -99,12 +94,43 @@ commands:
name: fetch all tags
command: |
git fetch --all
install-ubuntu-deps:
steps:
- run: sudo apt-get update
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
check-go-version:
steps:
- run: |
v=`go version | { read _ _ v _; echo ${v#go}; }`
if [["[[ $v != `cat GO_VERSION_MIN` ]]"]]; then
echo "GO_VERSION_MIN file does not match the go version being used."
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
exit 1
fi
jobs:
build:
executor: golang
working_directory: ~/lotus
steps:
- checkout
- git_fetch_all_tags
- run: git submodule sync
- run: git submodule update --init
- install-ubuntu-deps
- check-go-version
- run: make deps lotus
- persist_to_workspace:
root: ~/
paths:
- "lotus"
mod-tidy-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go mod tidy -v
- run:
name: Check git diff
@@ -115,13 +141,14 @@ jobs:
test:
description: |
Run tests with gotestsum.
working_directory: ~/lotus
parameters: &test-params
executor:
type: executor
default: golang
go-test-flags:
type: string
default: "-timeout 30m"
default: "-timeout 20m"
description: Flags passed to go test.
target:
type: string
@@ -130,21 +157,22 @@ jobs:
proofs-log-test:
type: string
default: "0"
get-params:
type: boolean
default: false
suite:
type: string
default: unit
description: Test suite name to report to CircleCI.
gotestsum-format:
type: string
default: standard-verbose
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps lotus
no_output_timeout: 30m
- download-params
- install-ubuntu-deps
- attach_workspace:
at: ~/
- when:
condition: << parameters.get-params >>
steps:
- download-params
- run:
name: go test
environment:
@@ -155,12 +183,11 @@ jobs:
mkdir -p /tmp/test-reports/<< parameters.suite >>
mkdir -p /tmp/test-artifacts
gotestsum \
--format << parameters.gotestsum-format >> \
--format standard-verbose \
--junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \
--jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \
-- \
<< parameters.go-test-flags >> \
<< parameters.target >>
--packages="<< parameters.target >>" \
-- << parameters.go-test-flags >>
no_output_timeout: 30m
- store_test_results:
path: /tmp/test-reports
@@ -168,6 +195,7 @@ jobs:
path: /tmp/test-artifacts/<< parameters.suite >>.json
test-conformance:
working_directory: ~/lotus
description: |
Run tests using a corpus of interoperable test vectors for Filecoin
implementations to test their correctness and compliance with the Filecoin
@@ -183,10 +211,9 @@ jobs:
submodule is used.
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps lotus
no_output_timeout: 30m
- install-ubuntu-deps
- attach_workspace:
at: ~/
- download-params
- when:
condition:
@@ -229,7 +256,7 @@ jobs:
build-linux-amd64:
executor: golang
steps:
- prepare
- build-platform-specific
- run: make lotus lotus-miner lotus-worker
- run:
name: check tag and version output match
@@ -248,7 +275,7 @@ jobs:
macos:
xcode: "13.4.1"
steps:
- prepare:
- build-platform-specific:
linux: false
darwin: true
darwin-architecture: amd64
@@ -272,7 +299,7 @@ jobs:
resource_class: filecoin-project/self-hosted-m1
steps:
- run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV"
- prepare:
- build-platform-specific:
linux: false
darwin: true
darwin-architecture: arm64
@@ -330,16 +357,18 @@ jobs:
gofmt:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- run:
command: "! go fmt ./... 2>&1 | read"
gen-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- run: make deps
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go install golang.org/x/tools/cmd/goimports
- run: go install github.com/hannahhoward/cbor-gen-for
- run: make gen
@@ -349,32 +378,29 @@ jobs:
docs-check:
executor: golang
working_directory: ~/lotus
steps:
- prepare
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run: go install golang.org/x/tools/cmd/goimports
- run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full
- run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner
- run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker
- run: make deps
- run: make docsgen
- run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full
- run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner
- run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker
- run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet
lint: &lint
lint-all:
description: |
Run golangci-lint.
working_directory: ~/lotus
parameters:
executor:
type: executor
default: golang
concurrency:
type: string
default: '2'
description: |
Concurrency used to run linters. Defaults to 2 because NumCPU is not
aware of container CPU limits.
args:
type: string
default: ''
@@ -382,17 +408,14 @@ jobs:
Arguments to pass to golangci-lint
executor: << parameters.executor >>
steps:
- prepare
- run:
command: make deps
no_output_timeout: 30m
- install-ubuntu-deps
- attach_workspace:
at: ~/
- run:
name: Lint
command: |
golangci-lint run -v --timeout 2m \
--concurrency << parameters.concurrency >> << parameters.args >>
lint-all:
<<: *lint
golangci-lint run -v --timeout 10m \
--concurrency 4 << parameters.args >>
build-docker:
description: >
@@ -494,37 +517,58 @@ jobs:
extra_build_args: --target <<parameters.image>> --build-arg GOFLAGS=-tags=<<parameters.network>>
workflows:
version: 2.1
ci:
jobs:
- build
- lint-all:
concurrency: "16" # expend all docker 2xlarge CPUs.
- mod-tidy-check
- gofmt
- gen-check
- docs-check
requires:
- build
- mod-tidy-check:
requires:
- build
- gofmt:
requires:
- build
- gen-check:
requires:
- build
- docs-check:
requires:
- build
[[- range $file := .ItestFiles -]]
[[ with $name := $file | stripSuffix ]]
- test:
name: test-itest-[[ $name ]]
requires:
- build
suite: itest-[[ $name ]]
target: "./itests/[[ $file ]]"
[[ end ]]
[[- end -]]
[[- if or (eq $name "worker") (eq $name "deals_concurrent") (eq $name "wdpost_worker_config")]]
executor: golang-2xl
[[- end]]
[[- end ]][[- end]]
[[range $suite, $pkgs := .UnitSuites]]
[[- range $suite, $pkgs := .UnitSuites]]
- test:
name: test-[[ $suite ]]
requires:
- build
suite: utest-[[ $suite ]]
target: "[[ $pkgs ]]"
[[if eq $suite "unit-cli"]]get-params: true[[end]]
[[- if eq $suite "unit-rest"]]executor: golang-2xl[[end]]
[[- end]]
- test:
go-test-flags: "-run=TestMulticoreSDR"
requires:
- build
suite: multicore-sdr-check
target: "./storage/sealer/ffiwrapper"
proofs-log-test: "1"
- test-conformance:
requires:
- build
suite: conformance
target: "./conformance"
+10
View File
@@ -173,6 +173,16 @@ type FullNode interface {
// 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) //perm:read
// ChainExportRangeInternal triggers the export of a chain
// CAR-snapshot directly to disk. It is similar to ChainExport,
// except, depending on options, the snapshot can include receipts,
// messages and stateroots for the length between the specified head
// and tail, thus producing "archival-grade" snapshots that include
// all the on-chain data. The header chain is included back to
// genesis and these snapshots can be used to initialize Filecoin
// nodes.
ChainExportRangeInternal(ctx context.Context, head, tail types.TipSetKey, cfg ChainExportConfig) error //perm:admin
// ChainPrune prunes the stored chain state and garbage collects; only supported if you
// are using the splitstore
ChainPrune(ctx context.Context, opts PruneOpts) error //perm:admin
+14
View File
@@ -155,6 +155,20 @@ func (mr *MockFullNodeMockRecorder) ChainExport(arg0, arg1, arg2, arg3 interface
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainExport", reflect.TypeOf((*MockFullNode)(nil).ChainExport), arg0, arg1, arg2, arg3)
}
// ChainExportRangeInternal mocks base method.
func (m *MockFullNode) ChainExportRangeInternal(arg0 context.Context, arg1, arg2 types.TipSetKey, arg3 api.ChainExportConfig) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChainExportRangeInternal", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(error)
return ret0
}
// ChainExportRangeInternal indicates an expected call of ChainExportRangeInternal.
func (mr *MockFullNodeMockRecorder) ChainExportRangeInternal(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainExportRangeInternal", reflect.TypeOf((*MockFullNode)(nil).ChainExportRangeInternal), arg0, arg1, arg2, arg3)
}
// ChainGetBlock mocks base method.
func (m *MockFullNode) ChainGetBlock(arg0 context.Context, arg1 cid.Cid) (*types.BlockHeader, error) {
m.ctrl.T.Helper()
+14 -1
View File
@@ -117,7 +117,7 @@ type EthSubscriberStruct struct {
}
type EthSubscriberMethods struct {
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"`
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true" rpc_method:"eth_subscription"`
}
type EthSubscriberStub struct {
@@ -140,6 +140,8 @@ type FullNodeMethods struct {
ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"`
ChainExportRangeInternal func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error `perm:"admin"`
ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `perm:"read"`
@@ -1439,6 +1441,17 @@ func (s *FullNodeStub) ChainExport(p0 context.Context, p1 abi.ChainEpoch, p2 boo
return nil, ErrNotSupported
}
func (s *FullNodeStruct) ChainExportRangeInternal(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error {
if s.Internal.ChainExportRangeInternal == nil {
return ErrNotSupported
}
return s.Internal.ChainExportRangeInternal(p0, p1, p2, p3)
}
func (s *FullNodeStub) ChainExportRangeInternal(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error {
return ErrNotSupported
}
func (s *FullNodeStruct) ChainGetBlock(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) {
if s.Internal.ChainGetBlock == nil {
return nil, ErrNotSupported
+9
View File
@@ -398,3 +398,12 @@ func (m *MsgUuidMapType) UnmarshalJSON(b []byte) error {
}
return nil
}
// ChainExportConfig holds configuration for chain ranged exports.
type ChainExportConfig struct {
WriteBufferSize int
NumWorkers int
IncludeMessages bool
IncludeReceipts bool
IncludeStateRoots bool
}
+3 -1
View File
@@ -11,6 +11,8 @@ import (
"github.com/ipfs/go-cid"
"go.uber.org/zap"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/system"
)
type BadgerMarkSetEnv struct {
@@ -349,7 +351,7 @@ func (s *BadgerMarkSet) write(seqno int) (err error) {
persist := s.persist
s.mx.RUnlock()
if persist {
if persist && !system.BadgerFsyncDisable { // WARNING: disabling sync makes recovery from crash during critical section unsound
return s.db.Sync()
}
+6 -3
View File
@@ -115,8 +115,6 @@ func (s *SplitStore) HeadChange(_, apply []*types.TipSet) error {
return nil
}
// Prioritize hot store compaction over cold store prune
if epoch-s.baseEpoch > CompactionThreshold {
// it's time to compact -- prepare the transaction and go!
s.beginTxnProtect()
@@ -176,6 +174,8 @@ func (s *SplitStore) protectTipSets(apply []*types.TipSet) {
timestamp := time.Unix(int64(curTs.MinTimestamp()), 0)
doSync := time.Since(timestamp) < SyncWaitTime
go func() {
// we are holding the txnLk while marking
// so critical section cannot delete
if doSync {
defer func() {
s.txnSyncMx.Lock()
@@ -689,7 +689,7 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
log.Infow("cold collection done", "took", time.Since(startCollect))
log.Infow("compaction stats", "hot", hotCnt, "cold", coldCnt)
log.Infow("compaction stats", "hot", hotCnt, "cold", coldCnt, "purge", purgeCnt)
stats.Record(s.ctx, metrics.SplitstoreCompactionHot.M(int64(hotCnt)))
stats.Record(s.ctx, metrics.SplitstoreCompactionCold.M(int64(coldCnt)))
@@ -788,6 +788,9 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
if err := os.Remove(s.coldSetPath()); err != nil {
log.Warnf("error removing coldset: %s", err)
}
if err := os.Remove(s.discardSetPath()); err != nil {
log.Warnf("error removing discardset: %s", err)
}
// we are done; do some housekeeping
s.endTxnProtect()
+2 -2
View File
@@ -329,9 +329,9 @@ func (s *SplitStore) doPrune(curTs *types.TipSet, retainStateP func(int64) bool,
}
s.pruneIndex++
err = s.ds.Put(s.ctx, pruneIndexKey, int64ToBytes(s.compactionIndex))
err = s.ds.Put(s.ctx, pruneIndexKey, int64ToBytes(s.pruneIndex))
if err != nil {
return xerrors.Errorf("error saving compaction index: %w", err)
return xerrors.Errorf("error saving prune index: %w", err)
}
return nil
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -37,7 +37,7 @@ func BuildTypeString() string {
}
// BuildVersion is the local build version
const BuildVersion = "1.20.0"
const BuildVersion = "1.21.0-dev"
func UserVersion() string {
if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" {
+514
View File
@@ -0,0 +1,514 @@
package consensus
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/go-multierror"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/multiformats/go-varint"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network"
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/api"
bstore "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"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/lib/async"
"github.com/filecoin-project/lotus/metrics"
)
// Common operations shared by all consensus algorithm implementations.
var log = logging.Logger("consensus-common")
// RunAsyncChecks accepts a list of checks to perform in parallel.
//
// Each consensus algorithm may choose to perform a set of different
// checks when a new blocks is received.
func RunAsyncChecks(ctx context.Context, await []async.ErrorFuture) error {
var merr error
for _, fut := range await {
if err := fut.AwaitContext(ctx); err != nil {
merr = multierror.Append(merr, err)
}
}
if merr != nil {
mulErr := merr.(*multierror.Error)
mulErr.ErrorFormat = func(es []error) string {
if len(es) == 1 {
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
}
points := make([]string, len(es))
for i, err := range es {
points[i] = fmt.Sprintf("* %+v", err)
}
return fmt.Sprintf(
"%d errors occurred:\n\t%s\n\n",
len(es), strings.Join(points, "\n\t"))
}
return mulErr
}
return nil
}
// CommonBlkChecks performed by all consensus implementations.
func CommonBlkChecks(ctx context.Context, sm *stmgr.StateManager, cs *store.ChainStore,
b *types.FullBlock, baseTs *types.TipSet) []async.ErrorFuture {
h := b.Header
msgsCheck := async.Err(func() error {
if b.Cid() == build.WhitelistedBlock {
return nil
}
if err := checkBlockMessages(ctx, sm, cs, b, baseTs); err != nil {
return xerrors.Errorf("block had invalid messages: %w", err)
}
return nil
})
baseFeeCheck := async.Err(func() error {
baseFee, err := cs.ComputeBaseFee(ctx, baseTs)
if err != nil {
return xerrors.Errorf("computing base fee: %w", err)
}
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
b.Header.ParentBaseFee, baseFee)
}
return nil
})
stateRootCheck := async.Err(func() error {
stateroot, precp, err := sm.TipSetState(ctx, baseTs)
if err != nil {
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
}
if stateroot != h.ParentStateRoot {
msgs, err := cs.MessagesForTipset(ctx, baseTs)
if err != nil {
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
} else {
log.Warn("Messages for tipset with mismatching state:")
for i, m := range msgs {
mm := m.VMMessage()
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
}
}
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", h.ParentStateRoot, stateroot)
}
if precp != h.ParentMessageReceipts {
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
}
return nil
})
return []async.ErrorFuture{
msgsCheck,
baseFeeCheck,
stateRootCheck,
}
}
func IsValidForSending(nv network.Version, act *types.Actor) bool {
// Before nv18 (Hygge), we only supported built-in account actors as senders.
//
// Note: this gate is probably superfluous, since:
// 1. Placeholder actors cannot be created before nv18.
// 2. EthAccount actors cannot be created before nv18.
// 3. Delegated addresses cannot be created before nv18.
//
// But it's a safeguard.
//
// Note 2: ad-hoc checks for network versions like this across the codebase
// will be problematic with networks with diverging version lineages
// (e.g. Hyperspace). We need to revisit this strategy entirely.
if nv < network.Version18 {
return builtin.IsAccountActor(act.Code)
}
// After nv18, we also support other kinds of senders.
if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) {
return true
}
// Allow placeholder actors with a delegated address and nonce 0 to send a message.
// These will be converted to an EthAccount actor on first send.
if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated {
return false
}
// Only allow such actors to send if their delegated address is in the EAM's namespace.
id, _, err := varint.FromUvarint(act.Address.Payload())
return err == nil && id == builtintypes.EthereumAddressManagerActorID
}
func checkBlockMessages(ctx context.Context, sm *stmgr.StateManager, cs *store.ChainStore, b *types.FullBlock, baseTs *types.TipSet) error {
{
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
var pubks [][]byte
for _, m := range b.BlsMessages {
sigCids = append(sigCids, m.Cid())
pubk, err := sm.GetBlsPublicKey(ctx, m.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
}
pubks = append(pubks, pubk)
}
if err := VerifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
}
}
nonces := make(map[address.Address]uint64)
stateroot, _, err := sm.TipSetState(ctx, baseTs)
if err != nil {
return xerrors.Errorf("failed to compute tipsettate for %s: %w", baseTs.Key(), err)
}
st, err := state.LoadStateTree(cs.ActorStore(ctx), stateroot)
if err != nil {
return xerrors.Errorf("failed to load base state tree: %w", err)
}
nv := sm.GetNetworkVersion(ctx, b.Header.Height)
pl := vm.PricelistByEpoch(b.Header.Height)
var sumGasLimit int64
checkMsg := func(msg types.ChainMsg) error {
m := msg.VMMessage()
// Phase 1: syntactic validation, as defined in the spec
minGas := pl.OnChainMessage(msg.ChainLength())
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
return xerrors.Errorf("msg %s invalid for block inclusion: %w", m.Cid(), err)
}
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
// So below is overflow safe
sumGasLimit += m.GasLimit
if sumGasLimit > build.BlockGasLimit {
return xerrors.Errorf("block gas limit exceeded")
}
// Phase 2: (Partial) semantic validation:
// the sender exists and is an account actor, and the nonces make sense
var sender address.Address
if nv >= network.Version13 {
sender, err = st.LookupID(m.From)
if err != nil {
return xerrors.Errorf("failed to lookup sender %s: %w", m.From, err)
}
} else {
sender = m.From
}
if _, ok := nonces[sender]; !ok {
// `GetActor` does not validate that this is an account actor.
act, err := st.GetActor(sender)
if err != nil {
return xerrors.Errorf("failed to get actor: %w", err)
}
if !IsValidForSending(nv, act) {
return xerrors.New("Sender must be an account actor")
}
nonces[sender] = act.Nonce
}
if nonces[sender] != m.Nonce {
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
}
nonces[sender]++
return nil
}
// Validate message arrays in a temporary blockstore.
tmpbs := bstore.NewMemory()
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
bmArr := blockadt.MakeEmptyArray(tmpstore)
for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
}
c, err := store.PutMessage(ctx, tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := bmArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
}
}
smArr := blockadt.MakeEmptyArray(tmpstore)
for i, m := range b.SecpkMessages {
if nv >= network.Version14 && !IsValidSecpkSigType(nv, m.Signature.Type) {
return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
}
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
}
// `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
// in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
kaddr, err := sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to resolve key addr: %w", err)
}
if err := AuthenticateMessage(m, kaddr); err != nil {
return xerrors.Errorf("failed to validate signature: %w", err)
}
c, err := store.PutMessage(ctx, tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := smArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
}
}
bmroot, err := bmArr.Root()
if err != nil {
return xerrors.Errorf("failed to root bls msgs: %w", err)
}
smroot, err := smArr.Root()
if err != nil {
return xerrors.Errorf("failed to root secp msgs: %w", err)
}
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
if err != nil {
return xerrors.Errorf("failed to put msg meta: %w", err)
}
if b.Header.Messages != mrcid {
return fmt.Errorf("messages didnt match message root in header")
}
// Finally, flush.
err = vm.Copy(ctx, tmpbs, cs.ChainBlockstore(), mrcid)
if err != nil {
return xerrors.Errorf("failed to flush:%w", err)
}
return nil
}
// CreateBlockHeader generates the block header from the block template of
// the block being proposed.
func CreateBlockHeader(ctx context.Context, sm *stmgr.StateManager, pts *types.TipSet,
bt *api.BlockTemplate) (*types.BlockHeader, []*types.Message, []*types.SignedMessage, error) {
st, recpts, err := sm.TipSetState(ctx, pts)
if err != nil {
return nil, nil, nil, xerrors.Errorf("failed to load tipset state: %w", err)
}
next := &types.BlockHeader{
Miner: bt.Miner,
Parents: bt.Parents.Cids(),
Ticket: bt.Ticket,
ElectionProof: bt.Eproof,
BeaconEntries: bt.BeaconValues,
Height: bt.Epoch,
Timestamp: bt.Timestamp,
WinPoStProof: bt.WinningPoStProof,
ParentStateRoot: st,
ParentMessageReceipts: recpts,
}
var blsMessages []*types.Message
var secpkMessages []*types.SignedMessage
var blsMsgCids, secpkMsgCids []cid.Cid
var blsSigs []crypto.Signature
nv := sm.GetNetworkVersion(ctx, bt.Epoch)
for _, msg := range bt.Messages {
if msg.Signature.Type == crypto.SigTypeBLS {
blsSigs = append(blsSigs, msg.Signature)
blsMessages = append(blsMessages, &msg.Message)
c, err := sm.ChainStore().PutMessage(ctx, &msg.Message)
if err != nil {
return nil, nil, nil, err
}
blsMsgCids = append(blsMsgCids, c)
} else if IsValidSecpkSigType(nv, msg.Signature.Type) {
c, err := sm.ChainStore().PutMessage(ctx, msg)
if err != nil {
return nil, nil, nil, err
}
secpkMsgCids = append(secpkMsgCids, c)
secpkMessages = append(secpkMessages, msg)
} else {
return nil, nil, nil, xerrors.Errorf("unknown sig type: %d", msg.Signature.Type)
}
}
store := sm.ChainStore().ActorStore(ctx)
blsmsgroot, err := ToMessagesArray(store, blsMsgCids)
if err != nil {
return nil, nil, nil, xerrors.Errorf("building bls amt: %w", err)
}
secpkmsgroot, err := ToMessagesArray(store, secpkMsgCids)
if err != nil {
return nil, nil, nil, xerrors.Errorf("building secpk amt: %w", err)
}
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: blsmsgroot,
SecpkMessages: secpkmsgroot,
})
if err != nil {
return nil, nil, nil, err
}
next.Messages = mmcid
aggSig, err := AggregateSignatures(blsSigs)
if err != nil {
return nil, nil, nil, err
}
next.BLSAggregate = aggSig
pweight, err := sm.ChainStore().Weight(ctx, pts)
if err != nil {
return nil, nil, nil, err
}
next.ParentWeight = pweight
baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
if err != nil {
return nil, nil, nil, xerrors.Errorf("computing base fee: %w", err)
}
next.ParentBaseFee = baseFee
return next, blsMessages, secpkMessages, err
}
// Basic sanity-checks performed when a block is proposed locally.
func validateLocalBlock(ctx context.Context, msg *pubsub.Message) (pubsub.ValidationResult, string) {
stats.Record(ctx, metrics.BlockPublished.M(1))
if size := msg.Size(); size > 1<<20-1<<15 {
log.Errorf("ignoring oversize block (%dB)", size)
return pubsub.ValidationIgnore, "oversize_block"
}
blk, what, err := decodeAndCheckBlock(msg)
if err != nil {
log.Errorf("got invalid local block: %s", err)
return pubsub.ValidationIgnore, what
}
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept, ""
}
func decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
}
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
}
// make sure we have a signature
if blk.Header.BlockSig == nil {
return nil, "missing_signature", fmt.Errorf("block without a signature")
}
return blk, "", nil
}
func validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
// TODO there has to be a simpler way to do this without the blockstore dance
// block headers use adt0
store := blockadt.WrapStore(ctx, cbor.NewCborStore(bstore.NewMemory()))
bmArr := blockadt.MakeEmptyArray(store)
smArr := blockadt.MakeEmptyArray(store)
for i, m := range msg.BlsMessages {
c := cbg.CborCid(m)
if err := bmArr.Set(uint64(i), &c); err != nil {
return err
}
}
for i, m := range msg.SecpkMessages {
c := cbg.CborCid(m)
if err := smArr.Set(uint64(i), &c); err != nil {
return err
}
}
bmroot, err := bmArr.Root()
if err != nil {
return err
}
smroot, err := smArr.Root()
if err != nil {
return err
}
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
if err != nil {
return err
}
if msg.Header.Messages != mrcid {
return fmt.Errorf("messages didn't match root cid in header")
}
return nil
}
@@ -1,4 +1,4 @@
package filcns
package consensus
import (
"context"
@@ -26,7 +26,6 @@ import (
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/cron"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
@@ -55,10 +54,12 @@ func NewActorRegistry() *vm.ActorRegistry {
return inv
}
type TipSetExecutor struct{}
type TipSetExecutor struct {
reward RewardFunc
}
func NewTipSetExecutor() *TipSetExecutor {
return &TipSetExecutor{}
func NewTipSetExecutor(r RewardFunc) *TipSetExecutor {
return &TipSetExecutor{reward: r}
}
func (t *TipSetExecutor) NewActorRegistry() *vm.ActorRegistry {
@@ -226,39 +227,15 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
processedMsgs[m.Cid()] = struct{}{}
}
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
params := &reward.AwardBlockRewardParams{
Miner: b.Miner,
Penalty: penalty,
GasReward: gasReward,
WinCount: b.WinCount,
})
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
}
rwMsg := &types.Message{
From: builtin.SystemActorAddr,
To: reward.Address,
Nonce: uint64(epoch),
Value: types.NewInt(0),
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
GasLimit: 1 << 30,
Method: reward.Methods.AwardBlockReward,
Params: params,
}
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
if actErr != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
}
if em != nil {
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
}
}
if ret.ExitCode != 0 {
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
rErr := t.reward(ctx, vmi, em, epoch, ts, params)
if rErr != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("error applying reward: %w", err)
}
}
+66 -432
View File
@@ -4,46 +4,36 @@ import (
"bytes"
"context"
"errors"
"fmt"
"os"
"strings"
"time"
"github.com/hashicorp/go-multierror"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/multiformats/go-varint"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network"
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
bstore "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"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/lib/async"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
@@ -69,6 +59,39 @@ type FilecoinEC struct {
// the theoretical max height based on systime are quickly rejected
const MaxHeightDrift = 5
var RewardFunc = func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonitor,
epoch abi.ChainEpoch, ts *types.TipSet, params *reward.AwardBlockRewardParams) error {
ser, err := actors.SerializeParams(params)
if err != nil {
return xerrors.Errorf("failed to serialize award params: %w", err)
}
rwMsg := &types.Message{
From: builtin.SystemActorAddr,
To: reward.Address,
Nonce: uint64(epoch),
Value: types.NewInt(0),
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
GasLimit: 1 << 30,
Method: reward.Methods.AwardBlockReward,
Params: ser,
}
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
if actErr != nil {
return xerrors.Errorf("failed to apply reward message: %w", actErr)
}
if em != nil {
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
return xerrors.Errorf("callback failed on reward message: %w", err)
}
}
if ret.ExitCode != 0 {
return xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
}
return nil
}
func NewFilecoinExpectedConsensus(sm *stmgr.StateManager, beacon beacon.Schedule, verifier storiface.Verifier, genesis chain.Genesis) consensus.Consensus {
if build.InsecurePoStValidation {
log.Warn("*********************************************************************************************")
@@ -127,17 +150,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
}
msgsCheck := async.Err(func() error {
if b.Cid() == build.WhitelistedBlock {
return nil
}
if err := filec.checkBlockMessages(ctx, b, baseTs); err != nil {
return xerrors.Errorf("block had invalid messages: %w", err)
}
return nil
})
minerCheck := async.Err(func() error {
if err := filec.minerIsValid(ctx, h.Miner, baseTs); err != nil {
return xerrors.Errorf("minerIsValid failed: %w", err)
@@ -145,17 +157,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
return nil
})
baseFeeCheck := async.Err(func() error {
baseFee, err := filec.store.ComputeBaseFee(ctx, baseTs)
if err != nil {
return xerrors.Errorf("computing base fee: %w", err)
}
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
b.Header.ParentBaseFee, baseFee)
}
return nil
})
pweight, err := filec.store.Weight(ctx, baseTs)
if err != nil {
return xerrors.Errorf("getting parent weight: %w", err)
@@ -166,34 +167,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
b.Header.ParentWeight, pweight)
}
stateRootCheck := async.Err(func() error {
stateroot, precp, err := filec.sm.TipSetState(ctx, baseTs)
if err != nil {
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
}
if stateroot != h.ParentStateRoot {
msgs, err := filec.store.MessagesForTipset(ctx, baseTs)
if err != nil {
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
} else {
log.Warn("Messages for tipset with mismatching state:")
for i, m := range msgs {
mm := m.VMMessage()
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
}
}
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", h.ParentStateRoot, stateroot)
}
if precp != h.ParentMessageReceipts {
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
}
return nil
})
// Stuff that needs worker address
waddr, err := stmgr.GetMinerWorkerRaw(ctx, filec.sm, lbst, h.Miner)
if err != nil {
@@ -255,10 +228,11 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
})
blockSigCheck := async.Err(func() error {
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
if err := verifyBlockSignature(ctx, h, waddr); err != nil {
return xerrors.Errorf("check block signature failed: %w", err)
}
return nil
})
beaconValuesCheck := async.Err(func() error {
@@ -307,44 +281,17 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
return nil
})
await := []async.ErrorFuture{
commonChecks := consensus.CommonBlkChecks(ctx, filec.sm, filec.store, b, baseTs)
await := append([]async.ErrorFuture{
minerCheck,
tktsCheck,
blockSigCheck,
beaconValuesCheck,
wproofCheck,
winnerCheck,
msgsCheck,
baseFeeCheck,
stateRootCheck,
}
}, commonChecks...)
var merr error
for _, fut := range await {
if err := fut.AwaitContext(ctx); err != nil {
merr = multierror.Append(merr, err)
}
}
if merr != nil {
mulErr := merr.(*multierror.Error)
mulErr.ErrorFormat = func(es []error) string {
if len(es) == 1 {
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
}
points := make([]string, len(es))
for i, err := range es {
points[i] = fmt.Sprintf("* %+v", err)
}
return fmt.Sprintf(
"%d errors occurred:\n\t%s\n\n",
len(es), strings.Join(points, "\n\t"))
}
return mulErr
}
return nil
return consensus.RunAsyncChecks(ctx, await)
}
func blockSanityChecks(h *types.BlockHeader) error {
@@ -435,209 +382,6 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
return nil
}
func IsValidForSending(nv network.Version, act *types.Actor) bool {
// Before nv18 (Hygge), we only supported built-in account actors as senders.
//
// Note: this gate is probably superfluous, since:
// 1. Placeholder actors cannot be created before nv18.
// 2. EthAccount actors cannot be created before nv18.
// 3. Delegated addresses cannot be created before nv18.
//
// But it's a safeguard.
//
// Note 2: ad-hoc checks for network versions like this across the codebase
// will be problematic with networks with diverging version lineages
// (e.g. Hyperspace). We need to revisit this strategy entirely.
if nv < network.Version18 {
return builtin.IsAccountActor(act.Code)
}
// After nv18, we also support other kinds of senders.
if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) {
return true
}
// Allow placeholder actors with a delegated address and nonce 0 to send a message.
// These will be converted to an EthAccount actor on first send.
if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated {
return false
}
// Only allow such actors to send if their delegated address is in the EAM's namespace.
id, _, err := varint.FromUvarint(act.Address.Payload())
return err == nil && id == builtintypes.EthereumAddressManagerActorID
}
// TODO: We should extract this somewhere else and make the message pool and miner use the same logic
func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
{
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
var pubks [][]byte
for _, m := range b.BlsMessages {
sigCids = append(sigCids, m.Cid())
pubk, err := filec.sm.GetBlsPublicKey(ctx, m.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
}
pubks = append(pubks, pubk)
}
if err := consensus.VerifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
}
}
nonces := make(map[address.Address]uint64)
stateroot, _, err := filec.sm.TipSetState(ctx, baseTs)
if err != nil {
return xerrors.Errorf("failed to compute tipsettate for %s: %w", baseTs.Key(), err)
}
st, err := state.LoadStateTree(filec.store.ActorStore(ctx), stateroot)
if err != nil {
return xerrors.Errorf("failed to load base state tree: %w", err)
}
nv := filec.sm.GetNetworkVersion(ctx, b.Header.Height)
pl := vm.PricelistByEpoch(b.Header.Height)
var sumGasLimit int64
checkMsg := func(msg types.ChainMsg) error {
m := msg.VMMessage()
// Phase 1: syntactic validation, as defined in the spec
minGas := pl.OnChainMessage(msg.ChainLength())
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
return xerrors.Errorf("msg %s invalid for block inclusion: %w", m.Cid(), err)
}
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
// So below is overflow safe
sumGasLimit += m.GasLimit
if sumGasLimit > build.BlockGasLimit {
return xerrors.Errorf("block gas limit exceeded")
}
// Phase 2: (Partial) semantic validation:
// the sender exists and is an account actor, and the nonces make sense
var sender address.Address
if nv >= network.Version13 {
sender, err = st.LookupID(m.From)
if err != nil {
return xerrors.Errorf("failed to lookup sender %s: %w", m.From, err)
}
} else {
sender = m.From
}
if _, ok := nonces[sender]; !ok {
// `GetActor` does not validate that this is an account actor.
act, err := st.GetActor(sender)
if err != nil {
return xerrors.Errorf("failed to get actor: %w", err)
}
if !IsValidForSending(nv, act) {
return xerrors.New("Sender must be an account actor")
}
nonces[sender] = act.Nonce
}
if nonces[sender] != m.Nonce {
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
}
nonces[sender]++
return nil
}
// Validate message arrays in a temporary blockstore.
tmpbs := bstore.NewMemory()
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
bmArr := blockadt.MakeEmptyArray(tmpstore)
for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
}
c, err := store.PutMessage(ctx, tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := bmArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
}
}
smArr := blockadt.MakeEmptyArray(tmpstore)
for i, m := range b.SecpkMessages {
if nv >= network.Version14 && !chain.IsValidSecpkSigType(nv, m.Signature.Type) {
return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
}
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
}
// `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
// in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
kaddr, err := filec.sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
if err != nil {
return xerrors.Errorf("failed to resolve key addr: %w", err)
}
if err := chain.AuthenticateMessage(m, kaddr); err != nil {
return xerrors.Errorf("failed to validate signature: %w", err)
}
c, err := store.PutMessage(ctx, tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := smArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
}
}
bmroot, err := bmArr.Root()
if err != nil {
return xerrors.Errorf("failed to root bls msgs: %w", err)
}
smroot, err := smArr.Root()
if err != nil {
return xerrors.Errorf("failed to root secp msgs: %w", err)
}
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
if err != nil {
return xerrors.Errorf("failed to put msg meta: %w", err)
}
if b.Header.Messages != mrcid {
return fmt.Errorf("messages didnt match message root in header")
}
// Finally, flush.
err = vm.Copy(ctx, tmpbs, filec.store.ChainBlockstore(), mrcid)
if err != nil {
return xerrors.Errorf("failed to flush:%w", err)
}
return nil
}
func (filec *FilecoinEC) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
if filec.genesis == nil {
return false
@@ -693,140 +437,7 @@ func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []
var ErrSoftFailure = errors.New("soft validation failure")
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
func (filec *FilecoinEC) ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string) {
if self {
return filec.validateLocalBlock(ctx, msg)
}
// track validation time
begin := build.Clock.Now()
defer func() {
log.Debugf("block validation time: %s", build.Clock.Since(begin))
}()
stats.Record(ctx, metrics.BlockReceived.M(1))
recordFailureFlagPeer := func(what string) {
// bv.Validate will flag the peer in that case
panic(what)
}
blk, what, err := filec.decodeAndCheckBlock(msg)
if err != nil {
log.Error("got invalid block over pubsub: ", err)
recordFailureFlagPeer(what)
return pubsub.ValidationReject, what
}
// validate the block meta: the Message CID in the header must match the included messages
err = filec.validateMsgMeta(ctx, blk)
if err != nil {
log.Warnf("error validating message metadata: %s", err)
recordFailureFlagPeer("invalid_block_meta")
return pubsub.ValidationReject, "invalid_block_meta"
}
reject, err := filec.validateBlockHeader(ctx, blk.Header)
if err != nil {
if reject == "" {
log.Warn("ignoring block msg: ", err)
return pubsub.ValidationIgnore, reject
}
recordFailureFlagPeer(reject)
return pubsub.ValidationReject, reject
}
// all good, accept the block
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept, ""
}
func (filec *FilecoinEC) validateLocalBlock(ctx context.Context, msg *pubsub.Message) (pubsub.ValidationResult, string) {
stats.Record(ctx, metrics.BlockPublished.M(1))
if size := msg.Size(); size > 1<<20-1<<15 {
log.Errorf("ignoring oversize block (%dB)", size)
return pubsub.ValidationIgnore, "oversize_block"
}
blk, what, err := filec.decodeAndCheckBlock(msg)
if err != nil {
log.Errorf("got invalid local block: %s", err)
return pubsub.ValidationIgnore, what
}
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept, ""
}
func (filec *FilecoinEC) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
}
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
}
// make sure we have a signature
if blk.Header.BlockSig == nil {
return nil, "missing_signature", fmt.Errorf("block without a signature")
}
return blk, "", nil
}
func (filec *FilecoinEC) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
// TODO there has to be a simpler way to do this without the blockstore dance
// block headers use adt0
store := blockadt.WrapStore(ctx, cbor.NewCborStore(bstore.NewMemory()))
bmArr := blockadt.MakeEmptyArray(store)
smArr := blockadt.MakeEmptyArray(store)
for i, m := range msg.BlsMessages {
c := cbg.CborCid(m)
if err := bmArr.Set(uint64(i), &c); err != nil {
return err
}
}
for i, m := range msg.SecpkMessages {
c := cbg.CborCid(m)
if err := smArr.Set(uint64(i), &c); err != nil {
return err
}
}
bmroot, err := bmArr.Root()
if err != nil {
return err
}
smroot, err := smArr.Root()
if err != nil {
return err
}
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
if err != nil {
return err
}
if msg.Header.Messages != mrcid {
return fmt.Errorf("messages didn't match root cid in header")
}
return nil
}
func (filec *FilecoinEC) validateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error) {
func (filec *FilecoinEC) ValidateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error) {
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
// to prevent spam attacks.
@@ -901,4 +512,27 @@ func (filec *FilecoinEC) isChainNearSynced() bool {
return build.Clock.Since(timestampTime) < 6*time.Hour
}
func verifyBlockSignature(ctx context.Context, h *types.BlockHeader,
addr address.Address) error {
return sigs.CheckBlockSignature(ctx, h, addr)
}
func signBlock(ctx context.Context, w api.Wallet,
addr address.Address, next *types.BlockHeader) error {
nosigbytes, err := next.SigningBytes()
if err != nil {
return xerrors.Errorf("failed to get signing bytes for block: %w", err)
}
sig, err := w.WalletSign(ctx, addr, nosigbytes, api.MsgMeta{
Type: api.MTBlock,
})
if err != nil {
return xerrors.Errorf("failed to sign new block: %w", err)
}
next.BlockSig = sig
return nil
}
var _ consensus.Consensus = &FilecoinEC{}
+3 -99
View File
@@ -3,13 +3,9 @@ package filcns
import (
"context"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
@@ -21,11 +17,6 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
return nil, xerrors.Errorf("failed to load parent tipset: %w", err)
}
st, recpts, err := filec.sm.TipSetState(ctx, pts)
if err != nil {
return nil, xerrors.Errorf("failed to load tipset state: %w", err)
}
_, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, filec.sm, pts, bt.Epoch)
if err != nil {
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
@@ -36,102 +27,15 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
}
next := &types.BlockHeader{
Miner: bt.Miner,
Parents: bt.Parents.Cids(),
Ticket: bt.Ticket,
ElectionProof: bt.Eproof,
BeaconEntries: bt.BeaconValues,
Height: bt.Epoch,
Timestamp: bt.Timestamp,
WinPoStProof: bt.WinningPoStProof,
ParentStateRoot: st,
ParentMessageReceipts: recpts,
}
var blsMessages []*types.Message
var secpkMessages []*types.SignedMessage
var blsMsgCids, secpkMsgCids []cid.Cid
var blsSigs []crypto.Signature
nv := filec.sm.GetNetworkVersion(ctx, bt.Epoch)
for _, msg := range bt.Messages {
if msg.Signature.Type == crypto.SigTypeBLS {
blsSigs = append(blsSigs, msg.Signature)
blsMessages = append(blsMessages, &msg.Message)
c, err := filec.sm.ChainStore().PutMessage(ctx, &msg.Message)
if err != nil {
return nil, err
}
blsMsgCids = append(blsMsgCids, c)
} else if chain.IsValidSecpkSigType(nv, msg.Signature.Type) {
c, err := filec.sm.ChainStore().PutMessage(ctx, msg)
if err != nil {
return nil, err
}
secpkMsgCids = append(secpkMsgCids, c)
secpkMessages = append(secpkMessages, msg)
} else {
return nil, xerrors.Errorf("unknown sig type: %d", msg.Signature.Type)
}
}
store := filec.sm.ChainStore().ActorStore(ctx)
blsmsgroot, err := consensus.ToMessagesArray(store, blsMsgCids)
next, blsMessages, secpkMessages, err := consensus.CreateBlockHeader(ctx, filec.sm, pts, bt)
if err != nil {
return nil, xerrors.Errorf("building bls amt: %w", err)
}
secpkmsgroot, err := consensus.ToMessagesArray(store, secpkMsgCids)
if err != nil {
return nil, xerrors.Errorf("building secpk amt: %w", err)
return nil, xerrors.Errorf("failed to process messages from block template: %w", err)
}
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: blsmsgroot,
SecpkMessages: secpkmsgroot,
})
if err != nil {
return nil, err
}
next.Messages = mmcid
aggSig, err := consensus.AggregateSignatures(blsSigs)
if err != nil {
return nil, err
}
next.BLSAggregate = aggSig
pweight, err := filec.sm.ChainStore().Weight(ctx, pts)
if err != nil {
return nil, err
}
next.ParentWeight = pweight
baseFee, err := filec.sm.ChainStore().ComputeBaseFee(ctx, pts)
if err != nil {
return nil, xerrors.Errorf("computing base fee: %w", err)
}
next.ParentBaseFee = baseFee
nosigbytes, err := next.SigningBytes()
if err != nil {
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
}
sig, err := w.WalletSign(ctx, worker, nosigbytes, api.MsgMeta{
Type: api.MTBlock,
})
if err != nil {
if err := signBlock(ctx, w, worker, next); err != nil {
return nil, xerrors.Errorf("failed to sign new block: %w", err)
}
next.BlockSig = sig
fullBlock := &types.FullBlock{
Header: next,
BlsMessages: blsMessages,
+83 -1
View File
@@ -4,17 +4,99 @@ import (
"context"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"go.opencensus.io/stats"
"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/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/metrics"
)
type Consensus interface {
// ValidateBlockHeader is called by peers when they receive a new block through the network.
//
// This is a fast sanity-check validation performed by the PubSub protocol before delivering
// it to the syncer. It checks that the block has the right format and it performs
// other consensus-specific light verifications like ensuring that the block is signed by
// a valid miner, or that it includes all the data required for a full verification.
ValidateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error)
// ValidateBlock is called by the syncer to determine if to accept a block or not.
//
// It performs all the checks needed by the syncer to accept
// the block (signature verifications, VRF checks, message validity, etc.)
ValidateBlock(ctx context.Context, b *types.FullBlock) (err error)
ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string)
// IsEpochBeyondCurrMax is used to configure the fork rules for longest-chain
// consensus protocols.
IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool
// CreateBlock implements all the logic required to propose and assemble a new Filecoin block.
//
// This function encapsulate all the consensus-specific actions to propose a new block
// such as the ordering of transactions, the inclusion of consensus proofs, the signature
// of the block, etc.
CreateBlock(ctx context.Context, w api.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error)
}
// RewardFunc parametrizes the logic for rewards when a message is executed.
//
// Each consensus implementation can set their own reward function.
type RewardFunc func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonitor,
epoch abi.ChainEpoch, ts *types.TipSet, params *reward.AwardBlockRewardParams) error
// ValidateBlockPubsub implements the common checks performed by all consensus implementations
// when a block is received through the pubsub channel.
func ValidateBlockPubsub(ctx context.Context, cns Consensus, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string) {
if self {
return validateLocalBlock(ctx, msg)
}
// track validation time
begin := build.Clock.Now()
defer func() {
log.Debugf("block validation time: %s", build.Clock.Since(begin))
}()
stats.Record(ctx, metrics.BlockReceived.M(1))
recordFailureFlagPeer := func(what string) {
// bv.Validate will flag the peer in that case
panic(what)
}
blk, what, err := decodeAndCheckBlock(msg)
if err != nil {
log.Error("got invalid block over pubsub: ", err)
recordFailureFlagPeer(what)
return pubsub.ValidationReject, what
}
// validate the block meta: the Message CID in the header must match the included messages
err = validateMsgMeta(ctx, blk)
if err != nil {
log.Warnf("error validating message metadata: %s", err)
recordFailureFlagPeer("invalid_block_meta")
return pubsub.ValidationReject, "invalid_block_meta"
}
reject, err := cns.ValidateBlockHeader(ctx, blk.Header)
if err != nil {
if reject == "" {
log.Warn("ignoring block msg: ", err)
return pubsub.ValidationIgnore, reject
}
recordFailureFlagPeer(reject)
return pubsub.ValidationReject, reject
}
// all good, accept the block
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept, ""
}
@@ -1,4 +1,4 @@
package chain
package consensus
import (
"golang.org/x/xerrors"
+2 -1
View File
@@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/rand"
@@ -255,7 +256,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
//}
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us, beac)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), sys, us, beac)
if err != nil {
return nil, xerrors.Errorf("initing stmgr: %w", err)
}
+2 -2
View File
@@ -38,7 +38,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -486,7 +486,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca
Epoch: 0,
Rand: &fakeRand{},
Bstore: cs.StateBlockstore(),
Actors: filcns.NewActorRegistry(),
Actors: consensus.NewActorRegistry(),
Syscalls: mkFakedSigSyscalls(sys),
CircSupplyCalc: csc,
NetworkVersion: nv,
+2 -2
View File
@@ -40,7 +40,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -94,7 +94,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
Epoch: 0,
Rand: &fakeRand{},
Bstore: cs.StateBlockstore(),
Actors: filcns.NewActorRegistry(),
Actors: consensus.NewActorRegistry(),
Syscalls: mkFakedSigSyscalls(sys),
CircSupplyCalc: csc,
NetworkVersion: nv,
+3 -4
View File
@@ -33,8 +33,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -794,7 +793,7 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
return nil
}
if err := chain.AuthenticateMessage(m, m.Message.From); err != nil {
if err := consensus.AuthenticateMessage(m, m.Message.From); err != nil {
return xerrors.Errorf("failed to validate signature: %w", err)
}
@@ -862,7 +861,7 @@ func (mp *MessagePool) addTs(ctx context.Context, m *types.SignedMessage, curTs
nv := mp.api.StateNetworkVersion(ctx, epoch)
// TODO: I'm not thrilled about depending on filcns here, but I prefer this to duplicating logic
if !filcns.IsValidForSending(nv, senderAct) {
if !consensus.IsValidForSending(nv, senderAct) {
return false, xerrors.Errorf("sender actor %s is not a valid top-level sender", m.Message.From)
}
+10
View File
@@ -4,7 +4,9 @@ import (
"bytes"
"context"
"encoding/binary"
"os"
"sort"
"strings"
"sync"
"time"
@@ -26,6 +28,9 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
)
// EnvDisablePreMigrations when set to '1' stops pre-migrations from running
const EnvDisablePreMigrations = "LOTUS_DISABLE_PRE_MIGRATIONS"
// MigrationCache can be used to cache information used by a migration. This is primarily useful to
// "pre-compute" some migration state ahead of time, and make it accessible in the migration itself.
type MigrationCache interface {
@@ -218,6 +223,11 @@ func runPreMigration(ctx context.Context, sm *StateManager, fn PreMigrationFunc,
height := ts.Height()
parent := ts.ParentState()
if disabled := os.Getenv(EnvDisablePreMigrations); strings.TrimSpace(disabled) == "1" {
log.Warnw("SKIPPING pre-migration", "height", height)
return
}
startTime := time.Now()
log.Warn("STARTING pre-migration")
+75 -6
View File
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"io"
"os"
"sync"
"testing"
@@ -31,6 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin"
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/gen"
. "github.com/filecoin-project/lotus/chain/stmgr"
@@ -128,7 +130,7 @@ func TestForkHeightTriggers(t *testing.T) {
}
sm, err := NewStateManager(
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
Network: network.Version1,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
@@ -169,7 +171,7 @@ func TestForkHeightTriggers(t *testing.T) {
t.Fatal(err)
}
inv := filcns.NewActorRegistry()
inv := consensus.NewActorRegistry()
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
inv.Register(actorstypes.Version0, nil, registry)
@@ -274,7 +276,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
var migrationCount int
sm, err := NewStateManager(
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
Network: network.Version1,
Expensive: true,
Height: testForkHeight,
@@ -287,7 +289,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
t.Fatal(err)
}
inv := filcns.NewActorRegistry()
inv := consensus.NewActorRegistry()
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
inv.Register(actorstypes.Version0, nil, registry)
@@ -412,7 +414,7 @@ func TestForkPreMigration(t *testing.T) {
counter := make(chan struct{}, 10)
sm, err := NewStateManager(
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
Network: network.Version1,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
@@ -509,7 +511,7 @@ func TestForkPreMigration(t *testing.T) {
require.NoError(t, sm.Stop(context.Background()))
}()
inv := filcns.NewActorRegistry()
inv := consensus.NewActorRegistry()
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
inv.Register(actorstypes.Version0, nil, registry)
@@ -534,3 +536,70 @@ func TestForkPreMigration(t *testing.T) {
// to this channel.
require.Equal(t, 6, len(counter))
}
func TestDisablePreMigration(t *testing.T) {
logging.SetAllLoggers(logging.LevelInfo)
cg, err := gen.NewGenerator()
require.NoError(t, err)
err = os.Setenv(EnvDisablePreMigrations, "1")
require.NoError(t, err)
defer func() {
err := os.Unsetenv(EnvDisablePreMigrations)
require.NoError(t, err)
}()
counter := make(chan struct{}, 10)
sm, err := NewStateManager(
cg.ChainStore(),
consensus.NewTipSetExecutor(filcns.RewardFunc),
cg.StateManager().VMSys(),
UpgradeSchedule{{
Network: network.Version1,
Height: testForkHeight,
Migration: func(_ context.Context, _ *StateManager, _ MigrationCache, _ ExecMonitor,
root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) {
counter <- struct{}{}
return root, nil
},
PreMigrations: []PreMigration{{
StartWithin: 20,
PreMigration: func(ctx context.Context, _ *StateManager, _ MigrationCache,
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
panic("should be skipped")
},
}}},
},
cg.BeaconSchedule(),
)
require.NoError(t, err)
require.NoError(t, sm.Start(context.Background()))
defer func() {
require.NoError(t, sm.Stop(context.Background()))
}()
inv := consensus.NewActorRegistry()
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
inv.Register(actorstypes.Version0, nil, registry)
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
nvm, err := vm.NewLegacyVM(ctx, vmopt)
require.NoError(t, err)
nvm.SetInvoker(inv)
return nvm, nil
})
cg.SetStateManager(sm)
for i := 0; i < 50; i++ {
_, err := cg.NextTipSet()
require.NoError(t, err)
}
require.Equal(t, 1, len(counter))
}
+422
View File
@@ -3,7 +3,10 @@ package store
import (
"bytes"
"context"
"fmt"
"io"
"sync"
"time"
"github.com/ipfs/go-cid"
blocks "github.com/ipfs/go-libipfs/blocks"
@@ -12,6 +15,8 @@ import (
carv2 "github.com/ipld/go-car/v2"
mh "github.com/multiformats/go-multihash"
cbg "github.com/whyrusleeping/cbor-gen"
"go.uber.org/atomic"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
@@ -132,6 +137,423 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
return root, nil
}
type walkSchedTaskType int
const (
finishTask walkSchedTaskType = -1
blockTask walkSchedTaskType = iota
messageTask
receiptTask
stateTask
dagTask
)
func (t walkSchedTaskType) String() string {
switch t {
case finishTask:
return "finish"
case blockTask:
return "block"
case messageTask:
return "message"
case receiptTask:
return "receipt"
case stateTask:
return "state"
case dagTask:
return "dag"
}
panic(fmt.Sprintf("unknow task %d", t))
}
type walkTask struct {
c cid.Cid
taskType walkSchedTaskType
}
// an ever growing FIFO
type taskFifo struct {
in chan walkTask
out chan walkTask
fifo []walkTask
}
type taskResult struct {
c cid.Cid
b blocks.Block
}
func newTaskFifo(bufferLen int) *taskFifo {
f := taskFifo{
in: make(chan walkTask, bufferLen),
out: make(chan walkTask, bufferLen),
fifo: make([]walkTask, 0),
}
go f.run()
return &f
}
func (f *taskFifo) Close() error {
close(f.in)
return nil
}
func (f *taskFifo) run() {
for {
if len(f.fifo) > 0 {
// we have items in slice
// try to put next out or read something in.
// blocks if nothing works.
next := f.fifo[0]
select {
case f.out <- next:
f.fifo = f.fifo[1:]
case elem, ok := <-f.in:
if !ok {
// drain and close out.
for _, elem := range f.fifo {
f.out <- elem
}
close(f.out)
return
}
f.fifo = append(f.fifo, elem)
}
} else {
// no elements in fifo to put out.
// Try to read in and block.
// When done, try to put out or add to fifo.
select {
case elem, ok := <-f.in:
if !ok {
close(f.out)
return
}
select {
case f.out <- elem:
default:
f.fifo = append(f.fifo, elem)
}
}
}
}
}
type walkSchedulerConfig struct {
numWorkers int
head *types.TipSet // Tipset to start walking from.
tail *types.TipSet // Tipset to end at.
includeMessages bool
includeReceipts bool
includeState bool
}
type walkScheduler struct {
ctx context.Context
cancel context.CancelFunc
store bstore.Blockstore
cfg walkSchedulerConfig
writer io.Writer
workerTasks *taskFifo
totalTasks atomic.Int64
results chan taskResult
writeErrorChan chan error
// tracks number of inflight tasks
//taskWg sync.WaitGroup
// launches workers and collects errors if any occur
workers *errgroup.Group
// set of CIDs already exported
seen sync.Map
}
func newWalkScheduler(ctx context.Context, store bstore.Blockstore, cfg walkSchedulerConfig, w io.Writer) (*walkScheduler, error) {
ctx, cancel := context.WithCancel(ctx)
workers, ctx := errgroup.WithContext(ctx)
s := &walkScheduler{
ctx: ctx,
cancel: cancel,
store: store,
cfg: cfg,
writer: w,
results: make(chan taskResult, cfg.numWorkers*64),
workerTasks: newTaskFifo(cfg.numWorkers * 64),
writeErrorChan: make(chan error, 1),
workers: workers,
}
go func() {
defer close(s.writeErrorChan)
for r := range s.results {
// Write
if err := carutil.LdWrite(s.writer, r.c.Bytes(), r.b.RawData()); err != nil {
// abort operations
cancel()
s.writeErrorChan <- err
}
}
}()
// workers
for i := 0; i < cfg.numWorkers; i++ {
f := func(n int) func() error {
return func() error {
return s.workerFunc(n)
}
}(i)
s.workers.Go(f)
}
s.totalTasks.Add(int64(len(cfg.head.Blocks())))
for _, b := range cfg.head.Blocks() {
select {
case <-ctx.Done():
log.Errorw("context done while sending root tasks", ctx.Err())
cancel() // kill workers
return nil, ctx.Err()
case s.workerTasks.in <- walkTask{
c: b.Cid(),
taskType: blockTask,
}:
}
}
return s, nil
}
func (s *walkScheduler) Wait() error {
err := s.workers.Wait()
// all workers done. One would have reached genesis and notified the
// rest to exit. Yet, there might be some pending tasks in the queue,
// so we need to run a "single worker".
if err != nil {
log.Errorw("export workers finished with error", "error", err)
}
for {
if n := s.totalTasks.Load(); n == 0 {
break // finally fully done
}
select {
case task := <-s.workerTasks.out:
s.totalTasks.Add(-1)
if err != nil {
continue // just drain if errors happened.
}
err = s.processTask(task, 0)
}
}
close(s.results)
errWrite := <-s.writeErrorChan
if errWrite != nil {
log.Errorw("error writing to CAR file", "error", err)
return errWrite
}
s.workerTasks.Close() //nolint:errcheck
return err
}
func (s *walkScheduler) enqueueIfNew(task walkTask) {
if task.c.Prefix().MhType == mh.IDENTITY {
//log.Infow("ignored", "cid", todo.c.String())
return
}
if task.c.Prefix().Codec != cid.Raw && task.c.Prefix().Codec != cid.DagCBOR {
//log.Infow("ignored", "cid", todo.c.String())
return
}
if _, loaded := s.seen.LoadOrStore(task.c, struct{}{}); loaded {
// we already had it on the map
return
}
log.Debugw("enqueue", "type", task.taskType.String(), "cid", task.c.String())
s.totalTasks.Add(1)
s.workerTasks.in <- task
}
func (s *walkScheduler) sendFinish(workerN int) error {
log.Infow("worker finished work", "worker", workerN)
s.totalTasks.Add(1)
s.workerTasks.in <- walkTask{
taskType: finishTask,
}
return nil
}
func (s *walkScheduler) workerFunc(workerN int) error {
log.Infow("starting worker", "worker", workerN)
for t := range s.workerTasks.out {
s.totalTasks.Add(-1)
select {
case <-s.ctx.Done():
return s.ctx.Err()
default:
// A worker reached genesis, so we wind down and let others do
// the same. Exit.
if t.taskType == finishTask {
return s.sendFinish(workerN)
}
}
err := s.processTask(t, workerN)
if err != nil {
return err
}
// continue
}
return nil
}
func (s *walkScheduler) processTask(t walkTask, workerN int) error {
if t.taskType == finishTask {
return nil
}
blk, err := s.store.Get(s.ctx, t.c)
if err != nil {
return xerrors.Errorf("writing object to car, bs.Get: %w", err)
}
s.results <- taskResult{
c: t.c,
b: blk,
}
// extract relevant dags to walk from the block
if t.taskType == blockTask {
blk := t.c
data, err := s.store.Get(s.ctx, blk)
if err != nil {
return err
}
var b types.BlockHeader
if err := b.UnmarshalCBOR(bytes.NewBuffer(data.RawData())); err != nil {
return xerrors.Errorf("unmarshalling block header (cid=%s): %w", blk, err)
}
if b.Height%1_000 == 0 {
log.Infow("block export", "height", b.Height)
}
if b.Height == 0 {
log.Info("exporting genesis block")
for i := range b.Parents {
s.enqueueIfNew(walkTask{
c: b.Parents[i],
taskType: dagTask,
})
}
s.enqueueIfNew(walkTask{
c: b.ParentStateRoot,
taskType: stateTask,
})
return s.sendFinish(workerN)
}
// enqueue block parents
for i := range b.Parents {
s.enqueueIfNew(walkTask{
c: b.Parents[i],
taskType: blockTask,
})
}
if s.cfg.tail.Height() >= b.Height {
log.Debugw("tail reached: only blocks will be exported from now until genesis", "cid", blk.String())
return nil
}
if s.cfg.includeMessages {
// enqueue block messages
s.enqueueIfNew(walkTask{
c: b.Messages,
taskType: messageTask,
})
}
if s.cfg.includeReceipts {
// enqueue block receipts
s.enqueueIfNew(walkTask{
c: b.ParentMessageReceipts,
taskType: receiptTask,
})
}
if s.cfg.includeState {
s.enqueueIfNew(walkTask{
c: b.ParentStateRoot,
taskType: stateTask,
})
}
return nil
}
// Not a chain-block: we scan for CIDs in the raw block-data
return cbg.ScanForLinks(bytes.NewReader(blk.RawData()), func(c cid.Cid) {
if t.c.Prefix().Codec != cid.DagCBOR || t.c.Prefix().MhType == mh.IDENTITY {
return
}
s.enqueueIfNew(walkTask{
c: c,
taskType: dagTask,
})
})
}
func (cs *ChainStore) ExportRange(
ctx context.Context,
w io.Writer,
head, tail *types.TipSet,
messages, receipts, stateroots bool,
workers int) error {
h := &car.CarHeader{
Roots: head.Cids(),
Version: 1,
}
if err := car.WriteHeader(h, w); err != nil {
return xerrors.Errorf("failed to write car header: %s", err)
}
start := time.Now()
log.Infow("walking snapshot range",
"head", head.Key(),
"tail", tail.Key(),
"messages", messages,
"receipts", receipts,
"stateroots",
stateroots,
"workers", workers)
cfg := walkSchedulerConfig{
numWorkers: workers,
head: head,
tail: tail,
includeMessages: messages,
includeState: stateroots,
includeReceipts: receipts,
}
pw, err := newWalkScheduler(ctx, cs.UnionStore(), cfg, w)
if err != nil {
return err
}
// wait until all workers are done.
err = pw.Wait()
if err != nil {
log.Errorw("walker scheduler", "error", err)
return err
}
log.Infow("walking snapshot range complete", "duration", time.Since(start), "success", err == nil)
return nil
}
func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs, skipMsgReceipts bool, cb func(cid.Cid) error) error {
if ts == nil {
ts = cs.GetHeaviestTipSet()
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -212,7 +213,7 @@ func TestChainExportImportFull(t *testing.T) {
t.Fatal("imported chain differed from exported chain")
}
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule())
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule())
if err != nil {
t.Fatal(err)
}
+1 -1
View File
@@ -273,7 +273,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
}()
var what string
res, what = bv.consensus.ValidateBlockPubsub(ctx, pid == bv.self, msg)
res, what = consensus.ValidateBlockPubsub(ctx, bv.consensus, pid == bv.self, msg)
if res == pubsub.ValidationAccept {
// it's a good block! make sure we've only seen it once
if count := bv.recvBlocks.add(msg.ValidatorData.(*types.BlockMsg).Cid()); count > 0 {
+4
View File
@@ -207,6 +207,10 @@ func (m *Message) ValidForBlockInclusion(minGas int64, version network.Version)
return xerrors.Errorf("'GasLimit' field cannot be greater than a block's gas limit (%d > %d)", m.GasLimit, build.BlockGasLimit)
}
if m.GasLimit <= 0 {
return xerrors.Errorf("'GasLimit' field %d must be positive", m.GasLimit)
}
// since prices might vary with time, this is technically semantic validation
if m.GasLimit < minGas {
return xerrors.Errorf("'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d", m.GasLimit, minGas)
+10 -1
View File
@@ -61,6 +61,10 @@ func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Comma
return xerrors.Errorf("expanding file path: %w", err)
}
if _, err := os.Stat(fpath); !os.IsNotExist(err) {
return xerrors.Errorf("backup file %s already exists. Overwriting it will corrupt the file, please specify another file name", fpath)
}
out, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return xerrors.Errorf("opening backup file %s: %w", fpath, err)
@@ -87,7 +91,12 @@ func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Comma
}
defer closer()
err = api.CreateBackup(ReqContext(cctx), cctx.Args().First())
backupPath := cctx.Args().First()
if _, err := os.Stat(backupPath); !os.IsNotExist(err) {
return xerrors.Errorf("backup file %s already exists. Overwriting it will corrupt the file, please specify another file name", backupPath)
}
err = api.CreateBackup(ReqContext(cctx), backupPath)
if err != nil {
return err
}
+133 -8
View File
@@ -6,6 +6,7 @@ import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@@ -37,7 +38,7 @@ import (
"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/types"
)
@@ -56,6 +57,7 @@ var ChainCmd = &cli.Command{
ChainGetCmd,
ChainBisectCmd,
ChainExportCmd,
ChainExportRangeCmd,
SlashConsensusFault,
ChainGasPriceCmd,
ChainInspectUsage,
@@ -112,8 +114,8 @@ var ChainGetBlock = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass cid of block to print")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
bcid, err := cid.Decode(cctx.Args().First())
@@ -198,6 +200,10 @@ var ChainReadObjCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to parse cid input: %s", err)
@@ -233,6 +239,10 @@ var ChainDeleteObjCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to parse cid input: %s", err)
@@ -276,6 +286,10 @@ var ChainStatObjCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
obj, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("failed to parse cid input: %s", err)
@@ -308,8 +322,8 @@ var ChainGetMsgCmd = &cli.Command{
Action: func(cctx *cli.Context) error {
afmt := NewAppFmt(cctx.App)
if !cctx.Args().Present() {
return fmt.Errorf("must pass a cid of a message to get")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
@@ -374,6 +388,10 @@ var ChainSetHeadCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
var ts *types.TipSet
if cctx.Bool("genesis") {
@@ -493,7 +511,7 @@ var ChainInspectUsage = &cli.Command{
return err
}
mm := filcns.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map
mm := consensus.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map
byMethod[mm.Name] += m.Message.GasLimit
byMethodC[mm.Name]++
@@ -734,6 +752,10 @@ var ChainGetCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
p := path.Clean(cctx.Args().First())
if strings.HasPrefix(p, "/pstate") {
p = p[len("/pstate"):]
@@ -1071,8 +1093,8 @@ var ChainExportCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify filename to export chain to")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
rsrs := abi.ChainEpoch(cctx.Int64("recent-stateroots"))
@@ -1125,6 +1147,109 @@ var ChainExportCmd = &cli.Command{
},
}
var ChainExportRangeCmd = &cli.Command{
Name: "export-range",
Usage: "export chain to a car file",
ArgsUsage: "",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "head",
Usage: "specify tipset to start the export from (higher epoch)",
Value: "@head",
},
&cli.StringFlag{
Name: "tail",
Usage: "specify tipset to end the export at (lower epoch)",
Value: "@tail",
},
&cli.BoolFlag{
Name: "messages",
Usage: "specify if messages should be include",
Value: false,
},
&cli.BoolFlag{
Name: "receipts",
Usage: "specify if receipts should be include",
Value: false,
},
&cli.BoolFlag{
Name: "stateroots",
Usage: "specify if stateroots should be include",
Value: false,
},
&cli.IntFlag{
Name: "workers",
Usage: "specify the number of workers",
Value: 1,
},
&cli.IntFlag{
Name: "write-buffer",
Usage: "specify write buffer size",
Value: 1 << 20,
},
&cli.BoolFlag{
Name: "internal",
Usage: "write the file locally to disk",
Value: true,
Hidden: true, // currently, non-internal export is not implemented.
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
var head, tail *types.TipSet
headstr := cctx.String("head")
if headstr == "@head" {
head, err = api.ChainHead(ctx)
if err != nil {
return err
}
} else {
head, err = ParseTipSetRef(ctx, api, headstr)
if err != nil {
return fmt.Errorf("parsing head: %w", err)
}
}
tailstr := cctx.String("tail")
if tailstr == "@tail" {
tail, err = api.ChainGetGenesis(ctx)
if err != nil {
return err
}
} else {
tail, err = ParseTipSetRef(ctx, api, tailstr)
if err != nil {
return fmt.Errorf("parsing tail: %w", err)
}
}
if head.Height() < tail.Height() {
return errors.New("Height of --head tipset must be greater or equal to the height of the --tail tipset")
}
if !cctx.Bool("internal") {
return errors.New("Non-internal exports are not implemented")
}
err = api.ChainExportRangeInternal(ctx, head.Key(), tail.Key(), lapi.ChainExportConfig{
WriteBufferSize: cctx.Int("write-buffer"),
NumWorkers: cctx.Int("workers"),
IncludeMessages: cctx.Bool("messages"),
IncludeReceipts: cctx.Bool("receipts"),
IncludeStateRoots: cctx.Bool("stateroots"),
})
if err != nil {
return err
}
return nil
},
}
var SlashConsensusFault = &cli.Command{
Name: "slash-consensus",
Usage: "Report consensus fault",
+20 -48
View File
@@ -166,8 +166,8 @@ var clientDropCmd = &cli.Command{
Usage: "Remove import",
ArgsUsage: "[import ID...]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return xerrors.Errorf("no imports specified")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
@@ -996,9 +996,8 @@ var clientFindCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
fmt.Println("Usage: find [CID]")
return nil
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
file, err := cid.Parse(cctx.Args().First())
@@ -1063,8 +1062,7 @@ var clientQueryRetrievalAskCmd = &cli.Command{
Action: func(cctx *cli.Context) error {
afmt := NewAppFmt(cctx.App)
if cctx.NArg() != 2 {
afmt.Println("Usage: retrieval-ask [minerAddress] [data CID]")
return nil
return IncorrectNumArgs(cctx)
}
maddr, err := address.NewFromString(cctx.Args().First())
@@ -1120,11 +1118,6 @@ var clientListRetrievalsCmd = &cli.Command{
Aliases: []string{"v"},
Usage: "print verbose deal details",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.BoolFlag{
Name: "show-failed",
Usage: "show failed/failing deals",
@@ -1140,10 +1133,6 @@ var clientListRetrievalsCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
@@ -1639,8 +1628,7 @@ var clientQueryAskCmd = &cli.Command{
Action: func(cctx *cli.Context) error {
afmt := NewAppFmt(cctx.App)
if cctx.NArg() != 1 {
afmt.Println("Usage: query-ask [minerAddress]")
return nil
return IncorrectNumArgs(cctx)
}
maddr, err := address.NewFromString(cctx.Args().First())
@@ -1712,11 +1700,6 @@ var clientListDeals = &cli.Command{
Aliases: []string{"v"},
Usage: "print verbose deal details",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.BoolFlag{
Name: "show-failed",
Usage: "show failed/failing deals",
@@ -1727,10 +1710,6 @@ var clientListDeals = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
@@ -1944,8 +1923,8 @@ var clientGetDealCmd = &cli.Command{
Usage: "Print detailed deal information",
ArgsUsage: "[proposalCID]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
@@ -2058,8 +2037,8 @@ var clientStat = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() || cctx.NArg() != 1 {
return fmt.Errorf("must specify cid of data")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
dataCid, err := cid.Parse(cctx.Args().First())
@@ -2080,8 +2059,9 @@ var clientStat = &cli.Command{
}
var clientRestartTransfer = &cli.Command{
Name: "restart-transfer",
Usage: "Force restart a stalled data transfer",
Name: "restart-transfer",
Usage: "Force restart a stalled data transfer",
ArgsUsage: "[transferID]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "peerid",
@@ -2094,8 +2074,8 @@ var clientRestartTransfer = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -2140,8 +2120,9 @@ var clientRestartTransfer = &cli.Command{
}
var clientCancelTransfer = &cli.Command{
Name: "cancel-transfer",
Usage: "Force cancel a data transfer",
Name: "cancel-transfer",
Usage: "Force cancel a data transfer",
ArgsUsage: "[transferID]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "peerid",
@@ -2159,8 +2140,8 @@ var clientCancelTransfer = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -2242,11 +2223,6 @@ var clientListTransfers = &cli.Command{
Aliases: []string{"v"},
Usage: "print verbose transfer details",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.BoolFlag{
Name: "completed",
Usage: "show completed data transfers",
@@ -2261,10 +2237,6 @@ var clientListTransfers = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
+1 -2
View File
@@ -58,8 +58,7 @@ var disputerMsgCmd = &cli.Command{
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 3 {
fmt.Println("Usage: dispute [minerAddress index postIndex]")
return nil
return IncorrectNumArgs(cctx)
}
ctx := ReqContext(cctx)
+180
View File
@@ -43,7 +43,9 @@ var filplusCmd = &cli.Command{
filplusCheckNotaryCmd,
filplusSignRemoveDataCapProposal,
filplusListAllocationsCmd,
filplusListClaimsCmd,
filplusRemoveExpiredAllocationsCmd,
filplusRemoveExpiredClaimsCmd,
},
}
@@ -310,6 +312,91 @@ var filplusListAllocationsCmd = &cli.Command{
},
}
var filplusListClaimsCmd = &cli.Command{
Name: "list-claims",
Usage: "List claims made by provider",
ArgsUsage: "providerAddress",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "expired",
Usage: "list only expired claims",
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
providerAddr, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
providerIdAddr, err := api.StateLookupID(ctx, providerAddr, types.EmptyTSK)
if err != nil {
return err
}
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api)))
verifregActor, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK)
if err != nil {
return err
}
verifregState, err := verifreg.Load(store, verifregActor)
if err != nil {
return err
}
ts, err := api.ChainHead(ctx)
if err != nil {
return err
}
claimsMap, err := verifregState.GetClaims(providerIdAddr)
if err != nil {
return err
}
tw := tablewriter.New(
tablewriter.Col("ID"),
tablewriter.Col("Provider"),
tablewriter.Col("Client"),
tablewriter.Col("Data"),
tablewriter.Col("Size"),
tablewriter.Col("TermMin"),
tablewriter.Col("TermMax"),
tablewriter.Col("TermStart"),
tablewriter.Col("Sector"),
)
for claimId, claim := range claimsMap {
if ts.Height() > claim.TermMax || !cctx.IsSet("expired") {
tw.Write(map[string]interface{}{
"ID": claimId,
"Provider": claim.Provider,
"Client": claim.Client,
"Data": claim.Data,
"Size": claim.Size,
"TermMin": claim.TermMin,
"TermMax": claim.TermMax,
"TermStart": claim.TermStart,
"Sector": claim.Sector,
})
}
}
return tw.Flush(os.Stdout)
},
}
var filplusRemoveExpiredAllocationsCmd = &cli.Command{
Name: "remove-expired-allocations",
Usage: "remove expired allocations (if no allocations are specified all eligible allocations are removed)",
@@ -403,6 +490,99 @@ var filplusRemoveExpiredAllocationsCmd = &cli.Command{
},
}
var filplusRemoveExpiredClaimsCmd = &cli.Command{
Name: "remove-expired-claims",
Usage: "remove expired claims (if no claims are specified all eligible claims are removed)",
ArgsUsage: "providerAddress Optional[...claimId]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "optionally specify the account to send the message from",
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() < 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
args := cctx.Args().Slice()
providerAddr, err := address.NewFromString(args[0])
if err != nil {
return err
}
providerIdAddr, err := api.StateLookupID(ctx, providerAddr, types.EmptyTSK)
if err != nil {
return err
}
providerId, err := address.IDFromAddress(providerIdAddr)
if err != nil {
return err
}
fromAddr := providerIdAddr
if from := cctx.String("from"); from != "" {
addr, err := address.NewFromString(from)
if err != nil {
return err
}
fromAddr = addr
}
claimIDs := make([]verifregtypes9.ClaimId, len(args)-1)
for i, claimStr := range args[1:] {
id, err := strconv.ParseUint(claimStr, 10, 64)
if err != nil {
return err
}
claimIDs[i] = verifregtypes9.ClaimId(id)
}
params, err := actors.SerializeParams(&verifregtypes9.RemoveExpiredClaimsParams{
Provider: abi.ActorID(providerId),
ClaimIds: claimIDs,
})
if err != nil {
return err
}
msg := &types.Message{
To: verifreg.Address,
From: fromAddr,
Method: verifreg.Methods.RemoveExpiredClaims,
Params: params,
}
smsg, err := api.MpoolPushMessage(ctx, msg, nil)
if err != nil {
return err
}
fmt.Printf("message sent, now waiting on cid: %s\n", smsg.Cid())
mwait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
if err != nil {
return err
}
if mwait.Receipt.ExitCode.IsError() {
return fmt.Errorf("failed to remove expired allocations: %d", mwait.Receipt.ExitCode)
}
return nil
},
}
var filplusCheckClientCmd = &cli.Command{
Name: "check-client-datacap",
Usage: "check verified client remaining bytes",
+2 -2
View File
@@ -28,7 +28,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/types"
)
@@ -325,7 +325,7 @@ var msigInspectCmd = &cli.Command{
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%s(%d)\t%s\n", txid, "pending", len(tx.Approved), target, types.FIL(tx.Value), "new account, unknown method", tx.Method, paramStr)
}
} else {
method := filcns.NewActorRegistry().Methods[targAct.Code][tx.Method] // TODO: use remote map
method := consensus.NewActorRegistry().Methods[targAct.Code][tx.Method] // TODO: use remote map
if decParams && tx.Method != 0 {
ptyp := reflect.New(method.Params.Elem()).Interface().(cbg.CBORUnmarshaler)
+2 -2
View File
@@ -15,8 +15,8 @@ var FetchParamCmd = &cli.Command{
Usage: "Fetch proving parameters",
ArgsUsage: "[sectorSize]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return xerrors.Errorf("must pass sector size to fetch params for (specify as \"32GiB\", for instance)")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
sectorSizeInt, err := units.RAMInBytes(cctx.Args().First())
if err != nil {
+2 -2
View File
@@ -17,7 +17,7 @@ import (
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/types"
)
@@ -88,7 +88,7 @@ func (s *ServicesImpl) DecodeTypedParamsFromJSON(ctx context.Context, to address
return nil, err
}
methodMeta, found := filcns.NewActorRegistry().Methods[act.Code][method] // TODO: use remote map
methodMeta, found := consensus.NewActorRegistry().Methods[act.Code][method] // TODO: use remote map
if !found {
return nil, fmt.Errorf("method %d not found on actor %s", method, act.Code)
}
+41 -34
View File
@@ -41,7 +41,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -99,8 +99,8 @@ var StateMinerProvingDeadlineCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify miner to get information for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -142,8 +142,8 @@ var StateMinerInfo = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify miner to get information for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -252,10 +252,16 @@ func ParseTipSetString(ts string) ([]cid.Cid, error) {
return cids, nil
}
type TipSetResolver interface {
ChainHead(context.Context) (*types.TipSet, error)
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
}
// LoadTipSet gets the tipset from the context, or the head from the API.
//
// It always gets the head from the API so commands use a consistent tipset even if time pases.
func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*types.TipSet, error) {
func LoadTipSet(ctx context.Context, cctx *cli.Context, api TipSetResolver) (*types.TipSet, error) {
tss := cctx.String("tipset")
if tss == "" {
return api.ChainHead(ctx)
@@ -264,7 +270,7 @@ func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*ty
return ParseTipSetRef(ctx, api, tss)
}
func ParseTipSetRef(ctx context.Context, api v0api.FullNode, tss string) (*types.TipSet, error) {
func ParseTipSetRef(ctx context.Context, api TipSetResolver, tss string) (*types.TipSet, error) {
if tss[0] == '@' {
if tss == "@head" {
return api.ChainHead(ctx)
@@ -391,8 +397,8 @@ var StateSectorsCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify miner to list sectors for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
maddr, err := address.NewFromString(cctx.Args().First())
@@ -431,8 +437,8 @@ var StateActiveSectorsCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify miner to list sectors for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
maddr, err := address.NewFromString(cctx.Args().First())
@@ -463,8 +469,8 @@ var StateExecTraceCmd = &cli.Command{
Usage: "Get the execution trace of a given message",
ArgsUsage: "<messageCid>",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return ShowHelp(cctx, fmt.Errorf("must pass message cid"))
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
mcid, err := cid.Decode(cctx.Args().First())
@@ -606,8 +612,8 @@ var StateGetDealSetCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify deal ID")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
dealid, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
@@ -750,8 +756,8 @@ var StateGetActorCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass address of actor to get")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -804,8 +810,8 @@ var StateLookupIDCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass address of actor to get")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -848,8 +854,8 @@ var StateSectorSizeCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass miner's address")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -885,8 +891,8 @@ var StateReadStateCmd = &cli.Command{
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass address of actor to get")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -1411,7 +1417,7 @@ func codeStr(c cid.Cid) string {
}
func getMethod(code cid.Cid, method abi.MethodNum) string {
return filcns.NewActorRegistry().Methods[code][method].Name // todo: use remote
return consensus.NewActorRegistry().Methods[code][method].Name // todo: use remote
}
func toFil(f types.BigInt) types.FIL {
@@ -1427,7 +1433,7 @@ func isVerySlow(t time.Duration) bool {
}
func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
p, err := stmgr.GetParamType(filcns.NewActorRegistry(), code, method) // todo use api for correct actor registry
p, err := stmgr.GetParamType(consensus.NewActorRegistry(), code, method) // todo use api for correct actor registry
if err != nil {
return "", err
}
@@ -1441,7 +1447,7 @@ func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro
}
func JsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) {
methodMeta, found := filcns.NewActorRegistry().Methods[code][method] // TODO: use remote
methodMeta, found := consensus.NewActorRegistry().Methods[code][method] // TODO: use remote
if !found {
return "", fmt.Errorf("method %d not found on actor %s", method, code)
}
@@ -1467,8 +1473,8 @@ var StateWaitMsgCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must specify message cid to wait for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
@@ -1504,8 +1510,8 @@ var StateSearchMsgCmd = &cli.Command{
Usage: "Search to see whether a message has appeared on chain",
ArgsUsage: "[messageCid]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must specify message cid to search for")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
@@ -1836,11 +1842,12 @@ var StateMarketCmd = &cli.Command{
}
var stateMarketBalanceCmd = &cli.Command{
Name: "balance",
Usage: "Get the market balance (locked and escrowed) for a given account",
Name: "balance",
Usage: "Get the market balance (locked and escrowed) for a given account",
ArgsUsage: "[address]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return ShowHelp(cctx, fmt.Errorf("must specify address to print market balance for"))
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
+12 -12
View File
@@ -251,8 +251,8 @@ var walletSetDefault = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must pass address to set as default")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -279,8 +279,8 @@ var walletExport = &cli.Command{
afmt := NewAppFmt(cctx.App)
if !cctx.Args().Present() {
return fmt.Errorf("must specify key to export")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -414,8 +414,8 @@ var walletSign = &cli.Command{
afmt := NewAppFmt(cctx.App)
if !cctx.Args().Present() || cctx.NArg() != 2 {
return fmt.Errorf("must specify signing address and message to sign")
if cctx.NArg() != 2 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -457,8 +457,8 @@ var walletVerify = &cli.Command{
afmt := NewAppFmt(cctx.App)
if !cctx.Args().Present() || cctx.NArg() != 3 {
return fmt.Errorf("must specify signing address, message, and signature to verify")
if cctx.NArg() != 3 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -509,8 +509,8 @@ var walletDelete = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if !cctx.Args().Present() || cctx.NArg() != 1 {
return fmt.Errorf("must specify address to delete")
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
addr, err := address.NewFromString(cctx.Args().First())
@@ -701,8 +701,8 @@ var walletMarketAdd = &cli.Command{
afmt := NewAppFmt(cctx.App)
// Get amount param
if !cctx.Args().Present() {
return fmt.Errorf("must pass amount to add")
if cctx.NArg() < 1 {
return IncorrectNumArgs(cctx)
}
f, err := types.ParseFIL(cctx.Args().First())
if err != nil {
+2 -1
View File
@@ -34,6 +34,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/blockstore"
badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -228,7 +229,7 @@ var importBenchCmd = &cli.Command{
defer cs.Close() //nolint:errcheck
// TODO: We need to supply the actual beacon after v14
stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil)
stm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
+15 -18
View File
@@ -55,9 +55,10 @@ var actorCmd = &cli.Command{
}
var actorSetAddrsCmd = &cli.Command{
Name: "set-addresses",
Aliases: []string{"set-addrs"},
Usage: "set addresses that your miner can be publicly dialed on",
Name: "set-addresses",
Aliases: []string{"set-addrs"},
Usage: "set addresses that your miner can be publicly dialed on",
ArgsUsage: "<multiaddrs>",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
@@ -170,8 +171,9 @@ var actorSetAddrsCmd = &cli.Command{
}
var actorSetPeeridCmd = &cli.Command{
Name: "set-peer-id",
Usage: "set the peer id of your miner",
Name: "set-peer-id",
Usage: "set the peer id of your miner",
ArgsUsage: "<peer id>",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "gas-limit",
@@ -194,6 +196,10 @@ var actorSetPeeridCmd = &cli.Command{
ctx := lcli.ReqContext(cctx)
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
pid, err := peer.Decode(cctx.Args().Get(0))
if err != nil {
return fmt.Errorf("failed to parse input as a peerId: %w", err)
@@ -433,17 +439,8 @@ var actorControlList = &cli.Command{
&cli.BoolFlag{
Name: "verbose",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
@@ -729,15 +726,15 @@ var actorSetOwnerCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 2 {
return lcli.IncorrectNumArgs(cctx)
}
if !cctx.Bool("really-do-it") {
fmt.Println("Pass --really-do-it to actually execute this action")
return nil
}
if cctx.NArg() != 2 {
return lcli.IncorrectNumArgs(cctx)
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
+2 -5
View File
@@ -34,8 +34,8 @@ func TestWorkerKeyChange(t *testing.T) {
kit.QuietMiningLogs()
blocktime := 1 * time.Millisecond
client1, client2, miner, ens := kit.EnsembleTwoOne(t, kit.MockProofs())
blocktime := 5 * time.Millisecond
client1, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs())
ens.InterconnectAll().BeginMining(blocktime)
output := bytes.NewBuffer(nil)
@@ -96,7 +96,4 @@ func TestWorkerKeyChange(t *testing.T) {
// Wait for finality (worker key switch).
targetHeight := head.Height() + policy.ChainFinality
client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
// Make sure the other node can catch up.
client2.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
}
+1 -1
View File
@@ -25,7 +25,7 @@ func TestMinerAllInfo(t *testing.T) {
kit.QuietMiningLogs()
client, miner, ens := kit.EnsembleMinimal(t)
ens.InterconnectAll().BeginMining(time.Second)
ens.InterconnectAll().BeginMiningMustPost(5 * time.Millisecond)
run := func(t *testing.T) {
app := cli.NewApp()
-75
View File
@@ -31,18 +31,7 @@ var dagstoreCmd = &cli.Command{
var dagstoreListShardsCmd = &cli.Command{
Name: "list-shards",
Usage: "List all shards known to the dagstore, with their current status",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
if err != nil {
return err
@@ -64,18 +53,7 @@ var dagstoreRegisterShardCmd = &cli.Command{
Name: "register-shard",
ArgsUsage: "[key]",
Usage: "Register a shard",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
@@ -103,18 +81,7 @@ var dagstoreInitializeShardCmd = &cli.Command{
Name: "initialize-shard",
ArgsUsage: "[key]",
Usage: "Initialize the specified shard",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
@@ -135,18 +102,7 @@ var dagstoreRecoverShardCmd = &cli.Command{
Name: "recover-shard",
ArgsUsage: "[key]",
Usage: "Attempt to recover a shard in errored state",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
@@ -176,17 +132,8 @@ var dagstoreInitializeAllCmd = &cli.Command{
Name: "include-sealed",
Usage: "initialize sealed pieces as well",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
concurrency := cctx.Uint("concurrency")
sealed := cctx.Bool("sealed")
@@ -236,18 +183,7 @@ var dagstoreInitializeAllCmd = &cli.Command{
var dagstoreGcCmd = &cli.Command{
Name: "gc",
Usage: "Garbage collect the dagstore",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
if err != nil {
return err
@@ -317,18 +253,7 @@ var dagstoreLookupPiecesCmd = &cli.Command{
Name: "lookup-pieces",
Usage: "Lookup pieces that a given CID belongs to",
ArgsUsage: "<cid>",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
-23
View File
@@ -3,7 +3,6 @@ package main
import (
"fmt"
"github.com/fatih/color"
"github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
@@ -23,18 +22,7 @@ var indexProvAnnounceCmd = &cli.Command{
Name: "announce",
ArgsUsage: "<deal proposal cid>",
Usage: "Announce a deal to indexers so they can download its index",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
@@ -60,18 +48,7 @@ var indexProvAnnounceCmd = &cli.Command{
var indexProvAnnounceAllCmd = &cli.Command{
Name: "announce-all",
Usage: "Announce all active deals to indexers so they can download the indices",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
if err != nil {
return err
+1 -122
View File
@@ -7,8 +7,6 @@ import (
corebig "math/big"
"os"
"sort"
"strings"
"text/tabwriter"
"time"
"github.com/fatih/color"
@@ -18,8 +16,6 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -65,12 +61,6 @@ func infoCmdAct(cctx *cli.Context) error {
}
defer closer()
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
if err != nil {
return err
}
defer closer()
fullapi, acloser, err := lcli.GetFullNodeAPIV1(cctx)
if err != nil {
return err
@@ -84,14 +74,7 @@ func infoCmdAct(cctx *cli.Context) error {
return err
}
fmt.Println("Enabled subsystems (from miner API):", subsystems)
subsystems, err = marketsApi.RuntimeSubsystems(ctx)
if err != nil {
return err
}
fmt.Println("Enabled subsystems (from markets API):", subsystems)
fmt.Println("Enabled subsystems:", subsystems)
start, err := minerApi.StartTime(ctx)
if err != nil {
@@ -128,11 +111,6 @@ func infoCmdAct(cctx *cli.Context) error {
return err
}
err = handleMarketsInfo(ctx, marketsApi)
if err != nil {
return err
}
return nil
}
@@ -393,105 +371,6 @@ func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v1api.Full
return nil
}
func handleMarketsInfo(ctx context.Context, nodeApi api.StorageMiner) error {
deals, err := nodeApi.MarketListIncompleteDeals(ctx)
if err != nil {
return err
}
type dealStat struct {
count, verifCount int
bytes, verifBytes uint64
}
dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) {
ds.count++
ds.bytes += uint64(deal.Proposal.PieceSize)
if deal.Proposal.VerifiedDeal {
ds.verifCount++
ds.verifBytes += uint64(deal.Proposal.PieceSize)
}
}
showDealStates := map[storagemarket.StorageDealStatus]struct{}{
storagemarket.StorageDealActive: {},
storagemarket.StorageDealAcceptWait: {},
storagemarket.StorageDealReserveProviderFunds: {},
storagemarket.StorageDealProviderFunding: {},
storagemarket.StorageDealTransferring: {},
storagemarket.StorageDealValidating: {},
storagemarket.StorageDealStaged: {},
storagemarket.StorageDealAwaitingPreCommit: {},
storagemarket.StorageDealSealing: {},
storagemarket.StorageDealPublish: {},
storagemarket.StorageDealCheckForAcceptance: {},
storagemarket.StorageDealPublishing: {},
}
var total dealStat
perState := map[storagemarket.StorageDealStatus]*dealStat{}
for _, deal := range deals {
if _, ok := showDealStates[deal.State]; !ok {
continue
}
if perState[deal.State] == nil {
perState[deal.State] = new(dealStat)
}
dsAdd(&total, deal)
dsAdd(perState[deal.State], deal)
}
type wstr struct {
str string
status storagemarket.StorageDealStatus
}
sorted := make([]wstr, 0, len(perState))
for status, stat := range perState {
st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal")
sorted = append(sorted, wstr{
str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))),
status: status,
},
)
}
sort.Slice(sorted, func(i, j int) bool {
if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive {
return sorted[i].status == storagemarket.StorageDealActive
}
return sorted[i].status > sorted[j].status
})
fmt.Println()
fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes)))
tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
for _, e := range sorted {
_, _ = tw.Write([]byte(e.str))
}
_ = tw.Flush()
fmt.Println()
retrievals, err := nodeApi.MarketListRetrievalDeals(ctx)
if err != nil {
return xerrors.Errorf("getting retrieval deal list: %w", err)
}
var retrComplete dealStat
for _, retrieval := range retrievals {
if retrieval.Status == retrievalmarket.DealStatusCompleted {
retrComplete.count++
retrComplete.bytes += retrieval.TotalSent
}
}
fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes)))
fmt.Println()
return nil
}
type stateMeta struct {
i int
col color.Attribute
+11 -2
View File
@@ -198,8 +198,17 @@ var infoAllCmd = &cli.Command{
}
fmt.Println("\n#: Sector List")
if err := sectorsListCmd.Action(cctx); err != nil {
fmt.Println("ERROR: ", err)
{
fs := &flag.FlagSet{}
for _, f := range sectorsListCmd.Flags {
if err := f.Apply(fs); err != nil {
fmt.Println("ERROR: ", err)
}
}
if err := sectorsListCmd.Action(cli.NewContext(cctx.App, fs, cctx)); err != nil {
fmt.Println("ERROR: ", err)
}
}
fmt.Println("\n#: Storage Sector List")
-10
View File
@@ -16,7 +16,6 @@ import (
tm "github.com/buger/goterm"
"github.com/docker/go-units"
"github.com/fatih/color"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-cidutil/cidenc"
"github.com/libp2p/go-libp2p/core/peer"
@@ -779,11 +778,6 @@ var transfersListCmd = &cli.Command{
Aliases: []string{"v"},
Usage: "print verbose transfer details",
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.BoolFlag{
Name: "completed",
Usage: "show completed data transfers",
@@ -798,10 +792,6 @@ var transfersListCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
api, closer, err := lcli.GetMarketsAPI(cctx)
if err != nil {
return err
-20
View File
@@ -45,18 +45,7 @@ func workersCmd(sealing bool) *cli.Command {
return &cli.Command{
Name: "workers",
Usage: "list workers",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
@@ -218,21 +207,12 @@ var sealingJobsCmd = &cli.Command{
Name: "jobs",
Usage: "list running jobs",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.BoolFlag{
Name: "show-ret-done",
Usage: "show returned but not consumed calls",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
+116 -315
View File
@@ -9,6 +9,7 @@ import (
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/docker/go-units"
@@ -33,11 +34,14 @@ import (
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/lib/result"
"github.com/filecoin-project/lotus/lib/strle"
"github.com/filecoin-project/lotus/lib/tablewriter"
sealing "github.com/filecoin-project/lotus/storage/pipeline"
)
const parallelSectorChecks = 300
var sectorsCmd = &cli.Command{
Name: "sectors",
Usage: "interact with sector store",
@@ -51,7 +55,6 @@ var sectorsCmd = &cli.Command{
sectorPreCommitsCmd,
sectorsCheckExpireCmd,
sectorsExpiredCmd,
sectorsRenewCmd,
sectorsExtendCmd,
sectorsTerminateCmd,
sectorsRemoveCmd,
@@ -121,8 +124,8 @@ var sectorsStatusCmd = &cli.Command{
defer closer()
ctx := lcli.ReqContext(cctx)
if !cctx.Args().Present() {
return fmt.Errorf("must specify sector number to get status of")
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
id, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
@@ -278,12 +281,6 @@ var sectorsListCmd = &cli.Command{
Usage: "show removed sectors",
Aliases: []string{"r"},
},
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
Aliases: []string{"c"},
},
&cli.BoolFlag{
Name: "fast",
Usage: "don't show on-chain info for better performance",
@@ -313,13 +310,15 @@ var sectorsListCmd = &cli.Command{
Usage: "only show sectors which aren't in the 'Proving' state",
Aliases: []string{"u"},
},
&cli.Int64Flag{
Name: "check-parallelism",
Usage: "number of parallel requests to make for checking sector states",
Value: parallelSectorChecks,
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
// http mode allows for parallel json decoding/encoding, which was a bottleneck here
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp)
if err != nil {
return err
}
@@ -418,16 +417,37 @@ var sectorsListCmd = &cli.Command{
fast := cctx.Bool("fast")
for _, s := range list {
st, err := minerApi.SectorsStatus(ctx, s, !fast)
if err != nil {
throttle := make(chan struct{}, cctx.Int64("check-parallelism"))
slist := make([]result.Result[api.SectorInfo], len(list))
var wg sync.WaitGroup
for i, s := range list {
throttle <- struct{}{}
wg.Add(1)
go func(i int, s abi.SectorNumber) {
defer wg.Done()
defer func() { <-throttle }()
r := result.Wrap(minerApi.SectorsStatus(ctx, s, !fast))
if r.Error != nil {
r.Value.SectorID = s
}
slist[i] = r
}(i, s)
}
wg.Wait()
for _, rsn := range slist {
if rsn.Error != nil {
tw.Write(map[string]interface{}{
"ID": s,
"ID": rsn.Value.SectorID,
"Error": err,
})
continue
}
st := rsn.Value
s := st.SectorID
if !showRemoved && st.State == api.SectorState(sealing.Removed) {
continue
}
@@ -743,14 +763,14 @@ func ArrayToString(array []uint64) string {
return strings.Join(sarray, ",")
}
func getSectorsFromFile(filePath string) ([]uint64, error) {
func getSectorsFromFile(filePath string) ([]abi.SectorNumber, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(file)
sectors := make([]uint64, 0)
sectors := make([]abi.SectorNumber, 0)
for scanner.Scan() {
line := scanner.Text()
@@ -760,7 +780,7 @@ func getSectorsFromFile(filePath string) ([]uint64, error) {
return nil, xerrors.Errorf("could not parse %s as sector id: %s", line, err)
}
sectors = append(sectors, id)
sectors = append(sectors, abi.SectorNumber(id))
}
if err = file.Close(); err != nil {
@@ -770,9 +790,19 @@ func getSectorsFromFile(filePath string) ([]uint64, error) {
return sectors, nil
}
var sectorsRenewCmd = &cli.Command{
Name: "renew",
Usage: "Renew expiring sectors while not exceeding each sector's max life",
func SectorNumsToBitfield(sectors []abi.SectorNumber) bitfield.BitField {
var numbers []uint64
for _, sector := range sectors {
numbers = append(numbers, uint64(sector))
}
return bitfield.NewFromSet(numbers)
}
var sectorsExtendCmd = &cli.Command{
Name: "extend",
Usage: "Extend expiring sectors while not exceeding each sector's max life",
ArgsUsage: "<sectorNumbers...(optional)>",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "from",
@@ -819,7 +849,7 @@ var sectorsRenewCmd = &cli.Command{
},
&cli.BoolFlag{
Name: "really-do-it",
Usage: "pass this flag to really renew sectors, otherwise will only print out json representation of parameters",
Usage: "pass this flag to really extend sectors, otherwise will only print out json representation of parameters",
},
},
Action: func(cctx *cli.Context) error {
@@ -896,8 +926,7 @@ var sectorsRenewCmd = &cli.Command{
return err
}
excludeSet := make(map[uint64]struct{})
excludeSet := make(map[abi.SectorNumber]struct{})
if cctx.IsSet("exclude") {
excludeSectors, err := getSectorsFromFile(cctx.String("exclude"))
if err != nil {
@@ -909,28 +938,24 @@ var sectorsRenewCmd = &cli.Command{
}
}
var sis []*miner.SectorOnChainInfo
if cctx.IsSet("sector-file") {
sectors, err := getSectorsFromFile(cctx.String("sector-file"))
if err != nil {
return err
var sectors []abi.SectorNumber
if cctx.Args().Present() {
if cctx.IsSet("sector-file") {
return xerrors.Errorf("sector-file specified along with command line params")
}
for _, id := range sectors {
if _, exclude := excludeSet[id]; exclude {
continue
for i, s := range cctx.Args().Slice() {
id, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return xerrors.Errorf("could not parse sector %d: %w", i, err)
}
si, found := activeSectorsInfo[abi.SectorNumber(id)]
if !found {
return xerrors.Errorf("sector %d is not active", id)
}
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
continue
}
sis = append(sis, si)
sectors = append(sectors, abi.SectorNumber(id))
}
} else if cctx.IsSet("sector-file") {
sectors, err = getSectorsFromFile(cctx.String("sector-file"))
if err != nil {
return err
}
} else {
from := currEpoch + 120
@@ -945,19 +970,28 @@ var sectorsRenewCmd = &cli.Command{
}
for _, si := range activeSet {
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
continue
}
if si.Expiration >= from && si.Expiration <= to {
if _, exclude := excludeSet[uint64(si.SectorNumber)]; !exclude {
sis = append(sis, si)
}
sectors = append(sectors, si.SectorNumber)
}
}
}
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]uint64{}
var sis []*miner.SectorOnChainInfo
for _, id := range sectors {
if _, exclude := excludeSet[id]; exclude {
continue
}
si, found := activeSectorsInfo[id]
if !found {
return xerrors.Errorf("sector %d is not active", id)
}
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
continue
}
sis = append(sis, si)
}
withinTolerance := func(a, b abi.ChainEpoch) bool {
diff := a - b
@@ -968,6 +1002,7 @@ var sectorsRenewCmd = &cli.Command{
return diff <= abi.ChainEpoch(cctx.Int64("tolerance"))
}
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]abi.SectorNumber{}
for _, si := range sis {
extension := abi.ChainEpoch(cctx.Int64("extension"))
newExp := si.Expiration + extension
@@ -997,21 +1032,21 @@ var sectorsRenewCmd = &cli.Command{
es, found := extensions[*l]
if !found {
ne := make(map[abi.ChainEpoch][]uint64)
ne[newExp] = []uint64{uint64(si.SectorNumber)}
ne := make(map[abi.ChainEpoch][]abi.SectorNumber)
ne[newExp] = []abi.SectorNumber{si.SectorNumber}
extensions[*l] = ne
} else {
added := false
for exp := range es {
if withinTolerance(newExp, exp) {
es[exp] = append(es[exp], uint64(si.SectorNumber))
es[exp] = append(es[exp], si.SectorNumber)
added = true
break
}
}
if !added {
es[newExp] = []uint64{uint64(si.SectorNumber)}
es[newExp] = []abi.SectorNumber{si.SectorNumber}
}
}
}
@@ -1051,7 +1086,7 @@ var sectorsRenewCmd = &cli.Command{
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
Deadline: l.Deadline,
Partition: l.Partition,
Sectors: bitfield.NewFromSet(numbers),
Sectors: SectorNumsToBitfield(numbers),
NewExpiration: newExp,
})
}
@@ -1083,7 +1118,7 @@ var sectorsRenewCmd = &cli.Command{
}
scount += int(count)
}
fmt.Printf("Renewing %d sectors: ", scount)
fmt.Printf("Extending %d sectors: ", scount)
stotal += scount
if !cctx.Bool("really-do-it") {
@@ -1097,8 +1132,7 @@ var sectorsRenewCmd = &cli.Command{
return err
}
fmt.Println()
fmt.Println(string(data))
fmt.Println("\n", string(data))
continue
}
@@ -1121,252 +1155,7 @@ var sectorsRenewCmd = &cli.Command{
fmt.Println(smsg.Cid())
}
fmt.Printf("%d sectors renewed\n", stotal)
return nil
},
}
var sectorsExtendCmd = &cli.Command{
Name: "extend",
Usage: "Extend sector expiration",
ArgsUsage: "<sectorNumbers...>",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "new-expiration",
Usage: "new expiration epoch",
Required: false,
},
&cli.BoolFlag{
Name: "v1-sectors",
Usage: "renews all v1 sectors up to the maximum possible lifetime",
Required: false,
},
&cli.Int64Flag{
Name: "tolerance",
Value: 20160,
Usage: "when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs",
Required: false,
},
&cli.Int64Flag{
Name: "expiration-ignore",
Value: 120,
Usage: "when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now",
Required: false,
},
&cli.Int64Flag{
Name: "expiration-cutoff",
Usage: "when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified)",
Required: false,
},
&cli.StringFlag{},
},
Action: func(cctx *cli.Context) error {
api, nCloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer nCloser()
ctx := lcli.ReqContext(cctx)
maddr, err := getActorAddress(ctx, cctx)
if err != nil {
return err
}
var params []miner.ExtendSectorExpirationParams
if cctx.Bool("v1-sectors") {
head, err := api.ChainHead(ctx)
if err != nil {
return err
}
nv, err := api.StateNetworkVersion(ctx, types.EmptyTSK)
if err != nil {
return err
}
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]uint64{}
// are given durations within tolerance epochs
withinTolerance := func(a, b abi.ChainEpoch) bool {
diff := a - b
if diff < 0 {
diff = b - a
}
return diff <= abi.ChainEpoch(cctx.Int64("tolerance"))
}
sis, err := api.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner sector infos: %w", err)
}
for _, si := range sis {
if si.SealProof >= abi.RegisteredSealProof_StackedDrg2KiBV1_1 {
continue
}
if si.Expiration < (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-ignore"))) {
continue
}
if cctx.IsSet("expiration-cutoff") {
if si.Expiration > (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-cutoff"))) {
continue
}
}
ml := policy.GetSectorMaxLifetime(si.SealProof, nv)
// if the sector's missing less than "tolerance" of its maximum possible lifetime, don't bother extending it
if withinTolerance(si.Expiration-si.Activation, ml) {
continue
}
// Set the new expiration to 48 hours less than the theoretical maximum lifetime
newExp := ml - (miner.WPoStProvingPeriod * 2) + si.Activation
if withinTolerance(si.Expiration, newExp) || si.Expiration >= newExp {
continue
}
p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err)
}
if p == nil {
return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber)
}
es, found := extensions[*p]
if !found {
ne := make(map[abi.ChainEpoch][]uint64)
ne[newExp] = []uint64{uint64(si.SectorNumber)}
extensions[*p] = ne
} else {
added := false
for exp := range es {
if withinTolerance(exp, newExp) && newExp >= exp && exp > si.Expiration {
es[exp] = append(es[exp], uint64(si.SectorNumber))
added = true
break
}
}
if !added {
es[newExp] = []uint64{uint64(si.SectorNumber)}
}
}
}
p := miner.ExtendSectorExpirationParams{}
scount := 0
for l, exts := range extensions {
for newExp, numbers := range exts {
scount += len(numbers)
addressedMax, err := policy.GetAddressedSectorsMax(nv)
if err != nil {
return xerrors.Errorf("failed to get addressed sectors max")
}
declMax, err := policy.GetDeclarationsMax(nv)
if err != nil {
return xerrors.Errorf("failed to get declarations max")
}
if scount > addressedMax || len(p.Extensions) == declMax {
params = append(params, p)
p = miner.ExtendSectorExpirationParams{}
scount = len(numbers)
}
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
Deadline: l.Deadline,
Partition: l.Partition,
Sectors: bitfield.NewFromSet(numbers),
NewExpiration: newExp,
})
}
}
// if we have any sectors, then one last append is needed here
if scount != 0 {
params = append(params, p)
}
} else {
if !cctx.Args().Present() || !cctx.IsSet("new-expiration") {
return xerrors.Errorf("must pass at least one sector number and new expiration")
}
sectors := map[lminer.SectorLocation][]uint64{}
for i, s := range cctx.Args().Slice() {
id, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return xerrors.Errorf("could not parse sector %d: %w", i, err)
}
p, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(id), types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting sector location for sector %d: %w", id, err)
}
if p == nil {
return xerrors.Errorf("sector %d not found in any partition", id)
}
sectors[*p] = append(sectors[*p], id)
}
p := miner.ExtendSectorExpirationParams{}
for l, numbers := range sectors {
// TODO: Dedup with above loop
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
Deadline: l.Deadline,
Partition: l.Partition,
Sectors: bitfield.NewFromSet(numbers),
NewExpiration: abi.ChainEpoch(cctx.Int64("new-expiration")),
})
}
params = append(params, p)
}
if len(params) == 0 {
fmt.Println("nothing to extend")
return nil
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
for i := range params {
sp, aerr := actors.SerializeParams(&params[i])
if aerr != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: mi.Worker,
To: maddr,
Method: builtin.MethodsMiner.ExtendSectorExpiration,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push message: %w", err)
}
fmt.Println(smsg.Cid())
}
fmt.Printf("%d sectors extended\n", stotal)
return nil
},
@@ -1387,9 +1176,6 @@ var sectorsTerminateCmd = &cli.Command{
sectorsTerminatePendingCmd,
},
Action: func(cctx *cli.Context) error {
if !cctx.Bool("really-do-it") {
return xerrors.Errorf("pass --really-do-it to confirm this action")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
@@ -1400,6 +1186,10 @@ var sectorsTerminateCmd = &cli.Command{
return lcli.IncorrectNumArgs(cctx)
}
if !cctx.Bool("really-do-it") {
return xerrors.Errorf("pass --really-do-it to confirm this action")
}
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return xerrors.Errorf("could not parse sector number: %w", err)
@@ -1620,8 +1410,14 @@ var sectorsStartSealCmd = &cli.Command{
var sectorsSealDelayCmd = &cli.Command{
Name: "set-seal-delay",
Usage: "Set the time, in minutes, that a new sector waits for deals before sealing starts",
ArgsUsage: "<minutes>",
Usage: "Set the time (in minutes) that a new sector waits for deals before sealing starts",
ArgsUsage: "<time>",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "seconds",
Usage: "Specifies that the time argument should be in seconds",
},
},
Action: func(cctx *cli.Context) error {
minerAPI, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
@@ -1638,7 +1434,12 @@ var sectorsSealDelayCmd = &cli.Command{
return xerrors.Errorf("could not parse sector number: %w", err)
}
delay := hs * uint64(time.Minute)
var delay uint64
if cctx.Bool("seconds") {
delay = hs * uint64(time.Second)
} else {
delay = hs * uint64(time.Minute)
}
return minerAPI.SectorSetSealDelay(ctx, time.Duration(delay))
},
@@ -1732,8 +1533,8 @@ var sectorsUpdateCmd = &cli.Command{
}
defer closer()
ctx := lcli.ReqContext(cctx)
if cctx.NArg() < 2 {
return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number and new state"))
if cctx.NArg() != 2 {
return lcli.IncorrectNumArgs(cctx)
}
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
+18 -30
View File
@@ -55,8 +55,9 @@ stored while moving through the sealing pipeline (references as 'seal').`,
}
var storageAttachCmd = &cli.Command{
Name: "attach",
Usage: "attach local storage path",
Name: "attach",
Usage: "attach local storage path",
ArgsUsage: "[path]",
Description: `Storage can be attached to the miner using this command. The storage volume
list is stored local to the miner in $LOTUS_MINER_PATH/storage.json. We do not
recommend manually modifying this value without further understanding of the
@@ -115,8 +116,8 @@ over time
defer closer()
ctx := lcli.ReqContext(cctx)
if !cctx.Args().Present() {
return xerrors.Errorf("must specify storage path to attach")
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
p, err := homedir.Expand(cctx.Args().First())
@@ -192,8 +193,8 @@ var storageDetachCmd = &cli.Command{
defer closer()
ctx := lcli.ReqContext(cctx)
if !cctx.Args().Present() {
return xerrors.Errorf("must specify storage path")
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
p, err := homedir.Expand(cctx.Args().First())
@@ -210,8 +211,9 @@ var storageDetachCmd = &cli.Command{
}
var storageRedeclareCmd = &cli.Command{
Name: "redeclare",
Usage: "redeclare sectors in a local storage path",
Name: "redeclare",
Usage: "redeclare sectors in a local storage path",
ArgsUsage: "[path]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "id",
@@ -234,6 +236,10 @@ var storageRedeclareCmd = &cli.Command{
defer closer()
ctx := lcli.ReqContext(cctx)
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
if cctx.IsSet("id") && cctx.Bool("all") {
return xerrors.Errorf("--id and --all can't be passed at the same time")
}
@@ -254,21 +260,10 @@ var storageRedeclareCmd = &cli.Command{
var storageListCmd = &cli.Command{
Name: "list",
Usage: "list local storage paths",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Subcommands: []*cli.Command{
storageListSectorsCmd,
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
@@ -477,6 +472,10 @@ var storageFindCmd = &cli.Command{
defer closer()
ctx := lcli.ReqContext(cctx)
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
ma, err := minerApi.ActorAddress(ctx)
if err != nil {
return err
@@ -633,18 +632,7 @@ var storageFindCmd = &cli.Command{
var storageListSectorsCmd = &cli.Command{
Name: "sectors",
Usage: "get list of all sector files",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
},
Action: func(cctx *cli.Context) error {
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
+256
View File
@@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"
"os"
"strconv"
"github.com/fatih/color"
"github.com/urfave/cli/v2"
@@ -14,6 +15,7 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
"github.com/filecoin-project/go-state-types/network"
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
@@ -35,6 +37,8 @@ var actorCmd = &cli.Command{
actorProposeChangeWorker,
actorConfirmChangeWorker,
actorGetMethodNum,
actorProposeChangeBeneficiary,
actorConfirmChangeBeneficiary,
},
}
@@ -831,3 +835,255 @@ var actorGetMethodNum = &cli.Command{
return nil
},
}
var actorProposeChangeBeneficiary = &cli.Command{
Name: "propose-change-beneficiary",
Usage: "Propose a beneficiary address change",
ArgsUsage: "[beneficiaryAddress quota expiration minerID]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
&cli.BoolFlag{
Name: "overwrite-pending-change",
Usage: "Overwrite the current beneficiary change proposal",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 4 {
return lcli.IncorrectNumArgs(cctx)
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return xerrors.Errorf("getting fullnode api: %w", err)
}
defer acloser()
ctx := lcli.ReqContext(cctx)
na, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return xerrors.Errorf("parsing beneficiary address: %w", err)
}
newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("looking up new beneficiary address: %w", err)
}
quota, err := types.ParseFIL(cctx.Args().Get(1))
if err != nil {
return xerrors.Errorf("parsing quota: %w", err)
}
expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64)
if err != nil {
return xerrors.Errorf("parsing expiration: %w", err)
}
maddr, err := address.NewFromString(cctx.Args().Get(3))
if err != nil {
return xerrors.Errorf("getting miner address: %w", err)
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
if mi.Beneficiary == mi.Owner && newAddr == mi.Owner {
return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary)
}
if mi.PendingBeneficiaryTerm != nil {
fmt.Println("WARNING: replacing Pending Beneficiary Term of:")
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
if !cctx.Bool("overwrite-pending-change") {
return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY")
}
}
if !cctx.Bool("really-do-it") {
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
return nil
}
params := &miner.ChangeBeneficiaryParams{
NewBeneficiary: newAddr,
NewQuota: abi.TokenAmount(quota),
NewExpiration: abi.ChainEpoch(expiration),
}
sp, err := actors.SerializeParams(params)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: mi.Owner,
To: maddr,
Method: builtin.MethodsMiner.ChangeBeneficiary,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Println("Propose Message CID:", smsg.Cid())
// wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
if err != nil {
return xerrors.Errorf("waiting for message to be included in block: %w", err)
}
// check it executed successfully
if wait.Receipt.ExitCode.IsError() {
return fmt.Errorf("propose beneficiary change failed")
}
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr {
fmt.Println("Beneficiary address successfully changed")
} else {
fmt.Println("Beneficiary address change awaiting additional confirmations")
}
return nil
},
}
var actorConfirmChangeBeneficiary = &cli.Command{
Name: "confirm-change-beneficiary",
Usage: "Confirm a beneficiary address change",
ArgsUsage: "[minerAddress]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
&cli.BoolFlag{
Name: "existing-beneficiary",
Usage: "send confirmation from the existing beneficiary address",
},
&cli.BoolFlag{
Name: "new-beneficiary",
Usage: "send confirmation from the new beneficiary address",
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return xerrors.Errorf("getting fullnode api: %w", err)
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return xerrors.Errorf("parsing beneficiary address: %w", err)
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
if mi.PendingBeneficiaryTerm == nil {
return fmt.Errorf("no pending beneficiary term found for miner %s", maddr)
}
if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) {
return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary"))
}
var fromAddr address.Address
if cctx.IsSet("existing-beneficiary") {
if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary {
return fmt.Errorf("beneficiary change already approved by current beneficiary")
}
fromAddr = mi.Beneficiary
} else {
if mi.PendingBeneficiaryTerm.ApprovedByNominee {
return fmt.Errorf("beneficiary change already approved by new beneficiary")
}
fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary
}
fmt.Println("Confirming Pending Beneficiary Term of:")
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
if !cctx.Bool("really-do-it") {
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
return nil
}
params := &miner.ChangeBeneficiaryParams{
NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary,
NewQuota: mi.PendingBeneficiaryTerm.NewQuota,
NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration,
}
sp, err := actors.SerializeParams(params)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: fromAddr,
To: maddr,
Method: builtin.MethodsMiner.ChangeBeneficiary,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Println("Confirm Message CID:", smsg.Cid())
// wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
if err != nil {
return xerrors.Errorf("waiting for message to be included in block: %w", err)
}
// check it executed successfully
if wait.Receipt.ExitCode.IsError() {
return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode)
}
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary {
fmt.Println("Beneficiary address successfully changed")
} else {
fmt.Println("Beneficiary address change awaiting additional confirmations")
}
return nil
},
}
+23
View File
@@ -13,6 +13,15 @@ import (
var addressCmd = &cli.Command{
Name: "addr",
Usage: "interact with filecoin addresses",
Subcommands: cli.Commands{
addrDecode,
addrEncode,
},
}
var addrDecode = &cli.Command{
Name: "decode",
Usage: "decode hex bytes into address",
Action: func(cctx *cli.Context) error {
addrHex := cctx.Args().First()
@@ -39,3 +48,17 @@ var addressCmd = &cli.Command{
return nil
},
}
var addrEncode = &cli.Command{
Name: "encode",
Usage: "encode address to hex bytes",
Action: func(cctx *cli.Context) error {
addr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return err
}
fmt.Printf("%x\n", addr.Bytes())
return nil
},
}
+3 -2
View File
@@ -32,6 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/gen/genesis"
"github.com/filecoin-project/lotus/chain/state"
@@ -512,7 +513,7 @@ var chainBalanceStateCmd = &cli.Command{
cst := cbor.NewCborStore(bs)
store := adt.WrapStore(ctx, cst)
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
@@ -736,7 +737,7 @@ var chainPledgeCmd = &cli.Command{
cst := cbor.NewCborStore(bs)
store := adt.WrapStore(ctx, cst)
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
+38
View File
@@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/base64"
"encoding/hex"
"fmt"
@@ -12,6 +13,7 @@ import (
"github.com/ipld/go-car"
mh "github.com/multiformats/go-multihash"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
@@ -27,6 +29,42 @@ var cidCmd = &cli.Command{
Subcommands: cli.Commands{
cidIdCmd,
inspectBundleCmd,
cborCid,
cidBytes,
},
}
var cidBytes = &cli.Command{
Name: "bytes",
Usage: "cid bytes",
ArgsUsage: "[cid]",
Action: func(cctx *cli.Context) error {
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return err
}
// Add in the troublesome zero byte prefix
fmt.Printf("00%x\n", c.Bytes())
return nil
},
}
var cborCid = &cli.Command{
Name: "cbor",
Usage: "Serialize cid to cbor",
ArgsUsage: "[cid]",
Action: func(cctx *cli.Context) error {
c, err := cid.Decode(cctx.Args().First())
if err != nil {
return err
}
cbgc := cbg.CborCid(c)
buf := bytes.NewBuffer(make([]byte, 0))
if err := cbgc.MarshalCBOR(buf); err != nil {
return err
}
fmt.Printf("%x\n", buf.Bytes())
return nil
},
}
+3 -2
View File
@@ -18,6 +18,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/beacon/drand"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -110,7 +111,7 @@ var gasTraceCmd = &cli.Command{
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
if err != nil {
return err
}
@@ -211,7 +212,7 @@ var replayOfflineCmd = &cli.Command{
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
if err != nil {
return err
}
+2 -1
View File
@@ -19,6 +19,7 @@ import (
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -89,7 +90,7 @@ var invariantsCmd = &cli.Command{
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
+2
View File
@@ -20,6 +20,8 @@ func main() {
local := []*cli.Command{
addressCmd,
statActorCmd,
statObjCmd,
base64Cmd,
base32Cmd,
base16Cmd,
+2 -1
View File
@@ -38,6 +38,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -120,7 +121,7 @@ var migrationsCmd = &cli.Command{
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
+2 -2
View File
@@ -16,7 +16,7 @@ import (
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
@@ -141,7 +141,7 @@ func printMessage(cctx *cli.Context, msg *types.Message) error {
return nil
}
fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][msg.Method].Name) // todo use remote
fmt.Println("Method:", consensus.NewActorRegistry().Methods[toact.Code][msg.Method].Name) // todo use remote
p, err := lcli.JsonParams(toact.Code, msg.Method, msg.Params)
if err != nil {
return err
+224
View File
@@ -18,6 +18,7 @@ import (
"github.com/ipfs/go-cid"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"gopkg.in/cheggaaa/pb.v1"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
@@ -31,6 +32,11 @@ import (
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/lib/parmap"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/paths"
"github.com/filecoin-project/lotus/storage/sealer/fr32"
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
var sectorsCmd = &cli.Command{
@@ -42,6 +48,8 @@ var sectorsCmd = &cli.Command{
terminateSectorPenaltyEstimationCmd,
visAllocatedSectorsCmd,
dumpRLESectorCmd,
sectorReadCmd,
sectorDeleteCmd,
},
}
@@ -563,3 +571,219 @@ func rleToPng(rleBytes []byte) ([]byte, error) {
return buf.Bytes(), nil
}
var sectorReadCmd = &cli.Command{
Name: "read",
Usage: "read data from a sector into stdout",
ArgsUsage: "[sector num] [padded length] [padded offset]",
Description: `Read data from a sector.
TIP: to get sectornum/len/offset for a piece you can use 'boostd pieces piece-info [cid]'
fr32 padding is removed from the output.`,
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 3 {
return xerrors.Errorf("must pass sectornum/len/offset")
}
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return xerrors.Errorf("parsing sector number: %w", err)
}
length, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
if err != nil {
return xerrors.Errorf("parsing length: %w", err)
}
offset, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
if err != nil {
return xerrors.Errorf("parsing offset: %w", err)
}
ctx := lcli.ReqContext(cctx)
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
maddr, err := api.ActorAddress(ctx)
if err != nil {
return xerrors.Errorf("getting miner actor address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return xerrors.Errorf("getting miner id: %w", err)
}
sid := abi.SectorID{
Miner: abi.ActorID(mid),
Number: abi.SectorNumber(sectorNum),
}
si, err := api.SectorsStatus(ctx, sid.Number, false)
if err != nil {
return xerrors.Errorf("getting sector status: %w", err)
}
sref := storiface.SectorRef{
ID: sid,
ProofType: si.SealProof,
}
defer closer()
// Setup remote sector store
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
if err != nil {
return xerrors.Errorf("could not get api info: %w", err)
}
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
if err != nil {
return err
}
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
&paths.DefaultPartialFileHandler{})
readStarter, err := remote.Reader(ctx, sref, abi.PaddedPieceSize(offset), abi.PaddedPieceSize(length))
if err != nil {
return xerrors.Errorf("getting reader: %w", err)
}
rd, err := readStarter(0)
if err != nil {
return xerrors.Errorf("starting reader: %w", err)
}
upr, err := fr32.NewUnpadReaderBuf(rd, abi.PaddedPieceSize(length), make([]byte, 1<<20))
if err != nil {
return xerrors.Errorf("creating unpadded reader: %w", err)
}
l := int64(abi.PaddedPieceSize(length).Unpadded())
bar := pb.New64(l)
br := bar.NewProxyReader(upr)
bar.ShowTimeLeft = true
bar.ShowPercent = true
bar.ShowSpeed = true
bar.Units = pb.U_BYTES
bar.Output = os.Stderr
bar.Start()
_, err = io.CopyN(os.Stdout, br, l)
if err != nil {
return xerrors.Errorf("reading data: %w", err)
}
return nil
},
}
var sectorDeleteCmd = &cli.Command{
Name: "delete",
Usage: "delete a sector file from sector storage",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "really-do-it",
},
},
ArgsUsage: "[sector num] [file type]",
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 2 {
return xerrors.Errorf("must pass sectornum/filetype")
}
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
if err != nil {
return xerrors.Errorf("parsing sector number: %w", err)
}
var ft storiface.SectorFileType
switch cctx.Args().Get(1) {
case "cache":
ft = storiface.FTCache
case "sealed":
ft = storiface.FTSealed
case "unsealed":
ft = storiface.FTUnsealed
case "update-cache":
ft = storiface.FTUpdateCache
case "update":
ft = storiface.FTUpdate
default:
return xerrors.Errorf("invalid file type")
}
ctx := lcli.ReqContext(cctx)
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
maddr, err := api.ActorAddress(ctx)
if err != nil {
return xerrors.Errorf("getting miner actor address: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return xerrors.Errorf("getting miner id: %w", err)
}
sid := abi.SectorID{
Miner: abi.ActorID(mid),
Number: abi.SectorNumber(sectorNum),
}
// get remote store
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
if err != nil {
return xerrors.Errorf("could not get api info: %w", err)
}
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
if err != nil {
return err
}
if !cctx.Bool("really-do-it") {
return xerrors.Errorf("pass --really-do-it to actually perform the deletion")
}
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
&paths.DefaultPartialFileHandler{})
err = remote.Remove(ctx, sid, ft, true, nil)
if err != nil {
return xerrors.Errorf("removing sector: %w", err)
}
return nil
},
}
type emptyLocalStorage struct {
}
func (e *emptyLocalStorage) GetStorage() (storiface.StorageConfig, error) {
return storiface.StorageConfig{}, nil
}
func (e *emptyLocalStorage) SetStorage(f func(*storiface.StorageConfig)) error {
panic("don't call")
}
func (e *emptyLocalStorage) Stat(path string) (fsutil.FsStat, error) {
panic("don't call")
}
func (e *emptyLocalStorage) DiskUsage(path string) (int64, error) {
panic("don't call")
}
var _ paths.LocalStorage = &emptyLocalStorage{}
+533
View File
@@ -0,0 +1,533 @@
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"reflect"
"sync"
"github.com/docker/go-units"
lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
offline "github.com/ipfs/go-ipfs-exchange-offline"
format "github.com/ipfs/go-ipld-format"
"github.com/ipfs/go-merkledag"
"github.com/urfave/cli/v2"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
)
type actorStats struct {
Address address.Address
Actor *types.Actor
Fields []fieldItem
Stats api.ObjStat
}
type fieldItem struct {
Name string
Cid cid.Cid
Stats api.ObjStat
}
type cacheNodeGetter struct {
ds format.NodeGetter
cache *lru.TwoQueueCache
}
func newCacheNodeGetter(d format.NodeGetter, size int) (*cacheNodeGetter, error) {
cng := &cacheNodeGetter{ds: d}
cache, err := lru.New2Q(size)
if err != nil {
return nil, err
}
cng.cache = cache
return cng, nil
}
func (cng *cacheNodeGetter) Get(ctx context.Context, c cid.Cid) (format.Node, error) {
if n, ok := cng.cache.Get(c); ok {
return n.(format.Node), nil
}
n, err := cng.ds.Get(ctx, c)
if err != nil {
return nil, err
}
cng.cache.Add(c, n)
return n, nil
}
func (cng *cacheNodeGetter) GetMany(ctx context.Context, list []cid.Cid) <-chan *format.NodeOption {
out := make(chan *format.NodeOption, len(list))
go func() {
for _, c := range list {
n, err := cng.Get(ctx, c)
if err != nil {
out <- &format.NodeOption{Err: err}
continue
}
out <- &format.NodeOption{Node: n}
}
}()
return out
}
type dagStatCollector struct {
ds format.NodeGetter
walk func(format.Node) ([]*format.Link, error)
statsLk sync.Mutex
stats api.ObjStat
}
func (dsc *dagStatCollector) record(ctx context.Context, nd format.Node) error {
size, err := nd.Size()
if err != nil {
return err
}
dsc.statsLk.Lock()
defer dsc.statsLk.Unlock()
dsc.stats.Size = dsc.stats.Size + size
dsc.stats.Links = dsc.stats.Links + 1
return nil
}
func (dsc *dagStatCollector) walkLinks(ctx context.Context, c cid.Cid) ([]*format.Link, error) {
nd, err := dsc.ds.Get(ctx, c)
if err != nil {
return nil, err
}
if err := dsc.record(ctx, nd); err != nil {
return nil, err
}
return dsc.walk(nd)
}
type ChainStoreTipSetResolver struct {
Chain *store.ChainStore
}
func (tsr *ChainStoreTipSetResolver) ChainHead(ctx context.Context) (*types.TipSet, error) {
return tsr.Chain.GetHeaviestTipSet(), nil
}
func (tsr *ChainStoreTipSetResolver) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
ts, err := tsr.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return tsr.Chain.GetTipsetByHeight(ctx, h, ts, true)
}
func (tsr *ChainStoreTipSetResolver) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
return tsr.Chain.LoadTipSet(ctx, tsk)
}
var statObjCmd = &cli.Command{
Name: "stat-obj",
Usage: "calculates the size of any DAG in the blockstore",
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
ctx := lcli.ReqContext(cctx)
c, err := cid.Parse(cctx.Args().First())
if err != nil {
return err
}
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
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return fmt.Errorf("failed to open blockstore: %w", err)
}
defer func() {
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}()
dag := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, c, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
return err
}
return DumpJSON(dsc.stats)
},
}
var statActorCmd = &cli.Command{
Name: "stat-actor",
Usage: "calculates the size of actors and their immeidate structures",
Description: `Any DAG linked by the actor object (field) will have its size calculated independently of all
other linked DAG. If an actor has two fields containing links to the same DAG the structure size will be counted
twice, included in each fields size individually.
The top level stats reported for an actor is computed independently of all fields and is a more accurate
accounting of the true size of the actor in the state datastore.
The calculation of these stats results in the actor state being traversed twice. The dag-cache-size flag can be used
to reduce the number of decode operations performed by caching the decoded object after first access.`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
Usage: "specify tipset to call method on (pass comma separated array of cids)",
},
&cli.IntFlag{
Name: "workers",
Usage: "number of workers to use when processing",
Value: 10,
},
&cli.IntFlag{
Name: "dag-cache-size",
Usage: "cache size per worker (setting to 0 disables)",
Value: 8092,
},
&cli.BoolFlag{
Name: "all",
Usage: "process all actors in stateroot of tipset",
Value: false,
},
&cli.BoolFlag{
Name: "pretty",
Usage: "print formated output instead of ldjson",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
ctx := lcli.ReqContext(cctx)
var addrs []address.Address
if !cctx.Bool("all") {
for _, a := range cctx.Args().Slice() {
addr, err := address.NewFromString(a)
if err != nil {
return err
}
addrs = append(addrs, addr)
}
}
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
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return fmt.Errorf("failed to open blockstore: %w", err)
}
defer func() {
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}()
mds, err := lr.Datastore(context.Background(), "/metadata")
if err != nil {
return err
}
cs := store.NewChainStore(bs, bs, mds, nil, nil)
if err := cs.Load(ctx); err != nil {
return nil
}
tsExec := consensus.NewTipSetExecutor(filcns.RewardFunc)
sm, err := stmgr.NewStateManager(cs, tsExec, vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
tsr := &ChainStoreTipSetResolver{
Chain: cs,
}
ts, err := lcli.LoadTipSet(ctx, cctx, tsr)
if err != nil {
return err
}
log.Infow("tipset", "parentstate", ts.ParentState())
if len(addrs) == 0 && cctx.Bool("all") {
var err error
addrs, err = sm.ListAllActors(ctx, ts)
if err != nil {
return err
}
}
numWorkers := cctx.Int("workers")
dagCacheSize := cctx.Int("dag-cache-size")
eg, egctx := errgroup.WithContext(ctx)
jobs := make(chan address.Address, numWorkers)
results := make(chan actorStats, numWorkers)
worker := func(ctx context.Context, id int) error {
completed := 0
defer func() {
log.Infow("worker done", "id", id, "completed", completed)
}()
for {
select {
case addr, ok := <-jobs:
if !ok {
return nil
}
actor, err := sm.LoadActor(ctx, addr, ts)
if err != nil {
return err
}
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
if dagCacheSize != 0 {
var err error
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs))), dagCacheSize)
if err != nil {
return err
}
}
actStats, err := collectStats(ctx, addr, actor, dag)
if err != nil {
return err
}
select {
case results <- actStats:
case <-ctx.Done():
return ctx.Err()
}
case <-ctx.Done():
return ctx.Err()
}
completed = completed + 1
}
}
for w := 0; w < numWorkers; w++ {
id := w
eg.Go(func() error {
return worker(egctx, id)
})
}
go func() {
defer close(jobs)
for _, addr := range addrs {
jobs <- addr
}
}()
go func() {
// error is check later
eg.Wait() //nolint:errcheck
close(results)
}()
for {
select {
case result, ok := <-results:
if !ok {
return eg.Wait()
}
if cctx.Bool("pretty") {
DumpStats(result)
} else {
if err := DumpJSON(result); err != nil {
return err
}
}
case <-ctx.Done():
return ctx.Err()
}
}
},
}
func collectStats(ctx context.Context, addr address.Address, actor *types.Actor, dag format.NodeGetter) (actorStats, error) {
log.Infow("actor", "addr", addr, "code", actor.Code, "name", builtin.ActorNameByCode(actor.Code))
nd, err := dag.Get(ctx, actor.Head)
if err != nil {
return actorStats{}, err
}
// When it comes to fvm / evm actors this method of inspecting fields will probably not work
// and we may only be able to collect stats for the top level object. We might be able to iterate
// over the top level fields for the actors and identify field that are CIDs, but unsure if we would
// be able to identify a field name.
oif, err := vm.DumpActorState(consensus.NewTipSetExecutor(filcns.RewardFunc).NewActorRegistry(), actor, nd.RawData())
if err != nil {
oif = nil
}
fields := []fieldItem{}
// Account actors return nil from DumpActorState as they have no state
if oif != nil {
v := reflect.Indirect(reflect.ValueOf(oif))
for i := 0; i < v.NumField(); i++ {
varName := v.Type().Field(i).Name
varType := v.Type().Field(i).Type
varValue := v.Field(i).Interface()
if varType == reflect.TypeOf(cid.Cid{}) {
fields = append(fields, fieldItem{
Name: varName,
Cid: varValue.(cid.Cid),
})
}
}
}
actStats := actorStats{
Address: addr,
Actor: actor,
}
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, actor.Head, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
return actorStats{}, err
}
actStats.Stats = dsc.stats
for _, field := range fields {
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, field.Cid, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
return actorStats{}, err
}
field.Stats = dsc.stats
actStats.Fields = append(actStats.Fields, field)
}
return actStats, nil
}
func DumpJSON(i interface{}) error {
bs, err := json.Marshal(i)
if err != nil {
return err
}
fmt.Println(string(bs))
return nil
}
func DumpStats(actStats actorStats) {
strtype := builtin.ActorNameByCode(actStats.Actor.Code)
fmt.Printf("Address:\t%s\n", actStats.Address)
fmt.Printf("Balance:\t%s\n", types.FIL(actStats.Actor.Balance))
fmt.Printf("Nonce:\t\t%d\n", actStats.Actor.Nonce)
fmt.Printf("Code:\t\t%s (%s)\n", actStats.Actor.Code, strtype)
fmt.Printf("Head:\t\t%s\n", actStats.Actor.Head)
fmt.Println()
fmt.Printf("%-*s%-*s%-*s\n", 32, "Field", 24, "Size", 24, "\"Blocks\"")
stats := actStats.Stats
sizeStr := units.BytesSize(float64(stats.Size))
fmt.Printf("%-*s%-*s%-*s%-*d\n", 32, "<self>", 10, sizeStr, 14, fmt.Sprintf("(%d)", stats.Size), 24, stats.Links)
for _, s := range actStats.Fields {
stats := s.Stats
sizeStr := units.BytesSize(float64(stats.Size))
fmt.Printf("%-*s%-*s%-*s%-*d\n", 32, s.Name, 10, sizeStr, 14, fmt.Sprintf("(%d)", stats.Size), 24, stats.Links)
}
fmt.Println("--------------------------------------------------------------------------")
}
@@ -16,7 +16,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
lrand "github.com/filecoin-project/lotus/chain/rand"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -85,7 +85,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S
Epoch: parentTs.Height() + 1,
Rand: r,
Bstore: sm.ChainStore().StateBlockstore(),
Actors: filcns.NewActorRegistry(),
Actors: consensus.NewActorRegistry(),
Syscalls: sm.VMSys(),
CircSupplyCalc: sm.GetVMCirculatingSupply,
NetworkVersion: sm.GetNetworkVersion(ctx, parentTs.Height()+1),
+3 -2
View File
@@ -10,6 +10,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -105,7 +106,7 @@ func (nd *Node) LoadSim(ctx context.Context, name string) (*Simulation, error) {
if err != nil {
return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err)
}
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us, nil)
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), us, nil)
if err != nil {
return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err)
}
@@ -124,7 +125,7 @@ func (nd *Node) CreateSim(ctx context.Context, name string, head *types.TipSet)
if err != nil {
return nil, err
}
sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil)
sm, err := stmgr.NewStateManager(nd.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return nil, xerrors.Errorf("creating state manager: %w", err)
}
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/filecoin-project/go-state-types/network"
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
@@ -200,7 +201,7 @@ func (sim *Simulation) SetUpgradeHeight(nv network.Version, epoch abi.ChainEpoch
if err != nil {
return err
}
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil)
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil)
if err != nil {
return err
}
+3 -3
View File
@@ -23,7 +23,7 @@ import (
"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
@@ -103,7 +103,7 @@ func (c *InteractiveWallet) WalletSign(ctx context.Context, k address.Address, m
return xerrors.Errorf("looking up dest actor: %w", err)
}
fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][cmsg.Method].Name)
fmt.Println("Method:", consensus.NewActorRegistry().Methods[toact.Code][cmsg.Method].Name)
p, err := lcli.JsonParams(toact.Code, cmsg.Method, cmsg.Params)
if err != nil {
return err
@@ -125,7 +125,7 @@ func (c *InteractiveWallet) WalletSign(ctx context.Context, k address.Address, m
return xerrors.Errorf("looking up msig dest actor: %w", err)
}
fmt.Println("\tMultiSig Proposal Method:", filcns.NewActorRegistry().Methods[toact.Code][mp.Method].Name) // todo use remote
fmt.Println("\tMultiSig Proposal Method:", consensus.NewActorRegistry().Methods[toact.Code][mp.Method].Name) // todo use remote
p, err := lcli.JsonParams(toact.Code, mp.Method, mp.Params)
if err != nil {
return err
+6 -2
View File
@@ -1,6 +1,8 @@
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
@@ -35,9 +37,11 @@ var setCmd = &cli.Command{
}
var waitQuietCmd = &cli.Command{
Name: "wait-quiet",
Usage: "Block until all running tasks exit",
Name: "wait-quiet",
Usage: "Block until all running tasks exit",
Hidden: true,
Action: func(cctx *cli.Context) error {
fmt.Println("DEPRECATED: This command will be removed in the future")
api, closer, err := lcli.GetWorkerAPI(cctx)
if err != nil {
return err
+5 -5
View File
@@ -184,25 +184,25 @@ var runCmd = &cli.Command{
},
&cli.BoolFlag{
Name: "precommit1",
Usage: "enable precommit1 (32G sectors: 1 core, 128GiB Memory)",
Usage: "enable precommit1",
Value: true,
EnvVars: []string{"LOTUS_WORKER_PRECOMMIT1"},
},
&cli.BoolFlag{
Name: "unseal",
Usage: "enable unsealing (32G sectors: 1 core, 128GiB Memory)",
Usage: "enable unsealing",
Value: true,
EnvVars: []string{"LOTUS_WORKER_UNSEAL"},
},
&cli.BoolFlag{
Name: "precommit2",
Usage: "enable precommit2 (32G sectors: all cores, 96GiB Memory)",
Usage: "enable precommit2",
Value: true,
EnvVars: []string{"LOTUS_WORKER_PRECOMMIT2"},
},
&cli.BoolFlag{
Name: "commit",
Usage: "enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap)",
Usage: "enable commit",
Value: true,
EnvVars: []string{"LOTUS_WORKER_COMMIT"},
},
@@ -257,7 +257,7 @@ var runCmd = &cli.Command{
&cli.IntFlag{
Name: "post-parallel-reads",
Usage: "maximum number of parallel challenge reads (0 = no limit)",
Value: 128,
Value: 32,
EnvVars: []string{"LOTUS_WORKER_POST_PARALLEL_READS"},
},
&cli.DurationFlag{
+42 -13
View File
@@ -44,33 +44,53 @@ var settableStr = func() string {
var tasksEnableCmd = &cli.Command{
Name: "enable",
Usage: "Enable a task type",
ArgsUsage: "[" + settableStr + "]",
Action: taskAction(api.Worker.TaskEnable),
ArgsUsage: "--all | [" + settableStr + "]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "all",
Usage: "Enable all task types",
},
},
Action: taskAction(api.Worker.TaskEnable),
}
var tasksDisableCmd = &cli.Command{
Name: "disable",
Usage: "Disable a task type",
ArgsUsage: "[" + settableStr + "]",
Action: taskAction(api.Worker.TaskDisable),
ArgsUsage: "--all | [" + settableStr + "]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "all",
Usage: "Disable all task types",
},
},
Action: taskAction(api.Worker.TaskDisable),
}
func taskAction(tf func(a api.Worker, ctx context.Context, tt sealtasks.TaskType) error) func(cctx *cli.Context) error {
return func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return xerrors.Errorf("expected 1 argument")
allFlag := cctx.Bool("all")
if cctx.NArg() == 1 && allFlag {
return xerrors.Errorf("Cannot use --all flag with task type argument")
}
if cctx.NArg() != 1 && !allFlag {
return xerrors.Errorf("Expected 1 argument or use --all flag")
}
var tt sealtasks.TaskType
for taskType := range allowSetting {
if taskType.Short() == cctx.Args().First() {
tt = taskType
break
if cctx.NArg() == 1 {
for taskType := range allowSetting {
if taskType.Short() == cctx.Args().First() {
tt = taskType
break
}
}
}
if tt == "" {
return xerrors.Errorf("unknown task type '%s'", cctx.Args().First())
if tt == "" {
return xerrors.Errorf("unknown task type '%s'", cctx.Args().First())
}
}
api, closer, err := lcli.GetWorkerAPI(cctx)
@@ -81,6 +101,15 @@ func taskAction(tf func(a api.Worker, ctx context.Context, tt sealtasks.TaskType
ctx := lcli.ReqContext(cctx)
if allFlag {
for taskType := range allowSetting {
if err := tf(api, ctx, taskType); err != nil {
return err
}
}
return nil
}
return tf(api, ctx, tt)
}
}
+2 -1
View File
@@ -33,6 +33,7 @@ import (
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store"
@@ -539,7 +540,7 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
}
// TODO: We need to supply the actual beacon after v14
stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
stm, err := stmgr.NewStateManager(cst, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
if err != nil {
return err
}
+11
View File
@@ -4,6 +4,7 @@ import (
"context"
"os"
"github.com/fatih/color"
logging "github.com/ipfs/go-log/v2"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
@@ -52,6 +53,10 @@ func main() {
}
jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name)
if cctx.IsSet("color") {
color.NoColor = !cctx.Bool("color")
}
if originBefore != nil {
return originBefore(cctx)
}
@@ -75,6 +80,12 @@ func main() {
Hidden: true,
Value: "~/.lotus", // should follow --repo default
},
&cli.BoolFlag{
// examined in the Before above
Name: "color",
Usage: "use color in display output",
DefaultText: "depends on output being a TTY",
},
&cli.StringFlag{
Name: "repo",
EnvVars: []string{"LOTUS_PATH"},
+2 -2
View File
@@ -19,7 +19,7 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/consensus"
)
var extractManyFlags struct {
@@ -159,7 +159,7 @@ func runExtractMany(c *cli.Context) error {
}
// Lookup the method in actor method table.
if m, ok := filcns.NewActorRegistry().Methods[codeCid]; !ok {
if m, ok := consensus.NewActorRegistry().Methods[codeCid]; !ok {
return fmt.Errorf("unrecognized actor: %s", actorcode)
} else if methodnum >= len(m) {
return fmt.Errorf("unrecognized method number for actor %s: %d", actorcode, methodnum)
+6 -5
View File
@@ -20,6 +20,7 @@ import (
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -106,7 +107,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
cs = store.NewChainStore(bs, bs, ds, filcns.Weight, nil)
tse = filcns.NewTipSetExecutor()
tse = consensus.NewTipSetExecutor(filcns.RewardFunc)
sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule(), nil)
)
if err != nil {
@@ -123,7 +124,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
defer cs.Close() //nolint:errcheck
blocks := make([]filcns.FilecoinBlockMessages, 0, len(tipset.Blocks))
blocks := make([]consensus.FilecoinBlockMessages, 0, len(tipset.Blocks))
for _, b := range tipset.Blocks {
sb := store.BlockMessages{
Miner: b.MinerAddr,
@@ -145,7 +146,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
sb.BlsMessages = append(sb.BlsMessages, msg)
}
}
blocks = append(blocks, filcns.FilecoinBlockMessages{
blocks = append(blocks, consensus.FilecoinBlockMessages{
BlockMessages: sb,
WinCount: b.WinCount,
})
@@ -265,7 +266,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
return nil, cid.Undef, err
}
invoker := filcns.NewActorRegistry()
invoker := consensus.NewActorRegistry()
av, _ := actorstypes.VersionForNetwork(params.NetworkVersion)
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{chaos.Actor{}})
invoker.Register(av, nil, registry)
@@ -283,7 +284,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
if err != nil {
return nil, cid.Undef, err
}
invoker := filcns.NewActorRegistry()
invoker := consensus.NewActorRegistry()
lvm.SetInvoker(invoker)
vmi = lvm
}
@@ -1,14 +1,14 @@
# Genesis block
Seems a good way to start exploring the VM state though the instantiation of its different actors like the storage power.
Seems a good way to start exploring the VM state through the instantiation of its different actors like the storage power.
Explain where do we load the genesis block, the CAR entries, and we set the root of the state. Follow the daemon command option, `chain.LoadGenesis()` saves all the blocks of the CAR file into the store provided by `ChainBlockstore` (this should already be explained in the previous section). The CAR root (MT root?) of those blocks is decoded into the `BlockHeader` that will be the Filecoin (genesis) block of the chain, but most of the information was stored in the raw data (non-Filecoin, what's the correct term?) blocks forwarded directly to the chain, the block header just has a pointer to it.
Explain where we load the genesis block, the CAR entries, and we set the root of the state. Follow the daemon command option, `chain.LoadGenesis()` saves all the blocks of the CAR file into the store provided by `ChainBlockstore` (this should already be explained in the previous section). The CAR root (MT root?) of those blocks is decoded into the `BlockHeader` that will be the Filecoin (genesis) block of the chain, but most of the information was stored in the raw data (non-Filecoin, what's the correct term?) blocks forwarded directly to the chain, the block header just has a pointer to it.
`SetGenesis` block with name 0. `(ChainStore).SetGenesis()` stores it there.
`MakeInitialStateTree` (`chain/gen/genesis/genesis.go`, used to construct the genesis block (`MakeGenesisBlock()`), constructs the state tree (`NewStateTree`) which is just a "pointer" (root node in the HAMT) to the different actors. It will be continuously used in `(*StateTree).SetActor()` an `types.Actor` structure under a certain `Address` (in the HAMT). (How does the `stateSnaps` work? It has no comments.)
From this point we can follow different setup function like:
From this point we can follow different setup functions like:
* `SetupInitActor()`: see the `AddressMap`.
@@ -40,7 +40,7 @@ List what are the main directories we should be looking at (e.g., `chain/`) and
# Tests
Run a few messages and observe state changes. What is the easiest test that also let's us "interact" with it (modify something and observe the difference).
Run a few messages and observe state changes. What is the easiest test that also lets us "interact" with it (modify something and observe the difference).
### Filecoin blocks vs IPFS blocks
@@ -84,7 +84,7 @@ func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
These edited extracts from the `BlockHeader` show how it's treated as an IPFS block, `github.com/ipfs/go-block-format.block.BasicBlock`, to be both stored and referenced by its block storage CID.
This duality permeates the code (and the Filecoin spec for that matter) but it is usually clear within the context to which block we are referring to. Normally the unqualified *block* is reserved for the Filecoin block and we won't usually refer to the IPFS one but only implicitly through the concept of its CID. With enough understanding of both stack's architecture the two definitions can coexist without much confusion as we will abstract away the IPFS layer and just use the CID as an identifier that we now its unique for two sequences of different *raw* byte strings.
This duality permeates the code (and the Filecoin spec for that matter) but it is usually clear within the context to which block we are referring to. Normally the unqualified *block* is reserved for the Filecoin block and we won't usually refer to the IPFS one but only implicitly through the concept of its CID. With enough understanding of both stack's architecture the two definitions can coexist without much confusion as we will abstract away the IPFS layer and just use the CID as an identifier that we know is unique for two sequences of different *raw* byte strings.
(FIXME: We use to do this presentation when talking about `gossipsub` topics and incoming blocks, and had to deal with, besides the block ambiguity, a similar confusion with the *message* term, used in libp2p to name anything that comes through the network, needing to present the extremely confusing hierarchy of a libp2p message containing a Filecoin block, identified by a IPFS block CID, containing Filecoin messages.)
@@ -150,4 +150,4 @@ Because we rely heavily on reflection for this part of the code the call chain i
This means that when we are tracking the logic of a CLI command we will eventually find this bifurcation and need to study the code of the server-side implementation in `node/impl/full` (mostly in the `common/` and `full/` directories). If we understand this architecture going directly to that part of the code abstracts away the JSON-RPC client/server logic and we can think that the CLI is actually running the node's logic.
FIXME: Explain that "*the* node" is actually an API structure like `impl.FullNodeAPI` with the different API subcomponents like `full.SyncAPI`. We won't see a *single* node structure, each API (full node, minder, etc) will gather the necessary subcomponents it needs to service its calls.
FIXME: Explain that "*the* node" is actually an API structure like `impl.FullNodeAPI` with the different API subcomponents like `full.SyncAPI`. We won't see a *single* node structure, each API (full node, minder, etc) will gather the necessary subcomponents it needs to service its calls.
+1 -1
View File
@@ -5,7 +5,7 @@ Lotus is an implementation of the **Filecoin Distributed Storage Network**.
It is written in Go and provides a suite of command-line applications:
- Lotus Node (`lotus`): a Filecoin Node: validates network transactions, manages a FIL wallet, can perform storage and retrieval deals.
- Lotus Miner (`lotus-miner`): a Filecoin miner. See the the respective Lotus Miner section in the Mine documentation.
- Lotus Miner (`lotus-miner`): a Filecoin miner. See the respective Lotus Miner section in the Mine documentation.
- Lotus Worker (`lotus-worker`): a worker that assists miners to perform mining-related tasks. See its respective guide for more information.
The [Lotus user documentation](https://lotus.filecoin.io/lotus/get-started/what-is-lotus/) is part of the [Filecoin documentation site](https://lotus.filecoin.io):
@@ -13,6 +13,7 @@
* [ChainCheckBlockstore](#ChainCheckBlockstore)
* [ChainDeleteObj](#ChainDeleteObj)
* [ChainExport](#ChainExport)
* [ChainExportRangeInternal](#ChainExportRangeInternal)
* [ChainGetBlock](#ChainGetBlock)
* [ChainGetBlockMessages](#ChainGetBlockMessages)
* [ChainGetEvents](#ChainGetEvents)
@@ -475,6 +476,50 @@ Inputs:
Response: `"Ynl0ZSBhcnJheQ=="`
### ChainExportRangeInternal
ChainExportRangeInternal triggers the export of a chain
CAR-snapshot directly to disk. It is similar to ChainExport,
except, depending on options, the snapshot can include receipts,
messages and stateroots for the length between the specified head
and tail, thus producing "archival-grade" snapshots that include
all the on-chain data. The header chain is included back to
genesis and these snapshots can be used to initialize Filecoin
nodes.
Perms: admin
Inputs:
```json
[
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
],
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
],
{
"WriteBufferSize": 123,
"NumWorkers": 123,
"IncludeMessages": true,
"IncludeReceipts": true,
"IncludeStateRoots": true
}
]
```
Response: `{}`
### ChainGetBlock
ChainGetBlock returns the block specified by the given CID.
@@ -81,7 +81,7 @@ Note: The API refers to these stages as `StageHeaders` and `StagePersistHeaders`
We proceed in the sync process by requesting block headers from the peer,
moving back from their head, until we reach a tipset that we have in common
(such a common tipset must exist, thought it may simply be the genesis block).
(such a common tipset must exist, though it may simply be the genesis block).
The functionality can be found in `Syncer::collectHeaders()`.
If the common tipset is our head, we treat the sync as a "fast-forward", else we must
@@ -126,7 +126,7 @@ If all validations pass we will now set that head as our heaviest tipset in
We already have the full state, since we calculated
it during the sync process.
FIXME (aayush) I don't fuilly understand the next 2 paragraphs, but it seems important. Confirm and polish.
FIXME (aayush) I don't fully understand the next 2 paragraphs, but it seems important. Confirm and polish.
Relevant issue in IPFS: https://github.com/ipfs/ipfs-docs/issues/264
It is important to note at this point that similar to the IPFS architecture of addressing by content and not by location/address (FIXME: check and link to IPFS docs) the "actual" chain stored in the node repo is *relative* to which CID we look for. We always have stored a series of Filecoin blocks pointing to other blocks, each a potential chain in itself by following its parent's reference, and its parent's parent, and so on up to the genesis block. (FIXME: We need a diagram here, one of the Filecoin blog entries might have something similar to what we are describing here.) It only depends on *where* (location) do we start to look for. The *only* address/location reference we hold of the chain, a relative reference, is the `heaviest` pointer. This is reflected by the fact that we don't store it in the `Blockstore` by a fixed, *absolute*, CID that reflects its contents, as this will change each time we sync to a new head (FIXME: link to the immutability IPFS doc that I need to write).
@@ -149,7 +149,7 @@ encapsulated in the [`StateTree`](https://github.com/filecoin-project/lotus/blob
and accessed through the
[`StateManager`](https://github.com/filecoin-project/lotus/blob/master/chain/stmgr/stmgr.go).
The state at the chain's head is thus easily tracked and updated in a state root CID.
(FIXME: Talk about CIDs somewhere, we might want to explain some of the modify/flush/update-root mechanism here.))
(FIXME: Talk about CIDs somewhere, we might want to explain some of the modify/flush/update-root mechanism here.)
## Calculating a Tipset State
+1 -1
View File
@@ -34,7 +34,7 @@ Assemble a `FullTipSet` populated with the single block received earlier.
`(*Syncer).collectHeaders()`: we retrieve all tipsets from the received block down to our chain. Validation now is expanded to *every* block inside these tipsets.
`V`: Beacon entires are ordered by their round number.
`V`: Beacon entries are ordered by their round number.
`V:` Tipset `Parents` CIDs match the fetched parent tipset through block sync. (This check is not enforced correctly at the moment, see [issue](https://github.com/filecoin-project/lotus/issues/1918).)
+32 -56
View File
@@ -7,7 +7,7 @@ USAGE:
lotus-miner [global options] command [command options] [arguments...]
VERSION:
1.20.0
1.21.0-dev
COMMANDS:
init Initialize a lotus miner repo
@@ -286,7 +286,7 @@ NAME:
lotus-miner actor set-peer-id - set the peer id of your miner
USAGE:
lotus-miner actor set-peer-id [command options] [arguments...]
lotus-miner actor set-peer-id [command options] <peer id>
OPTIONS:
--gas-limit value set gas limit (default: 0)
@@ -333,7 +333,6 @@ USAGE:
lotus-miner actor control list [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--verbose (default: false)
```
@@ -980,7 +979,6 @@ USAGE:
lotus-miner data-transfers list [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--completed show completed data transfers (default: false)
--show-failed show failed/cancelled transfers (default: false)
--verbose, -v print verbose transfer details (default: false)
@@ -1062,7 +1060,7 @@ USAGE:
lotus-miner dagstore list-shards [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1075,7 +1073,7 @@ USAGE:
lotus-miner dagstore register-shard [command options] [key]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1088,7 +1086,7 @@ USAGE:
lotus-miner dagstore initialize-shard [command options] [key]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1101,7 +1099,7 @@ USAGE:
lotus-miner dagstore recover-shard [command options] [key]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1114,7 +1112,6 @@ USAGE:
lotus-miner dagstore initialize-all [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--concurrency value maximum shards to initialize concurrently at a time; use 0 for unlimited (default: 0)
--include-sealed initialize sealed pieces as well (default: false)
@@ -1129,7 +1126,7 @@ USAGE:
lotus-miner dagstore gc [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1142,7 +1139,7 @@ USAGE:
lotus-miner dagstore lookup-pieces [command options] <cid>
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1173,7 +1170,7 @@ USAGE:
lotus-miner index announce [command options] <deal proposal cid>
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1186,7 +1183,7 @@ USAGE:
lotus-miner index announce-all [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -1677,14 +1674,13 @@ COMMANDS:
precommits Print on-chain precommit info
check-expire Inspect expiring sectors
expired Get or cleanup expired sectors
renew Renew expiring sectors while not exceeding each sector's max life
extend Extend sector expiration
extend Extend expiring sectors while not exceeding each sector's max life
terminate Terminate sector on-chain then remove (WARNING: This means losing power and collateral for the removed sector)
remove Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector (use 'terminate' for lower penalty))
snap-up Mark a committed capacity sector to be filled with deals
abort-upgrade Abort the attempted (SnapDeals) upgrade of a CC sector, reverting it to as before
seal Manually start sealing a sector (filling any unused space with junk)
set-seal-delay Set the time, in minutes, that a new sector waits for deals before sealing starts
set-seal-delay Set the time (in minutes) that a new sector waits for deals before sealing starts
get-cc-collateral Get the collateral required to pledge a committed capacity sector
batching manage batch sector operations
match-pending-pieces force a refreshed match of pending pieces to open sectors without manually waiting for more deals
@@ -1721,14 +1717,14 @@ USAGE:
lotus-miner sectors list [command options] [arguments...]
OPTIONS:
--color, -c use color in display output (default: depends on output being a TTY)
--events, -e display number of events the sector has received (default: false)
--fast, -f don't show on-chain info for better performance (default: false)
--initial-pledge, -p display initial pledge (default: false)
--seal-time, -t display how long it took for the sector to be sealed (default: false)
--show-removed, -r show removed sectors (default: false)
--states value filter sectors by a comma-separated list of states
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
--check-parallelism value number of parallel requests to make for checking sector states (default: 300)
--events, -e display number of events the sector has received (default: false)
--fast, -f don't show on-chain info for better performance (default: false)
--initial-pledge, -p display initial pledge (default: false)
--seal-time, -t display how long it took for the sector to be sealed (default: false)
--show-removed, -r show removed sectors (default: false)
--states value filter sectors by a comma-separated list of states
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
```
@@ -1884,13 +1880,13 @@ OPTIONS:
```
### lotus-miner sectors renew
### lotus-miner sectors extend
```
NAME:
lotus-miner sectors renew - Renew expiring sectors while not exceeding each sector's max life
lotus-miner sectors extend - Extend expiring sectors while not exceeding each sector's max life
USAGE:
lotus-miner sectors renew [command options] [arguments...]
lotus-miner sectors extend [command options] <sectorNumbers...(optional)>
OPTIONS:
--exclude value optionally provide a file containing excluding sectors
@@ -1900,31 +1896,13 @@ OPTIONS:
--max-sectors value the maximum number of sectors contained in each message message (default: 0)
--new-expiration value try to extend selected sectors to this epoch, ignoring extension (default: 0)
--only-cc only extend CC sectors (useful for making sector ready for snap upgrade) (default: false)
--really-do-it pass this flag to really renew sectors, otherwise will only print out json representation of parameters (default: false)
--really-do-it pass this flag to really extend sectors, otherwise will only print out json representation of parameters (default: false)
--sector-file value provide a file containing one sector number in each line, ignoring above selecting criteria
--to value only consider sectors whose current expiration epoch is in the range of [from, to], <to> defaults to: now + 92160 (32 days) (default: 0)
--tolerance value don't try to extend sectors by fewer than this number of epochs, defaults to 7 days (default: 20160)
```
### lotus-miner sectors extend
```
NAME:
lotus-miner sectors extend - Extend sector expiration
USAGE:
lotus-miner sectors extend [command options] <sectorNumbers...>
OPTIONS:
--expiration-cutoff value when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified) (default: 0)
--expiration-ignore value when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now (default: 120)
--new-expiration value new expiration epoch (default: 0)
--tolerance value when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs (default: 20160)
--v1-sectors renews all v1 sectors up to the maximum possible lifetime (default: false)
```
### lotus-miner sectors terminate
```
NAME:
@@ -2025,13 +2003,13 @@ OPTIONS:
### lotus-miner sectors set-seal-delay
```
NAME:
lotus-miner sectors set-seal-delay - Set the time, in minutes, that a new sector waits for deals before sealing starts
lotus-miner sectors set-seal-delay - Set the time (in minutes) that a new sector waits for deals before sealing starts
USAGE:
lotus-miner sectors set-seal-delay [command options] <minutes>
lotus-miner sectors set-seal-delay [command options] <time>
OPTIONS:
--help, -h show help (default: false)
--seconds Specifies that the time argument should be in seconds (default: false)
```
@@ -2223,7 +2201,7 @@ USAGE:
lotus-miner proving workers [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -2296,7 +2274,7 @@ NAME:
lotus-miner storage attach - attach local storage path
USAGE:
lotus-miner storage attach [command options] [arguments...]
lotus-miner storage attach [command options] [path]
DESCRIPTION:
Storage can be attached to the miner using this command. The storage volume
@@ -2349,7 +2327,7 @@ NAME:
lotus-miner storage redeclare - redeclare sectors in a local storage path
USAGE:
lotus-miner storage redeclare [command options] [arguments...]
lotus-miner storage redeclare [command options] [path]
OPTIONS:
--all redeclare all storage paths (default: false)
@@ -2371,7 +2349,6 @@ COMMANDS:
help, h Shows a list of commands or help for one command
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -2385,7 +2362,7 @@ USAGE:
lotus-miner storage list sectors [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
@@ -2458,7 +2435,6 @@ USAGE:
lotus-miner sealing jobs [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--show-ret-done show returned but not consumed calls (default: false)
```
@@ -2472,7 +2448,7 @@ USAGE:
lotus-miner sealing workers [command options] [arguments...]
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--help, -h show help (default: false)
```
+18 -32
View File
@@ -7,18 +7,17 @@ USAGE:
lotus-worker [global options] command [command options] [arguments...]
VERSION:
1.20.0
1.21.0-dev
COMMANDS:
run Start lotus worker
stop Stop a running lotus worker
info Print worker info
storage manage sector storage
set Manage worker settings
wait-quiet Block until all running tasks exit
resources Manage resource table overrides
tasks Manage task processing
help, h Shows a list of commands or help for one command
run Start lotus worker
stop Stop a running lotus worker
info Print worker info
storage manage sector storage
set Manage worker settings
resources Manage resource table overrides
tasks Manage task processing
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--enable-gpu-proving enable use of GPU for mining operations (default: true) [$LOTUS_WORKER_ENABLE_GPU_PROVING]
@@ -39,7 +38,7 @@ USAGE:
OPTIONS:
--addpiece enable addpiece (default: true) [$LOTUS_WORKER_ADDPIECE]
--commit enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap) (default: true) [$LOTUS_WORKER_COMMIT]
--commit enable commit (default: true) [$LOTUS_WORKER_COMMIT]
--http-server-timeout value (default: "30s")
--listen value host address and port the worker api will listen on (default: "0.0.0.0:3456") [$LOTUS_WORKER_LISTEN]
--name value custom worker name (default: hostname) [$LOTUS_WORKER_NAME]
@@ -47,16 +46,16 @@ OPTIONS:
--no-local-storage don't use storageminer repo for sector storage (default: false) [$LOTUS_WORKER_NO_LOCAL_STORAGE]
--no-swap don't use swap (default: false) [$LOTUS_WORKER_NO_SWAP]
--parallel-fetch-limit value maximum fetch operations to run in parallel (default: 5) [$LOTUS_WORKER_PARALLEL_FETCH_LIMIT]
--post-parallel-reads value maximum number of parallel challenge reads (0 = no limit) (default: 128) [$LOTUS_WORKER_POST_PARALLEL_READS]
--post-parallel-reads value maximum number of parallel challenge reads (0 = no limit) (default: 32) [$LOTUS_WORKER_POST_PARALLEL_READS]
--post-read-timeout value time limit for reading PoSt challenges (0 = no limit) (default: 0s) [$LOTUS_WORKER_POST_READ_TIMEOUT]
--precommit1 enable precommit1 (32G sectors: 1 core, 128GiB Memory) (default: true) [$LOTUS_WORKER_PRECOMMIT1]
--precommit2 enable precommit2 (32G sectors: all cores, 96GiB Memory) (default: true) [$LOTUS_WORKER_PRECOMMIT2]
--precommit1 enable precommit1 (default: true) [$LOTUS_WORKER_PRECOMMIT1]
--precommit2 enable precommit2 (default: true) [$LOTUS_WORKER_PRECOMMIT2]
--prove-replica-update2 enable prove replica update 2 (default: true) [$LOTUS_WORKER_PROVE_REPLICA_UPDATE2]
--regen-sector-key enable regen sector key (default: true) [$LOTUS_WORKER_REGEN_SECTOR_KEY]
--replica-update enable replica update (default: true) [$LOTUS_WORKER_REPLICA_UPDATE]
--sector-download enable external sector data download (default: false) [$LOTUS_WORKER_SECTOR_DOWNLOAD]
--timeout value used when 'listen' is unspecified. must be a valid duration recognized by golang's time.ParseDuration function (default: "30m") [$LOTUS_WORKER_TIMEOUT]
--unseal enable unsealing (32G sectors: 1 core, 128GiB Memory) (default: true) [$LOTUS_WORKER_UNSEAL]
--unseal enable unsealing (default: true) [$LOTUS_WORKER_UNSEAL]
--windowpost enable window post (default: false) [$LOTUS_WORKER_WINDOWPOST]
--winningpost enable winning post (default: false) [$LOTUS_WORKER_WINNINGPOST]
@@ -167,19 +166,6 @@ OPTIONS:
```
## lotus-worker wait-quiet
```
NAME:
lotus-worker wait-quiet - Block until all running tasks exit
USAGE:
lotus-worker wait-quiet [command options] [arguments...]
OPTIONS:
--help, -h show help (default: false)
```
## lotus-worker resources
```
NAME:
@@ -218,10 +204,10 @@ NAME:
lotus-worker tasks enable - Enable a task type
USAGE:
lotus-worker tasks enable [command options] [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
lotus-worker tasks enable [command options] --all | [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
OPTIONS:
--help, -h show help (default: false)
--all Enable all task types (default: false)
```
@@ -231,9 +217,9 @@ NAME:
lotus-worker tasks disable - Disable a task type
USAGE:
lotus-worker tasks disable [command options] [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
lotus-worker tasks disable [command options] --all | [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
OPTIONS:
--help, -h show help (default: false)
--all Disable all task types (default: false)
```
+53 -7
View File
@@ -7,7 +7,7 @@ USAGE:
lotus [global options] command [command options] [arguments...]
VERSION:
1.20.0
1.21.0-dev
COMMANDS:
daemon Start a lotus daemon process
@@ -39,6 +39,7 @@ COMMANDS:
status Check node status
GLOBAL OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--force-send if true, will ignore pre-send checks (default: false)
--help, -h show help (default: false)
--interactive setting to false will disable interactive functionality of commands (default: false)
@@ -687,7 +688,6 @@ CATEGORY:
RETRIEVAL
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--completed show completed retrievals (default: false)
--show-failed show failed/failing deals (default: true)
--verbose, -v print verbose deal details (default: false)
@@ -758,7 +758,6 @@ CATEGORY:
STORAGE
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--show-failed show failed/failing deals (default: false)
--verbose, -v print verbose deal details (default: false)
--watch watch deal updates in real-time, rather than a one time list (default: false)
@@ -891,7 +890,6 @@ CATEGORY:
UTIL
OPTIONS:
--color use color in display output (default: depends on output being a TTY)
--completed show completed data transfers (default: false)
--show-failed show failed/cancelled transfers (default: false)
--verbose, -v print verbose transfer details (default: false)
@@ -905,7 +903,7 @@ NAME:
lotus client restart-transfer - Force restart a stalled data transfer
USAGE:
lotus client restart-transfer [command options] [arguments...]
lotus client restart-transfer [command options] [transferID]
CATEGORY:
UTIL
@@ -922,7 +920,7 @@ NAME:
lotus client cancel-transfer - Force cancel a data transfer
USAGE:
lotus client cancel-transfer [command options] [arguments...]
lotus client cancel-transfer [command options] [transferID]
CATEGORY:
UTIL
@@ -1212,7 +1210,9 @@ COMMANDS:
check-notary-datacap check a notary's remaining bytes
sign-remove-data-cap-proposal allows a notary to sign a Remove Data Cap Proposal
list-allocations List allocations made by client
list-claims List claims made by provider
remove-expired-allocations remove expired allocations (if no allocations are specified all eligible allocations are removed)
remove-expired-claims remove expired claims (if no claims are specified all eligible claims are removed)
help, h Shows a list of commands or help for one command
OPTIONS:
@@ -1311,6 +1311,19 @@ OPTIONS:
```
### lotus filplus list-claims
```
NAME:
lotus filplus list-claims - List claims made by provider
USAGE:
lotus filplus list-claims [command options] providerAddress
OPTIONS:
--expired list only expired claims (default: false)
```
### lotus filplus remove-expired-allocations
```
NAME:
@@ -1324,6 +1337,19 @@ OPTIONS:
```
### lotus filplus remove-expired-claims
```
NAME:
lotus filplus remove-expired-claims - remove expired claims (if no claims are specified all eligible claims are removed)
USAGE:
lotus filplus remove-expired-claims [command options] providerAddress Optional[...claimId]
OPTIONS:
--from value optionally specify the account to send the message from
```
## lotus paych
```
NAME:
@@ -2005,7 +2031,7 @@ NAME:
lotus state market balance - Get the market balance (locked and escrowed) for a given account
USAGE:
lotus state market balance [command options] [arguments...]
lotus state market balance [command options] [address]
OPTIONS:
--help, -h show help (default: false)
@@ -2084,6 +2110,7 @@ COMMANDS:
get Get chain DAG node by path
bisect bisect chain for an event
export export chain to a car file
export-range export chain to a car file
slash-consensus Report consensus fault
gas-price Estimate gas prices
inspect-usage Inspect block space usage of a given tipset
@@ -2265,6 +2292,25 @@ OPTIONS:
```
### lotus chain export-range
```
NAME:
lotus chain export-range - export chain to a car file
USAGE:
lotus chain export-range [command options] [arguments...]
OPTIONS:
--head value specify tipset to start the export from (higher epoch) (default: "@head")
--messages specify if messages should be include (default: false)
--receipts specify if receipts should be include (default: false)
--stateroots specify if stateroots should be include (default: false)
--tail value specify tipset to end the export at (lower epoch) (default: "@tail")
--workers value specify the number of workers (default: 1)
--write-buffer value specify write buffer size (default: 1048576)
```
### lotus chain slash-consensus
```
NAME:
+1 -1
View File
@@ -2,7 +2,7 @@
This document explains the code flow of the [storage miner](https://filecoin-project.github.io/specs/#systems__filecoin_mining) creation process. It describes the flow on two dimensions: at the network level, from the local node to the rest of the Filecoin network, and at the VM level, from the CLI commands to the new chain state. It assumes the reader is already familiar with the general Lotus [architecture](architecture-2.md), relying especially on the descriptions of the CLI/API interface and the VM chain state.
Note we are not following the [Storage Mining](https://lotu.sh/en+mining) user documentation where the miner is created along with the owner through the faucet, but we do those in separate stages try to exercise what will be the closest code path to Mainnet, using the `createStorageMiner()` call in the CLI (when `--actor` is not provided).
Note we are not following the [Storage Mining](https://lotu.sh/en+mining) user documentation where the miner is created along with the owner through the faucet, but we do those in separate stages to try to exercise what will be the closest code path to Mainnet, using the `createStorageMiner()` call in the CLI (when `--actor` is not provided).
FIXME: Check that all the information it assumes throughout this document is actually present in the main architecture doc.
@@ -352,7 +352,7 @@
#
# type: int
# env var: LOTUS_PROVING_PARALLELCHECKLIMIT
#ParallelCheckLimit = 128
#ParallelCheckLimit = 32
# Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped
#
+1 -1
View File
@@ -19,7 +19,7 @@ Now go to `http://127.0.0.1:2222`.
## What can I test?
- The `Spawn Node` button starts a new **Lotus Node** in a new draggable window.
- Click `[Spawn Miner]` to start a **Lotus Miner**. This require's the node's wallet to have funds.
- Click `[Spawn Miner]` to start a **Lotus Miner**. This requires the node's wallet to have funds.
- Click on `[Client]` to open the **Lotus Node**'s client interface and propose a deal with an existing Miner. If successful you'll see a payment channel open up with that Miner.
Don't leave Pond unattended for more than 10 hours, the web client will eventually consume all available RAM.
+1 -1
View File
@@ -19,7 +19,7 @@ export LOTUS_JAEGER_AGENT_ENDPOINT=127.0.0.1:6831
lotus daemon
```
Alternatively, the agent endpoint can also be configured by a pair of environemnt variables to provide the host and port. The following snipit is functionally equivilent to the previous.
Alternatively, the agent endpoint can also be configured by a pair of environment variables to provide the host and port. The following snippet is functionally equivalent to the previous.
```bash
export LOTUS_JAEGER_AGENT_HOST=127.0.0.1
+2 -1
View File
@@ -307,7 +307,8 @@ type {{.Num}}Struct struct {
type {{.Num}}Methods struct {
{{range .Methods}}
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{$first := true}}{{range .Tags}}{{if $first}}{{$first = false}}{{else}} {{end}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
{{end}}
}
+4 -4
View File
@@ -39,7 +39,7 @@ require (
github.com/filecoin-project/go-data-transfer v1.15.2
github.com/filecoin-project/go-fil-commcid v0.1.0
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
github.com/filecoin-project/go-fil-markets v1.25.2
github.com/filecoin-project/go-fil-markets v1.26.0
github.com/filecoin-project/go-jsonrpc v0.2.1
github.com/filecoin-project/go-legs v0.4.4
github.com/filecoin-project/go-padreader v0.0.1
@@ -48,7 +48,6 @@ require (
github.com/filecoin-project/go-statemachine v1.0.2
github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0
github.com/filecoin-project/index-provider v0.9.1
github.com/filecoin-project/pubsub v1.0.0
github.com/filecoin-project/specs-actors v0.9.15
github.com/filecoin-project/specs-actors/v2 v2.3.6
@@ -111,6 +110,7 @@ require (
github.com/ipld/go-codec-dagpb v1.5.0
github.com/ipld/go-ipld-prime v0.20.0
github.com/ipld/go-ipld-selector-text-lite v0.0.1
github.com/ipni/index-provider v0.10.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/koalacxr/quantile v0.0.1
github.com/libp2p/go-buffer-pool v0.1.0
@@ -153,6 +153,7 @@ require (
go.opentelemetry.io/otel/bridge/opencensus v0.33.0
go.opentelemetry.io/otel/exporters/jaeger v1.2.0
go.opentelemetry.io/otel/sdk v1.11.1
go.uber.org/atomic v1.10.0
go.uber.org/fx v1.15.0
go.uber.org/multierr v1.8.0
go.uber.org/zap v1.23.0
@@ -203,7 +204,6 @@ require (
github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect
github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 // indirect
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
@@ -247,6 +247,7 @@ require (
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
github.com/ipfs/go-verifcid v0.0.2 // indirect
github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 // indirect
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c // indirect
@@ -334,7 +335,6 @@ require (
go.opentelemetry.io/otel/metric v0.33.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.33.0 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/dig v1.12.0 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
+6 -6
View File
@@ -331,8 +331,8 @@ github.com/filecoin-project/go-fil-commcid v0.1.0 h1:3R4ds1A9r6cr8mvZBfMYxTS88Oq
github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 h1:imrrpZWEHRnNqqv0tN7LXep5bFEVOVmQWHJvl2mgsGo=
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0fDJVnKADhfIv/d6dCbAGaAGWbdJEI8=
github.com/filecoin-project/go-fil-markets v1.25.2 h1:kVfgaamTC7dkn8KwS5zRJBNEBSNvVqdG3BCoDaUYuCI=
github.com/filecoin-project/go-fil-markets v1.25.2/go.mod h1:dc2oTPU6GH3Qk1nA+Er+hSX64rg+NVykkPIWFBYxcZU=
github.com/filecoin-project/go-fil-markets v1.26.0 h1:uNtt1UAxX2C/Q8tlWD00oF2Zma3CVGxhZmBc2ljYhkk=
github.com/filecoin-project/go-fil-markets v1.26.0/go.mod h1:eOIYHfPwyqc64O1HiapvcelfnrTfU7gLQgBf55IYleQ=
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM=
@@ -366,8 +366,6 @@ github.com/filecoin-project/go-statestore v0.2.0 h1:cRRO0aPLrxKQCZ2UOQbzFGn4WDNd
github.com/filecoin-project/go-statestore v0.2.0/go.mod h1:8sjBYbS35HwPzct7iT4lIXjLlYyPor80aU7t7a/Kspo=
github.com/filecoin-project/go-storedcounter v0.1.0 h1:Mui6wSUBC+cQGHbDUBcO7rfh5zQkWJM/CpAZa/uOuus=
github.com/filecoin-project/go-storedcounter v0.1.0/go.mod h1:4ceukaXi4vFURIoxYMfKzaRF5Xv/Pinh2oTnoxpv+z8=
github.com/filecoin-project/index-provider v0.9.1 h1:Jnh9dviIHvQxZ2baNoYu3n8z6F9O62ksnVlyREgPyyM=
github.com/filecoin-project/index-provider v0.9.1/go.mod h1:NlHxQcy2iMGfUoUGUzrRxntcpiC50QSnvp68u2VTT40=
github.com/filecoin-project/pubsub v1.0.0 h1:ZTmT27U07e54qV1mMiQo4HDr0buo8I1LDHBYLXlsNXM=
github.com/filecoin-project/pubsub v1.0.0/go.mod h1:GkpB33CcUtUNrLPhJgfdy4FDx4OMNR9k+46DHx/Lqrg=
github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao=
@@ -388,8 +386,6 @@ github.com/filecoin-project/specs-actors/v7 v7.0.1 h1:w72xCxijK7xs1qzmJiw+WYJaVt
github.com/filecoin-project/specs-actors/v7 v7.0.1/go.mod h1:tPLEYXoXhcpyLh69Ccq91SOuLXsPWjHiY27CzawjUEk=
github.com/filecoin-project/specs-actors/v8 v8.0.1 h1:4u0tIRJeT5G7F05lwLRIsDnsrN+bJ5Ixj6h49Q7uE2Y=
github.com/filecoin-project/specs-actors/v8 v8.0.1/go.mod h1:UYIPg65iPWoFw5NEftREdJwv9b/5yaLKdCgTvNI/2FA=
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 h1:6GCuzxLVHBzlz7y+FkbHh6n0UyoEGWqDwJKQPJoz7bE=
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893/go.mod h1:S7590oDimBvXMUtzWsBXoshu9HtYKwtXl47zAK9rcP8=
github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg=
github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
@@ -910,6 +906,10 @@ github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
github.com/ipld/go-ipld-selector-text-lite v0.0.1 h1:lNqFsQpBHc3p5xHob2KvEg/iM5dIFn6iw4L/Hh+kS1Y=
github.com/ipld/go-ipld-selector-text-lite v0.0.1/go.mod h1:U2CQmFb+uWzfIEF3I1arrDa5rwtj00PrpiwwCO+k1RM=
github.com/ipni/index-provider v0.10.0 h1:nu8YBxzRopdjwZHsgCUuC4AHpq88VVHJYrbkqUDx7eg=
github.com/ipni/index-provider v0.10.0/go.mod h1:InSXbZp2p/ZhAwiDElG/wzjnA1ea1iJ3hhyiAHrD+Vo=
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 h1:qJq6QtLk+9nQi3CDBhNfJ1cjZ4pghjCHcQUZ1mWbF0k=
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15/go.mod h1:c/NS640Iu2NrCCIErnUhsUM5KVEyeXymgtNnx6eDwMU=
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c=
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
+1 -1
View File
@@ -8,12 +8,12 @@ import (
"testing"
"time"
provider "github.com/ipni/index-provider"
"github.com/stretchr/testify/require"
datatransfer "github.com/filecoin-project/go-data-transfer"
"github.com/filecoin-project/go-fil-markets/shared_testutil"
"github.com/filecoin-project/go-state-types/abi"
provider "github.com/filecoin-project/index-provider"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/itests/kit"
@@ -166,7 +166,7 @@ func testDMExportAsFile(ctx context.Context, client *kit.TestFullNode, expDirect
func testV0RetrievalAsFile(ctx context.Context, client *kit.TestFullNode, retOrder api0.RetrievalOrder, tempDir string) error {
out := tempDir + string(os.PathSeparator) + "exp-test" + retOrder.Root.String()
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
err := cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
Path: out,
})
@@ -220,7 +220,7 @@ func tesV0RetrievalAsCar(ctx context.Context, client *kit.TestFullNode, retOrder
}
defer out.Close() //nolint:errcheck
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
err = cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
Path: out.Name(),
IsCAR: true,
+33
View File
@@ -858,6 +858,39 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
require.Len(t, receipt.Logs, 1)
}
// This test ensures that we can deploy new contracts from a solidity call to `transfer` without
// exceeding the 10M gas limit.
func TestFEVMTestDeployOnTransfer(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
fromAddr := client.DefaultKey.Address
t.Log("from - ", fromAddr)
//create contract A
filenameStorage := "contracts/ValueSender.hex"
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
//send to some random address.
params := [32]byte{}
params[30] = 0xff
randomAddr, err := ethtypes.CastEthAddress(params[12:])
value := big.NewInt(100)
entryPoint := kit.CalcFuncSignature("sendEthToB(address)")
require.NoError(t, err)
ret, err := client.EVM().InvokeSolidityWithValue(ctx, fromAddr, contractAddr, entryPoint, params[:], value)
require.NoError(t, err)
require.True(t, ret.Receipt.ExitCode.IsSuccess())
balance, err := client.EVM().EthGetBalance(ctx, randomAddr, "latest")
require.NoError(t, err)
require.Equal(t, value.Int, balance.Int)
filAddr, err := randomAddr.ToFilecoinAddress()
require.NoError(t, err)
client.AssertActorType(ctx, filAddr, manifest.PlaceholderKey)
}
func TestFEVMProxyUpgradeable(t *testing.T) {
ctx, cancel, client := kit.SetupFEVMTest(t)
defer cancel()
+5 -1
View File
@@ -104,6 +104,10 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string
}
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) {
return e.InvokeSolidityWithValue(ctx, sender, target, selector, inputData, big.Zero())
}
func (e *EVM) InvokeSolidityWithValue(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte, value big.Int) (*api.MsgLookup, error) {
params := append(selector, inputData...)
var buffer bytes.Buffer
err := cbg.WriteByteArray(&buffer, params)
@@ -115,7 +119,7 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
msg := &types.Message{
To: target,
From: sender,
Value: big.Zero(),
Value: value,
Method: builtintypes.MethodsEVM.InvokeContract,
GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041
Params: params,
+14 -1
View File
@@ -38,7 +38,7 @@ func TestPaymentChannelsAPI(t *testing.T) {
kit.QuietMiningLogs()
ctx := context.Background()
blockTime := 5 * time.Millisecond
blockTime := 10 * time.Millisecond
var (
paymentCreator kit.TestFullNode
@@ -55,6 +55,15 @@ func TestPaymentChannelsAPI(t *testing.T) {
bms := ens.BeginMiningMustPost(blockTime)
bm := bms[0]
waitRecvInSync := func() {
// paymentCreator is the block miner, in some cases paymentReceiver may fall behind, so we wait for it to catch up
head, err := paymentReceiver.ChainHead(ctx)
require.NoError(t, err)
paymentReceiver.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()))
}
// send some funds to register the receiver
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
@@ -74,6 +83,8 @@ func TestPaymentChannelsAPI(t *testing.T) {
channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.WaitSentinel)
require.NoError(t, err)
waitRecvInSync()
// allocate three lanes
var lanes []uint64
for i := 0; i < 3; i++ {
@@ -110,6 +121,8 @@ func TestPaymentChannelsAPI(t *testing.T) {
res := waitForMessage(ctx, t, paymentCreator, settleMsgCid, time.Second*10, "settle")
require.EqualValues(t, 0, res.Receipt.ExitCode, "Unable to settle payment channel")
waitRecvInSync()
creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(paymentCreator)))
// wait for the receiver to submit their vouchers
+24 -1
View File
@@ -282,7 +282,7 @@ func (w *RpcReader) Read(p []byte) (int, error) {
}
if w.postBody == nil {
return 0, xerrors.Errorf("reader already closed or redirected")
return 0, xerrors.Errorf("reader already closed, redirected or cancelled")
}
n, err := w.postBody.Read(p)
@@ -406,6 +406,29 @@ func ReaderParamDecoder() (http.HandlerFunc, jsonrpc.ServerOption) {
return
case <-req.Context().Done():
log.Errorf("context error in reader stream handler (2): %v", req.Context().Err())
closed := make(chan struct{})
// start a draining goroutine
go func() {
for {
select {
case r, ok := <-wr.res:
if !ok {
return
}
log.Errorw("discarding read res", "type", r.rt, "meta", r.meta)
case <-closed:
return
}
}
}()
wr.beginOnce.Do(func() {})
wr.closeOnce.Do(func() {
close(wr.res)
})
close(closed)
resp.WriteHeader(500)
return
}
+130
View File
@@ -7,7 +7,9 @@ import (
"io/ioutil"
"net/http/httptest"
"strings"
"sync"
"testing"
"time"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
@@ -20,6 +22,9 @@ import (
type ReaderHandler struct {
readApi func(ctx context.Context, r io.Reader) ([]byte, error)
cont chan struct{}
subErr error
}
func (h *ReaderHandler) ReadAllApi(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
@@ -31,6 +36,24 @@ func (h *ReaderHandler) ReadAllApi(ctx context.Context, r io.Reader, mustRedir b
return h.readApi(ctx, r)
}
func (h *ReaderHandler) ReadAllWaiting(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
if mustRedir {
if err := r.(*RpcReader).MustRedirect(); err != nil {
return nil, err
}
}
h.cont <- struct{}{}
<-h.cont
var m []byte
m, h.subErr = h.readApi(ctx, r)
h.cont <- struct{}{}
return m, h.subErr
}
func (h *ReaderHandler) ReadStartAndApi(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
if mustRedir {
if err := r.(*RpcReader).MustRedirect(); err != nil {
@@ -194,3 +217,110 @@ func TestReaderRedirect(t *testing.T) {
err = redirClient.CloseReader(context.TODO(), strings.NewReader("rediracted pooooootato"))
require.NoError(t, err)
}
func TestReaderRedirectDrop(t *testing.T) {
// lower timeout so that the dangling connection between client and reader is dropped quickly
// after the test. Otherwise httptest.Close is blocked.
Timeout = 200 * time.Millisecond
var allClient struct {
ReadAll func(ctx context.Context, r io.Reader) ([]byte, error)
}
{
allServerHandler := &ReaderHandler{}
readerHandler, readerServerOpt := ReaderParamDecoder()
rpcServer := jsonrpc.NewServer(readerServerOpt)
rpcServer.Register("ReaderHandler", allServerHandler)
mux := mux.NewRouter()
mux.Handle("/rpc/v0", rpcServer)
mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler)
testServ := httptest.NewServer(mux)
defer testServ.Close()
t.Logf("test server reading: %s", testServ.URL)
re := ReaderParamEncoder("http://" + testServ.Listener.Addr().String() + "/rpc/streams/v0/push")
closer, err := jsonrpc.NewMergeClient(context.Background(), "ws://"+testServ.Listener.Addr().String()+"/rpc/v0", "ReaderHandler", []interface{}{&allClient}, nil, re)
require.NoError(t, err)
defer closer()
}
var redirClient struct {
ReadAllWaiting func(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error)
}
contCh := make(chan struct{})
allServerHandler := &ReaderHandler{readApi: allClient.ReadAll, cont: contCh}
readerHandler, readerServerOpt := ReaderParamDecoder()
rpcServer := jsonrpc.NewServer(readerServerOpt)
rpcServer.Register("ReaderHandler", allServerHandler)
mux := mux.NewRouter()
mux.Handle("/rpc/v0", rpcServer)
mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler)
testServ := httptest.NewServer(mux)
defer testServ.Close()
t.Logf("test server redirecting: %s", testServ.URL)
re := ReaderParamEncoder("http://" + testServ.Listener.Addr().String() + "/rpc/streams/v0/push")
closer, err := jsonrpc.NewMergeClient(context.Background(), "http://"+testServ.Listener.Addr().String()+"/rpc/v0", "ReaderHandler", []interface{}{&redirClient}, nil, re)
require.NoError(t, err)
defer closer()
var done sync.WaitGroup
// Happy case
done.Add(1)
go func() {
defer done.Done()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
read, err := redirClient.ReadAllWaiting(ctx, strings.NewReader("rediracted pooooootato"), true)
require.NoError(t, err)
require.Equal(t, "rediracted pooooootato", string(read), "potatoes weren't equal")
}()
<-contCh // exec enter ReadAllWaiting
contCh <- struct{}{} // stert subcall
<-contCh // wait for subcall to finish
done.Wait()
// Redir client drops before subcall
done.Add(1)
go func() {
defer done.Done()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, err := redirClient.ReadAllWaiting(ctx, strings.NewReader("rediracted pooooootato"), true)
require.ErrorContains(t, err, "sendRequest failed")
}()
// wait for execution to enter ReadAllWaiting
<-contCh
// kill redirecting server connection
testServ.CloseClientConnections()
// ReadAllWaiting should fail
done.Wait()
// resume execution in ReadAllWaiting, calling redicect
contCh <- struct{}{}
// wait for subcall to finish
<-contCh
require.ErrorContains(t, allServerHandler.subErr, "decoding params for 'ReaderHandler.ReadAll' (param: 0; custom decoder): context canceled")
}
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"github.com/minio/blake2b-simd"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-crypto"
crypto "github.com/filecoin-project/go-crypto"
crypto2 "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/lib/sigs"
+3 -3
View File
@@ -83,7 +83,7 @@ func TestLotusAccessorFetchUnsealedPiece(t *testing.T) {
dealInfo := piecestore.DealInfo{
SectorID: sectorID,
}
err = ps.AddDealForPiece(cid1, dealInfo)
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
require.NoError(t, err)
}
@@ -124,7 +124,7 @@ func TestLotusAccessorGetUnpaddedCARSize(t *testing.T) {
dealInfo := piecestore.DealInfo{
Length: 10,
}
err = ps.AddDealForPiece(cid1, dealInfo)
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
require.NoError(t, err)
// Check that the data length is correct
@@ -153,7 +153,7 @@ func TestThrottle(t *testing.T) {
SectorID: unsealedSectorID,
Length: 10,
}
err = ps.AddDealForPiece(cid1, dealInfo)
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
require.NoError(t, err)
// hold the lock to block.
+2 -1
View File
@@ -67,9 +67,10 @@ var (
ConnectionManagerKey = special{9} // Libp2p option
AutoNATSvcKey = special{10} // Libp2p option
BandwidthReporterKey = special{11} // Libp2p option
ConnGaterKey = special{12} // libp2p option
ConnGaterKey = special{12} // Libp2p option
DAGStoreKey = special{13} // constructor returns multiple values
ResourceManagerKey = special{14} // Libp2p option
UserAgentKey = special{15} // Libp2p option
)
type invoke int
+1 -1
View File
@@ -76,7 +76,7 @@ var ChainNode = Options(
// Consensus: Chain storage/access
Override(new(chain.Genesis), chain.LoadGenesis),
Override(new(store.WeightFunc), filcns.Weight),
Override(new(stmgr.Executor), filcns.NewTipSetExecutor()),
Override(new(stmgr.Executor), consensus.NewTipSetExecutor(filcns.RewardFunc)),
Override(new(consensus.Consensus), filcns.NewFilecoinExpectedConsensus),
Override(new(*store.ChainStore), modules.ChainStore),
Override(new(*stmgr.StateManager), modules.StateManager),

Some files were not shown because too many files have changed in this diff Show More