Compare commits

..
Author SHA1 Message Date
Aayush Rajasekaran a6b2180756 Merge pull request #4323 from filecoin-project/asr/changelog
Lotus version 0.10.0
2020-10-12 02:27:55 -04:00
Aayush Rajasekaran 160f209f6a Lotus version 0.10.0 2020-10-12 02:14:36 -04:00
Aayush Rajasekaran a9d8bc7c45 Merge pull request #4322 from filecoin-project/steb/tape-upgrade
implement tape upgrade
2020-10-12 02:14:13 -04:00
Steven Allen 92177b5738 implement tape upgrade
Upgrade to specs-actors v2.1 and network version 5. This fixes the bug where
prove commits were not accepted.
2020-10-12 02:00:27 -04:00
Łukasz Magiera 8fd9b5f235 Merge pull request #4315 from filecoin-project/feat/stats-ops
lotus-stats: optmize getting miner power
2020-10-12 06:01:52 +02:00
Jakub Sztandera a95e343dee Merge pull request #4321 from filecoin-project/feat/love
Chain is love
2020-10-12 05:44:34 +02:00
Steven Allen c296e1bbca use actor abstraction in metrics command 2020-10-11 20:31:20 -07:00
Jakub Sztandera ae366972a9 Chain is love
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 05:11:04 +02:00
Travis Person 23470bc38f lotus-stats: optmize getting miner power 2020-10-11 20:27:36 +00:00
Whyrusleeping 40b2e2d0c1 Merge pull request #4312 from filecoin-project/feat/msig-inspect-decode
decode parameters for multisig transactions in inspect
2020-10-11 11:51:32 -05:00
Łukasz Magiera 00620aac57 Merge pull request #4296 from filecoin-project/feat/sync-unmarkbad-all
sync unmark-bad --all
2020-10-10 22:35:56 +02:00
Łukasz Magiera 32d95fc97a docsgen, gofmt 2020-10-10 20:46:06 +02:00
Łukasz Magiera a491fc97b9 Merge pull request #4301 from filecoin-project/steb/fix-two-races
Fix two races
2020-10-10 20:37:13 +02:00
Łukasz Magiera 151577f04e Merge pull request #4287 from filecoin-project/feat/flush_validation_cache_on_chain_import
Dump the block validation cache whenever we perform an import
2020-10-10 20:33:17 +02:00
Steven Allen c463582528 fix a race and optimize hello messages
LifecycleCtx can _only_ be called during startup as it appends an fx hook.
Worse, this was causing us to append an fx hook on every single hello message,
leaking memory (and probably causing other shutdown issues...).
2020-10-10 08:33:06 -07:00
Steven Allen 7245ac2b69 fix a race in the sync manager
1. SyncerState contains a mutex and should never be copied. Honestly, this case
was probably fine but it's just as easy to create a separate snapshot type and
easier to reason about.

2. We need to initialize the syncStates array once at start, before accessing
it. By each syncer state inside each worker, we were racing with calls to
`State()`. Again, this was probably benign, but I don't trust optimizing
compilers.
2020-10-10 08:31:04 -07:00
Łukasz Magiera 58f13a7d5a Merge pull request #4299 from filecoin-project/fix/wallet-export-panic
Fix panic in wallet export when key is not found
2020-10-10 16:25:40 +02:00
Peter Rabbitson e7d3b2503e Merge tag 'v0.9.1' 2020-10-10 15:54:51 +02:00
Łukasz Magiera ee8b8b8174 Merge pull request #4298 from filecoin-project/fix/cli-stderr-errors
cli: Don't output errors to stdout
2020-10-10 15:52:43 +02:00
Łukasz Magiera 4fa6afad13 Fix panic in wallet export when key is not found 2020-10-10 15:44:22 +02:00
Łukasz Magiera a80e98dc05 cli: Don't output errors to stdout 2020-10-10 15:38:14 +02:00
Peter Rabbitson 23f5a99117 Add comment clarifying current codepath 2020-10-10 15:36:32 +02:00
Łukasz Magiera 651522cbaa Merge pull request #4274 from filecoin-project/feat/msig-remove-api
add an api for removing multisig signers
2020-10-10 12:56:07 +02:00
Łukasz Magiera 388c9afce0 docsgen 2020-10-10 12:28:59 +02:00
Łukasz Magiera 9a26896c69 Merge pull request #4282 from filecoin-project/steb/fix-tipset-cache-race
fix a race in tipset cache usage
2020-10-10 12:27:15 +02:00
Łukasz Magiera 2db8b7efa7 Merge pull request #4291 from filecoin-project/steb/node-test-races
make pledge test pass with the race detector
2020-10-10 11:54:25 +02:00
Łukasz Magiera 18e58467f8 sync unmark-bad --all 2020-10-10 10:26:42 +02:00
Łukasz Magiera 1401efb115 Merge pull request #4294 from filecoin-project/feat/v0.9.1
Bump the version to 0.9.1
2020-10-10 09:15:04 +02:00
Łukasz Magiera f417d39a08 Bump the version to 0.9.1 2020-10-10 09:13:52 +02:00
Łukasz Magiera 11e35cf911 Merge pull request #4293 from filecoin-project/steb/actors-fixes
upgrade specs-actors
2020-10-10 08:53:20 +02:00
Steven Allen 10d464a1eb upgrade to specs-actors v2.0.3 2020-10-09 21:52:01 -07:00
Steven Allen d84f5dabab remove upgrade invariant checks
These checks may be _too_ strict and could cause the upgrade to fail unnecessarily.
2020-10-09 21:51:58 -07:00
Steven Allen f3abd1ae82 make pledge test pass with the race detector 2020-10-09 20:32:09 -07:00
Peter Rabbitson 85abca4b16 Delint 2020-10-10 04:00:12 +02:00
Peter Rabbitson 6610a247cf Dump the block validation cache whenever we perform an import
This solves a problem with folks resurrecting long-out-of-sync nodes via
snapshot imports.

The interface switch to Batching is necessary: startup is too long otherwise
( 8 minutes just to clear everything on a relatively old node )
2020-10-10 03:41:04 +02:00
Łukasz Magiera a6d9b302fa Merge pull request #3583 from filecoin-project/feat/signing-backends
Remote wallet backends
2020-10-10 02:58:02 +02:00
Steven Allen f32b3bf99b fix a race in tipset cache usage
This tipset cache is shared between multiple services and is called from
multiple places.
2020-10-09 17:32:45 -07:00
Łukasz Magiera 114a1aaffd Merge pull request #4281 from filecoin-project/steb/seal-race
fix race in unseal
2020-10-10 02:23:02 +02:00
Łukasz Magiera 83ba7ec8cc Merge pull request #4280 from filecoin-project/fix/market-deal-race
fix a race when retrieving pieces
2020-10-10 02:15:47 +02:00
Steven Allen 83dfc460d4 fix race in unseal
1. Remove an invalid error check.
2. Make sure to shadow the outer error type from within the goroutine instead or
reading the outer type.

This may have been causing test issues (caught in TestMinerAllInfo with the race
detector).
2020-10-09 15:39:41 -07:00
Steven Allen 283fd054e8 fix a race when retrieving pieces
We'd read the deal ID without synchronizing. This could (and probably did given
the history of flaky deal tests) cause us to miss events.

This patch also makes sure to always unsubscribe from events, even on error.
2020-10-09 15:35:44 -07:00
Łukasz Magiera 09bff14d85 Merge pull request #4269 from filecoin-project/steb/simplify-sync
simplify message syncing logic
2020-10-10 00:00:26 +02:00
Łukasz Magiera 3cb1abba4f Merge pull request #4276 from filecoin-project/steb/fix-bad-error
return the correct err from iterFullTipset
2020-10-09 23:26:54 +02:00
Łukasz Magiera d4c92942e7 Merge pull request #4275 from filecoin-project/steb/unshare-journal
unshare the journal
2020-10-09 23:16:27 +02:00
Aayush Rajasekaran f773ab4b28 Correct docs 2020-10-09 17:14:21 -04:00
Steven Allen c0182f8301 return the correct err from iterFullTipset 2020-10-09 13:59:56 -07:00
Łukasz Magiera c06f394b81 Merge pull request #4273 from filecoin-project/fix/fundsmgr-incorrect-cached-value
Revert cached "available" amount if the AddFunds message send fails
2020-10-09 22:52:40 +02:00
Steven Allen 748d2e82a7 unshare the journal
Motivation:

* Run lotus with the race detector enabled (primary motivation).
* Allow multiple lotus nodes in a process (not a high priority).

Previously, the journal was shared between all lotus instances, but it was
initialized for every new node. This caused safety problems in tests (at a
minimum).

This patch explicitly passes the journal to all services that need it.
2020-10-09 13:23:07 -07:00
Steven Allen a5c78371fd Merge pull request #4270 from filecoin-project/steb/test-fix-paychstatus-race
fix a race in the payment channel status test
2020-10-09 13:22:16 -07:00
Ingar Shu d80e7eda93 Revert cached "available" amount if the AddFunds message send fails 2020-10-09 13:18:43 -07:00
Steven Allen 9f9d5cb2a5 fix a race in the payment channel status test
We should not be clobbering the cmd variable.
2020-10-09 11:50:16 -07:00
Łukasz Magiera fdaa9c14ad Merge remote-tracking branch 'origin/master' into feat/signing-backends 2020-10-09 20:36:51 +02:00
Łukasz Magiera 9d8932d395 Merge pull request #4268 from iand/fix/rewardv2-cumsumrealized
fix: spec actors 2 reward shim uses correct field for CumsumRealized
2020-10-09 20:32:14 +02:00
Steven Allen 105aa40007 simplify message syncing logic
1. Allow duplicate blocks from bitswap. This shouldn't happen, but there's no
reason to bail (just log loudly).
2. Simplify logic to very explicitly check to make sure we're fetching every
block.
2020-10-09 11:06:49 -07:00
Łukasz Magiera 110f033c83 Merge pull request #4095 from filecoin-project/feat/daemon-lite
lotus-lite: replace wallet / msig calls with thin client to gateway
2020-10-09 19:22:43 +02:00
Ian Davis f87d325b6f fix: spec actors 2 reward shim uses correct field for CumsumRealized 2020-10-09 17:48:20 +01:00
Łukasz Magiera ab8286fa38 Fix docsgen, lotus-soup build 2020-10-09 18:43:22 +02:00
whyrusleeping 4cca3f19a3 add an api for removing multisig signers 2020-10-09 09:40:25 -07:00
Łukasz Magiera feb4b3c8b4 Merge remote-tracking branch 'origin/master' into feat/signing-backends 2020-10-09 15:51:25 +02:00
Dirk McCormick 7f7c9e978f feat: hide lite mode flag 2020-10-09 11:56:25 +02:00
Dirk McCormick 200a95f824 refactor: unify test builder full node options 2020-10-09 11:56:25 +02:00
Dirk McCormick d69e4c7cf2 refactor: lite-mode - simplify organization of dep injection 2020-10-09 11:54:42 +02:00
Dirk McCormick b2834baa4b feat: add msig available balance and vested to lite mode 2020-10-09 11:51:20 +02:00
Dirk McCormick e9e27cbbb0 feat: put gateway in middle of end-to-end test for lite mode 2020-10-09 11:48:35 +02:00
Dirk McCormick ef73b964fb feat: add end-to-end test for lite mode 2020-10-09 11:48:35 +02:00
Dirk McCormick 7b1bec91ed feat: add tests for gateway ChainGetTipsetByHeight 2020-10-09 11:45:16 +02:00
Dirk McCormick b32d25c562 feat: add RPC for GasEstimateMessageGas 2020-10-09 11:45:16 +02:00
Dirk McCormick 767611247c feat: add RPC for StateWaitMsg 2020-10-09 11:45:16 +02:00
Dirk McCormick be09a8a00a feat: lite-mode - check that gateway API implements required chain, mpool, state methods 2020-10-09 11:43:03 +02:00
Dirk McCormick 2719adc1b1 feat: lite-mode - thin client for chan & state 2020-10-09 11:43:03 +02:00
Dirk McCormick f1b1d8cec6 fix: MpoolAPI DI 2020-10-09 11:43:03 +02:00
Dirk McCormick 8fa4c0a970 feat: gateway - MpoolPush 2020-10-09 11:43:03 +02:00
Dirk McCormick 00a14de094 feat: gateway - StateLookupID 2020-10-09 11:43:03 +02:00
Dirk McCormick eec13ff8dc refactor: daemon - simplify gateway cleanup 2020-10-09 11:43:03 +02:00
Dirk McCormick 1ffdd7d5b3 fix: gateway - remove tracing (JsonRPC automatically traces all calls) 2020-10-09 11:43:03 +02:00
Dirk McCormick e19cd9ed01 feat: lotus-lite - replace wallet StateManager with thin client to gateway 2020-10-09 11:43:03 +02:00
Łukasz Magiera bacac245c7 Merge pull request #4256 from filecoin-project/steb/call-stop
cleanup tests on finish
2020-10-09 10:20:33 +02:00
Łukasz Magiera e1792ffe4d Merge pull request #4260 from filecoin-project/asr/wallet-abstract
Fix deletion of addresses from wallet
2020-10-09 09:55:25 +02:00
Aayush Rajasekaran 9c35762966 Fix deletion of addresses from wallet 2020-10-09 03:26:51 -04:00
Łukasz Magiera 356137439f apistruct: Drop unused WalletSignMessage 2020-10-09 03:12:33 +02:00
Łukasz Magiera 6cc7559b04 Fix APIInfo import cycle in tests 2020-10-09 02:58:12 +02:00
Łukasz Magiera 3cd53ad9d9 Use APIInfo parser for RemoteBacked wallet config 2020-10-09 02:21:37 +02:00
Łukasz Magiera 6c54d2445d Appease the linter 2020-10-09 01:53:12 +02:00
Łukasz Magiera 6a10af626c Nicer message logging in lotus-wallet 2020-10-09 01:50:46 +02:00
Łukasz Magiera 597d065e05 Update go-jsonrpc with http(s) client support 2020-10-09 01:39:06 +02:00
Łukasz Magiera 791aa5c6c8 Add lotus-wallet to Makefile 2020-10-09 01:37:17 +02:00
Steven Allen 82b15d2637 cleanup tests on finish 2020-10-08 16:36:02 -07:00
Łukasz Magiera 7d2f06cfbd Fix WalletSign in tests 2020-10-09 01:34:48 +02:00
Łukasz Magiera 6e8efb9d2c gofmt 2020-10-09 01:27:49 +02:00
Łukasz Magiera f3dc730b05 wallet: Add metadata to WalletAPI.WalletSign 2020-10-09 01:27:38 +02:00
Łukasz Magiera 114776f2c5 wallet: Drop WalletSignMessage from WalletAPI 2020-10-09 01:04:59 +02:00
Łukasz Magiera 4835109470 wallet: Post-merge fixes 2020-10-09 00:51:04 +02:00
Łukasz Magiera 8783c7434e Merge remote-tracking branch 'origin/master' into feat/signing-backends 2020-10-09 00:50:41 +02:00
Łukasz Magiera 2d3b61675b Merge pull request #3444 from IPFSMain-Official/fix-GetBestMiningCandidate-bug
fix GetBestMiningCandidate bug
2020-10-08 23:55:19 +02:00
刘林欣 a23ab123d7 fix GetBestMiningCandidate bug
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-08 23:39:33 +02:00
Łukasz Magiera 26ed6af040 Merge pull request #4227 from filecoin-project/par-upper-bounds
Increase the message fee cap upper bounds in PCR.
2020-10-08 23:34:32 +02:00
Łukasz Magiera 82bd7bd2ec Merge pull request #4224 from filecoin-project/fix/repub-journal
Fix Messages field in MessagePoolEvtMessage journal entry
2020-10-08 23:33:57 +02:00
Łukasz Magiera cd0a43b7f4 Merge pull request #4253 from filecoin-project/fix/syncwait-applied-offset
sync wait: Handle processed message offset
2020-10-08 23:30:55 +02:00
Łukasz Magiera b14632b750 Merge pull request #4250 from filecoin-project/asr/vesting-params-api
Add some new endpoints for querying Msig info
2020-10-08 23:25:23 +02:00
Łukasz Magiera ebcf77e830 Merge pull request #4254 from filecoin-project/feat/update-markets-0.7.1
Update markets v0.7.1
2020-10-08 23:24:08 +02:00
Łukasz Magiera 344d30e960 Merge pull request #4252 from filecoin-project/devnet-jennijuju
Update address prefix in client cli.
2020-10-08 23:23:40 +02:00
Łukasz Magiera efb13a0d9b Merge pull request #4246 from filecoin-project/feat/optim-search-msg
Optimize SearchForMessage and GetReceipt
2020-10-08 23:22:49 +02:00
Łukasz Magiera 0223582d41 sync wait: Handle processed message offset 2020-10-08 23:14:12 +02:00
Jakub Sztandera 973f61bc10 Optimize chain and message sync
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-08 23:10:07 +02:00
Jakub Sztandera 60768f4863 Optimize SearchForMessage and GetReceipt
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-08 23:10:06 +02:00
hannahhoward c60d13ee56 feat(markets): update markets v0.7.1 2020-10-08 13:52:39 -07:00
jennijuju 0f8fc119f3 Update address prefix in client cli. 2020-10-08 16:45:24 -04:00
Łukasz Magiera e4d2e6e01d Merge pull request #4249 from filecoin-project/feat/ux-enhancements
Feat/ux enhancements
2020-10-08 22:30:20 +02:00
Łukasz Magiera d55f10bed6 Merge pull request #4251 from filecoin-project/upgrade/noise
upgrade go-libp2p-noise to v0.1.2.
2020-10-08 22:26:46 +02:00
Raúl Kripalani 21de538d09 upgrade go-libp2p-noise to v0.1.2.
Improves throughput in large and/or fast transfers
and reduces syscalls when data is queued in receive
buffer, by using bufio.Reader.
2020-10-08 21:19:09 +01:00
Aayush Rajasekaran fe5b32026a Add some new endpoints for querying Msig info 2020-10-08 15:51:21 -04:00
Łukasz Magiera 91c10c2df5 Merge pull request #4248 from filecoin-project/feat/update-libp2p
Update libp2p things
2020-10-08 21:08:38 +02:00
Ingar Shu c3420c0ceb Display price, verified-price with units in lotus-miner storage-deals get-ask 2020-10-08 12:08:01 -07:00
vyzo 7933cf094f allow all drand topics 2020-10-08 21:48:55 +03:00
vyzo 4cd73f1560 use subscription filter in pubsub 2020-10-08 21:40:36 +03:00
vyzo 8a175a7465 update go-libp2p-pubsub and go-libp2p-quic-transport 2020-10-08 21:32:10 +03:00
Ingar Shu f7f229ae54 Show verified status in client list-deals 2020-10-08 11:31:33 -07:00
Ingar Shu 1323e07a2c Don't show failed deals by default in client list-deals, add option to to show failed deals. 2020-10-08 11:31:33 -07:00
Ingar Shu 2ad671649c Use FIL units for miner set-ask 2020-10-08 11:31:32 -07:00
Łukasz Magiera d26ece10b8 Merge pull request #4241 from filecoin-project/fix/daemon-flag-clash
fix: clash between daemon --api flag and cli tests
2020-10-08 18:30:47 +02:00
Raúl Kripalani 4c8084dcb0 Merge pull request #4243 from filecoin-project/conformance/rm-faked-syscalls 2020-10-08 17:06:25 +01:00
Raúl Kripalani 98d702fb5a add signature imports. 2020-10-08 16:44:20 +01:00
Łukasz Magiera 17f61ac212 Merge pull request #4245 from filecoin-project/debug/chain-sync-lookback
add more info to chain sync lookback failure
2020-10-08 17:05:08 +02:00
Łukasz Magiera df67576b89 Merge pull request #4233 from filecoin-project/fix/balances-audit-no-suffix
Some improvements to the lotus-shed balance audit commands
2020-10-08 17:02:21 +02:00
whyrusleeping cdc2f86f5a add more info to chain sync lookback failure 2020-10-08 09:45:07 -05:00
Raúl Kripalani 67b3a55e30 update test-vectors submodule. 2020-10-08 15:44:11 +01:00
Raúl Kripalani 3201e0eb8f Merge branch 'master' into conformance/rm-faked-syscalls 2020-10-08 15:17:26 +01:00
Raúl Kripalani 8d2d74438b Merge pull request #4221 from filecoin-project/conformance/randomness 2020-10-08 15:16:32 +01:00
Raúl Kripalani 1f9446f91f upgrade to test vectors schema v0.0.4. 2020-10-08 15:00:35 +01:00
Raúl Kripalani 4937ca1a96 conformance: remove usage of fake syscalls. 2020-10-08 14:55:03 +01:00
Łukasz Magiera 264fe4edb9 Merge pull request #4230 from filecoin-project/feat/inspect-counts
Add message counts to inspect chain output
2020-10-08 15:12:28 +02:00
Dirk McCormick cb7d99fcc7 fix: clash between daemon --api flag and cli tests 2020-10-08 14:24:50 +02:00
Łukasz Magiera 7332a39f00 Merge remote-tracking branch 'origin/master' into fix/balances-audit-no-suffix 2020-10-08 13:58:40 +02:00
Aayush Rajasekaran 8f35a5c036 Merge pull request #4238 from filecoin-project/asr/changelog
Lotus version 0.9.0
2020-10-07 23:25:02 -04:00
Aayush Rajasekaran dea7042668 Lotus version 0.9.0 2020-10-07 23:09:08 -04:00
Aayush Rajasekaran bd8f3f05be Merge pull request #4237 from filecoin-project/next
Merge next into master
2020-10-07 23:08:48 -04:00
Aayush Rajasekaran 304d835739 Merge branch 'master' into next 2020-10-07 23:03:59 -04:00
Łukasz Magiera cb8678e4c2 Merge pull request #4235 from filecoin-project/asr/set-head-unmark-valid
Set head should unmark blocks as valid
2020-10-08 03:58:05 +02:00
Aayush Rajasekaran da34548a05 Set head should unmark blocks as valid 2020-10-07 21:52:29 -04:00
whyrusleeping cd9af278b4 more info in audit outputs 2020-10-07 17:01:01 -07:00
Łukasz Magiera b1fe92f8ff Merge pull request #4201 from filecoin-project/feat/faster-v2-upgrade
stmgr: Make v2 upgrade faster
2020-10-08 01:56:05 +02:00
Łukasz Magiera 8dd8892b81 Merge remote-tracking branch 'origin/next' into feat/faster-v2-upgrade 2020-10-08 01:54:29 +02:00
Łukasz Magiera 79dba816c7 Merge pull request #4232 from filecoin-project/steb/fix-v2-actor-error
return an illegal actor error when we see an unsupported actor version
2020-10-08 01:47:10 +02:00
Aayush Rajasekaran 14bb4c9a0b Merge pull request #4196 from filecoin-project/asr/update-epoch
Set actorsv2 upgrade epoch
2020-10-07 19:45:56 -04:00
Łukasz Magiera f9f54819d4 Env var to control v2 actor migration
Env var to control v2 actor migration
2020-10-07 19:41:36 -04:00
Aayush Rajasekaran d1555106a4 Set actorsv2 upgrade epoch 2020-10-07 19:41:36 -04:00
Steven Allen 413c357361 Merge pull request #4231 from filecoin-project/steb/call-at-upgrade
reject explicit "calls" at the upgrade height
2020-10-07 16:33:51 -07:00
Steven Allen d97eb10349 fix spelling nit 2020-10-07 16:32:54 -07:00
Steven Allen e8253d22c6 only forbid Call* at expensive forks 2020-10-07 16:14:11 -07:00
Steven Allen a4e954197c retry StateCall at different height if we're at an expensive fork height 2020-10-07 16:03:42 -07:00
whyrusleeping 8f4911ac0d dont print fil suffix in lotus shed audit balances 2020-10-07 16:00:52 -07:00
Steven Allen b0bea5f145 return an illegal actor error when we see an unsupported actor version
As far as the chain is concerned, this actor does not exist.
2020-10-07 15:46:56 -07:00
Travis Person 7c7e0d73d5 Merge pull request #4229 from filecoin-project/fix/lotus-pcr-zero-refund
lotus-pcr: zero refund
2020-10-07 15:33:28 -07:00
Steven Allen 1fea550ce5 test that we refuse explicit calls at the migration epochs 2020-10-07 15:33:14 -07:00
Steven Allen 9b7b6146eb construct the new vm with the state manager's vm constructor 2020-10-07 15:31:14 -07:00
Steven Allen dab1107f5b avoid estimating gas and explicitly calling blocks on fork tipsets
These tipsets can be slow.
2020-10-07 15:31:14 -07:00
Steven Allen fe912223bd pass an explicit upgrade height to migrations
The tipset height may not be the correct one, given null blocks.
2020-10-07 15:31:12 -07:00
whyrusleeping 12cd478e11 Add message counts to inspect chain output 2020-10-07 15:14:46 -07:00
Travis Person ae3691e0a2 lotus-pcr: zero refund 2020-10-07 21:53:56 +00:00
Jennifer e55b00f358 Increase the message fee cap upper bounds in PCR. 2020-10-07 17:07:19 -04:00
Steven Allen de3f4111f4 Merge pull request #4197 from filecoin-project/steb/state-tree-version
introduce separate state-tree versions
2020-10-07 12:29:14 -07:00
Steven Allen 767c346cf8 update test-vectors 2020-10-07 12:17:32 -07:00
Jakub Sztandera 6f4a762664 Fix Messages field in MessagePoolEvtMessage journal entry
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-07 21:13:04 +02:00
Raúl Kripalani c02daca9e9 work around #4223. 2020-10-07 20:12:35 +01:00
Steven Allen cca17f6078 fix state tree version in v2 upgrade 2020-10-07 12:04:32 -07:00
Steven Allen c17fa4bc35 update test-vectors for StateManager constructor change 2020-10-07 12:04:32 -07:00
Steven Allen e803cf151f introduce separate state-tree versions
Instead of versioning the state tree along with the actors, version it
separately. This structure may not upgrade every time we update actors.
2020-10-07 12:04:32 -07:00
Łukasz Magiera 1268cfbfcd Merge pull request #4218 from filecoin-project/fix/lotus-pcr-ignore-other-messages
lotus-pcr: ignore all other messages
2020-10-07 21:03:53 +02:00
Łukasz Magiera 5ef929f130 Merge pull request #4219 from filecoin-project/merge-master-to-next
Merge branch 'master' into merge-master-to-next
2020-10-07 21:02:57 +02:00
Raúl Kripalani 5bd6a3cdad conformance: record randomness in tvx; replay in driver. 2020-10-07 19:57:42 +01:00
Steven Allen df4b068d0e Merge branch 'master' into next 2020-10-07 11:55:00 -07:00
Travis Person 0d34881a0c lotus-pcr: ignore all other messages 2020-10-07 18:50:50 +00:00
Steven Allen 6eb49b717f Merge pull request #4214 from filecoin-project/gas-tracing-public
make vm.EnableGasTracing public.
2020-10-07 11:12:55 -07:00
Whyrusleeping 099b982ea8 Merge pull request #4178 from filecoin-project/frrist/miner-diff-deadlines
feat(miner): add miner deadline diffing logic.
2020-10-07 12:00:31 -05:00
Łukasz Magiera 10c120bd3c Merge pull request #4213 from filecoin-project/feat/test-addrs-envvar
build: Env var to keep test address output
2020-10-07 18:49:55 +02:00
Raúl Kripalani 7cd1330acd make vm.EnableGasTracing public. 2020-10-07 15:52:03 +01:00
Łukasz Magiera 39bc816a79 build: Env var to keep test address output 2020-10-07 15:01:30 +02:00
Łukasz Magiera 81fb552e1d Merge pull request #4211 from filecoin-project/conformance/minor-refactors
conformance: minor driver refactors.
2020-10-07 14:57:00 +02:00
Łukasz Magiera cfd126ee9f Merge pull request #3961 from filecoin-project/docs/miner-storage
lotus-miner: add more help text to storage / attach
2020-10-07 14:55:42 +02:00
Łukasz Magiera d6fa644974 Fix lint 2020-10-07 14:19:04 +02:00
Raúl Kripalani d3dc560f53 conformance: minor refactors. 2020-10-07 13:01:08 +01:00
Łukasz Magiera 25bc00eec8 Merge pull request #4200 from filecoin-project/feat/state-exec-trace
implement command to get execution traces of any message
2020-10-07 08:14:08 +02:00
whyrusleeping 3b12a9f425 Add flag to accept previous output of compute-state as input 2020-10-07 08:12:39 +02:00
Łukasz Magiera b7c8f65af5 stmgr: Make v2 upgrade faster 2020-10-07 08:12:05 +02:00
Łukasz Magiera c6e0cb4ff2 Merge pull request #4205 from filecoin-project/feat/noncefix-manual-fee-cap
allow manual setting of noncefix fee cap
2020-10-07 08:08:52 +02:00
Łukasz Magiera f6eb530cba Merge pull request #4203 from filecoin-project/fix/pond-actorsv2
Fix pond
2020-10-07 07:55:38 +02:00
Travis Person f4991e868e Merge pull request #4198 from filecoin-project/feat/lotus-pcr-cap-limit
Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals
2020-10-06 21:03:43 -07:00
whyrusleeping be92dd9e63 allow manual setting of noncefix fee cap 2020-10-06 18:07:34 -07:00
Łukasz Magiera 15670942c3 Fix pond 2020-10-07 01:50:11 +02:00
whyrusleeping bd474617ed implement command to get execution traces of any message 2020-10-06 16:06:24 -07:00
Travis Person 087030fe37 lotus-pcr: refund windowed post and storage deal gas fees 2020-10-06 22:35:04 +00:00
Travis Person 4a3081c77a lotus-pcr: limit refunds to properly priced messages 2020-10-06 20:13:48 +00:00
frrist d4cbd4fb55 feat(miner): add miner deadline diffing
- logic gathering all removed, faulted, recovered, and recovering
sectors for a miner.
2020-10-06 11:39:38 -07:00
Łukasz Magiera 1fc23fb466 lotus-miner: Cleanup storage attach helptext a bit 2020-10-03 11:30:22 +02:00
whyrusleeping ef3987e2ab decode parameters for multisig transactions in inspect 2020-10-02 14:51:32 -07:00
Travis Person c66f087f4c lotus-miner: add more help text to storage / attach 2020-09-22 18:15:42 +00:00
Łukasz Magiera 780f6dba34 Remote wallet backends 2020-09-05 21:39:09 +02:00
Łukasz Magiera f90cfda2e6 wallet: Add interface layer 2020-09-04 22:18:03 +02:00
150 changed files with 4495 additions and 1241 deletions
+1
View File
@@ -12,6 +12,7 @@
/lotus-bench
/lotus-gateway
/lotus-pcr
/lotus-wallet
/bench.json
/lotuspond/front/node_modules
/lotuspond/front/build
+133 -1
View File
@@ -1,5 +1,137 @@
# Lotus changelog
# 0.10.0 / 2020-10-12
This is a consensus-breaking hotfix that addresses an issue in specs-actors v2.0.3 that made it impossible to pledge new 32GiB sectors. The change in Lotus is to update to actors v2.1.0, behind the new network version 5.
## Changes
- make pledge test pass with the race detector (https://github.com/filecoin-project/lotus/pull/4291)
- fix a race in tipset cache usage (https://github.com/filecoin-project/lotus/pull/4282)
- add an api for removing multisig signers (https://github.com/filecoin-project/lotus/pull/4274)
- cli: Don't output errors to stdout (https://github.com/filecoin-project/lotus/pull/4298)
- Fix panic in wallet export when key is not found (https://github.com/filecoin-project/lotus/pull/4299)
- Dump the block validation cache whenever we perform an import (https://github.com/filecoin-project/lotus/pull/4287)
- Fix two races (https://github.com/filecoin-project/lotus/pull/4301)
- sync unmark-bad --all (https://github.com/filecoin-project/lotus/pull/4296)
- decode parameters for multisig transactions in inspect (https://github.com/filecoin-project/lotus/pull/4312)
- Chain is love (https://github.com/filecoin-project/lotus/pull/4321)
- lotus-stats: optmize getting miner power (https://github.com/filecoin-project/lotus/pull/4315)
- implement tape upgrade (https://github.com/filecoin-project/lotus/pull/4322)
# 0.9.1 / 2020-10-10
This release fixes an issue which may cause the actors v2 migration to compute the state incorrectly when more than one migration is running in parallel.
## Changes
- Make concurrent actor migrations safe (https://github.com/filecoin-project/lotus/pull/4293)
- Remote wallet backends (https://github.com/filecoin-project/lotus/pull/3583)
- Track funds in FundMgr correctly in case of AddFunds failing (https://github.com/filecoin-project/lotus/pull/4273)
- Partial lite-node mode (https://github.com/filecoin-project/lotus/pull/4095)
- Fix potential infinite loop in GetBestMiningCandidate (https://github.com/filecoin-project/lotus/pull/3444)
- sync wait: Handle processed message offset (https://github.com/filecoin-project/lotus/pull/4253)
- Add some new endpoints for querying Msig info (https://github.com/filecoin-project/lotus/pull/4250)
- Update markets v0.7.1 (https://github.com/filecoin-project/lotus/pull/4254)
- Optimize SearchForMessage and GetReceipt (https://github.com/filecoin-project/lotus/pull/4246)
- Use FIL instead of attoFIL in CLI more consistently (https://github.com/filecoin-project/lotus/pull/4249)
- fix: clash between daemon --api flag and cli tests (https://github.com/filecoin-project/lotus/pull/4241)
- add more info to chain sync lookback failure (https://github.com/filecoin-project/lotus/pull/4245)
- Add message counts to inspect chain output (https://github.com/filecoin-project/lotus/pull/4230)
# 0.9.0 / 2020-10-07
This consensus-breaking release of Lotus upgrades the actors version to v2.0.0. This requires migrating actor state from v0 to v2. The changes that break consensus are:
- Introducing v2 actors and its migration (https://github.com/filecoin-project/lotus/pull/3936)
- Runtime's Receiver() should only return ID addresses (https://github.com/filecoin-project/lotus/pull/3589)
- Update miner eligibility checks for v2 actors (https://github.com/filecoin-project/lotus/pull/4188)
- Add funds that have left FilReserve to circ supply (https://github.com/filecoin-project/lotus/pull/4160)
- Set WinningPoStSectorSetLookback to finality post-v2 actors (https://github.com/filecoin-project/lotus/pull/4190)
- fix: error when actor panics directly (https://github.com/filecoin-project/lotus/pull/3697)
## Changes
#### Dependencies
- Update go-bitfield (https://github.com/filecoin-project/lotus/pull/4171)
- update the AMT implementation (https://github.com/filecoin-project/lotus/pull/4194)
- Update to actors v0.2.1 (https://github.com/filecoin-project/lotus/pull/4199)
#### Core Lotus
- Paych: fix voucher amount verification (https://github.com/filecoin-project/lotus/pull/3821)
- Cap market provider messages (https://github.com/filecoin-project/lotus/pull/4141)
- Run fork function after cron for null block safety (https://github.com/filecoin-project/lotus/pull/4114)
- use bitswap sessions when fetching messages, and cancel them (https://github.com/filecoin-project/lotus/pull/4142)
- relax pubsub IPColocationFactorThreshold to 5 (https://github.com/filecoin-project/lotus/pull/4183)
- Support addresses with mainnet prefixes (https://github.com/filecoin-project/lotus/pull/4186)
- fix: make message signer nonce generation transactional (https://github.com/filecoin-project/lotus/pull/4165)
- build: Env var to keep test address output (https://github.com/filecoin-project/lotus/pull/4213)
- make vm.EnableGasTracing public (https://github.com/filecoin-project/lotus/pull/4214)
- introduce separate state-tree versions (https://github.com/filecoin-project/lotus/pull/4197)
- reject explicit "calls" at the upgrade height (https://github.com/filecoin-project/lotus/pull/4231)
- return an illegal actor error when we see an unsupported actor version (https://github.com/filecoin-project/lotus/pull/4232)
- Set head should unmark blocks as valid (https://gist.github.com/travisperson/3c7cddd77a33979a519ccef4e6515f20)
#### Mining
- Increased ExpectedSealDuration and and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743)
- Miner backup/restore commands (https://github.com/filecoin-project/lotus/pull/4133)
- lotus-miner: add more help text to storage / attach (https://github.com/filecoin-project/lotus/pull/3961)
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
- feat(miner): add miner deadline diffing logic (https://github.com/filecoin-project/lotus/pull/4178)
#### UX
- Improve the UX for replacing messages (https://github.com/filecoin-project/lotus/pull/4134)
- Add verified flag to interactive deal creation (https://github.com/filecoin-project/lotus/pull/4145)
- Add command to (slowly) prune lotus chain datastore (https://github.com/filecoin-project/lotus/pull/3876)
- Some helpers for verifreg work (https://github.com/filecoin-project/lotus/pull/4124)
- Always use default 720h for setask duration and hide the duration param option (https://github.com/filecoin-project/lotus/pull/4077)
- Convert ID addresses to key addresses before checking wallet (https://github.com/filecoin-project/lotus/pull/4122)
- add a command to view block space utilization (https://github.com/filecoin-project/lotus/pull/4176)
- allow usage inspection on a chain segment (https://github.com/filecoin-project/lotus/pull/4177)
- Add mpool stats for base fee (https://github.com/filecoin-project/lotus/pull/4170)
- Add verified status to api.DealInfo (https://github.com/filecoin-project/lotus/pull/4153)
- Add a CLI command to set a miner's owner address (https://github.com/filecoin-project/lotus/pull/4189)
#### Tooling and validation
- Lotus-pcr: add recover-miners command (https://github.com/filecoin-project/lotus/pull/3714)
- MpoolPushUntrusted API for gateway (https://github.com/filecoin-project/lotus/pull/3915)
- Test lotus-miner info all (https://github.com/filecoin-project/lotus/pull/4166)
- chain export: Error with unfinished exports (https://github.com/filecoin-project/lotus/pull/4179)
- add printf in TestWindowPost (https://github.com/filecoin-project/lotus/pull/4043)
- add trace wdpost (https://github.com/filecoin-project/lotus/pull/4020)
- Fix noncefix (https://github.com/filecoin-project/lotus/pull/4202)
- Lotus-pcr: Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals (https://github.com/filecoin-project/lotus/pull/4198)
- Fix pond (https://github.com/filecoin-project/lotus/pull/4203)
- allow manual setting of noncefix fee cap (https://github.com/filecoin-project/lotus/pull/4205)
- implement command to get execution traces of any message (https://github.com/filecoin-project/lotus/pull/4200)
- conformance: minor driver refactors (https://github.com/filecoin-project/lotus/pull/4211)
- lotus-pcr: ignore all other messages (https://github.com/filecoin-project/lotus/pull/4218)
- lotus-pcr: zero refund (https://github.com/filecoin-project/lotus/pull/4229)
## Contributors
The following contributors had 5 or more commits go into this release.
We are grateful for every contribution!
| Contributor | Commits | Lines ± |
|--------------------|---------|---------------|
| Stebalien | 84 | +3425/-2287 |
| magik6k | 41 | +2121/-506 |
| arajasek | 39 | +2467/-424 |
| Kubuxu | 25 | +2344/-775 |
| raulk | 21 | +287/-196 |
| whyrusleeping | 13 | +727/-71 |
| hsanjuan | 13 | +5886/-7956 |
| dirkmc | 11 | +2634/-576 |
| travisperson | 8 | +923/-202 |
| ribasushi | 6 | +188/-128 |
| zgfzgf | 5 | +21/-17 |
# 0.8.1 / 2020-09-30
This optional release of Lotus introduces a new version of markets which switches to CBOR-map encodings, and allows datastore migrations. The release also introduces several improvements to the mining process, a few performance optimizations, and a battery of UX additions and enhancements.
@@ -117,7 +249,7 @@ We are grateful for every contribution!
| vyzo | 22 | +287/-196 |
| alanshaw | 15 | +761/-146 |
| whyrusleeping | 15 | +736/-52 |
| hannahhoward | 14 | +1237/837- |
| hannahhoward | 14 | +1237/-837 |
| anton | 6 | +32/-8 |
| travisperson | 5 | +502/-6 |
| Frank | 5 | +78/-39 |
+6
View File
@@ -186,6 +186,12 @@ lotus-health:
.PHONY: lotus-health
BINS+=lotus-health
lotus-wallet:
rm -f lotus-wallet
go build -o lotus-wallet ./cmd/lotus-wallet
.PHONY: lotus-wallet
BINS+=lotus-wallet
testground:
go build -tags testground -o /dev/null ./cmd/lotus
.PHONY: testground
+40 -3
View File
@@ -172,6 +172,9 @@ type FullNode interface {
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
// SyncUnmarkAllBad purges bad block cache, making it possible to sync to chains previously marked as bad
SyncUnmarkAllBad(ctx context.Context) error
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
// the reason.
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
@@ -367,6 +370,10 @@ type FullNode interface {
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
// message arrives on chain, and gets to the indicated confidence depth.
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
// StateWaitMsgLimited looks back up to limit epochs in the chain for a message.
// If not found, it blocks until the message arrives on chain, and gets to the
// indicated confidence depth.
StateWaitMsgLimited(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch) (*MsgLookup, error)
// StateListMiners returns the addresses of every miner that has claimed power in the Power Actor
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
// StateListActors returns the addresses of every actor in the state
@@ -418,6 +425,8 @@ type FullNode interface {
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
// MsigGetVestingSchedule returns the vesting details of a given multisig.
MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error)
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
@@ -429,12 +438,21 @@ type FullNode interface {
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
// <sender address of the propose msg>, <method to call in the proposed message>, <params to include in the proposed message>
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
// MsigApprove approves a previously-proposed multisig message
// MsigApprove approves a previously-proposed multisig message by transaction ID
// It takes the following params: <multisig address>, <proposed transaction ID> <signer address>
MsigApprove(context.Context, address.Address, uint64, address.Address) (cid.Cid, error)
// MsigApproveTxnHash approves a previously-proposed multisig message, specified
// using both transaction ID and a hash of the parameters used in the
// proposal. This method of approval can be used to ensure you only approve
// exactly the transaction you think you are.
// It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
// <sender address of the approve msg>, <method to call in the proposed message>, <params to include in the proposed message>
MsigApprove(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
MsigApproveTxnHash(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
// MsigCancel cancels a previously-proposed multisig message
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
// It takes the following params: <multisig address>, <proposed transaction ID>, <recipient address>, <value to transfer>,
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
// MsigAddPropose proposes adding a signer in the multisig
@@ -462,6 +480,13 @@ type FullNode interface {
// <old signer>, <new signer>
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
// MsigRemoveSigner proposes the removal of a signer from the multisig.
// It accepts the multisig to make the change on, the proposer address to
// send the message from, the address to be removed, and a boolean
// indicating whether or not the signing threshold should be lowered by one
// along with the address removal.
MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error)
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
// MarketFreeBalance
@@ -871,3 +896,15 @@ type Fault struct {
Miner address.Address
Epoch abi.ChainEpoch
}
var EmptyVesting = MsigVesting{
InitialBalance: types.EmptyInt,
StartEpoch: -1,
UnlockDuration: -1,
}
type MsigVesting struct {
InitialBalance abi.TokenAmount
StartEpoch abi.ChainEpoch
UnlockDuration abi.ChainEpoch
}
+24
View File
@@ -0,0 +1,24 @@
package api
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
)
type GatewayAPI interface {
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error)
}
+47
View File
@@ -0,0 +1,47 @@
package api
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/types"
)
type MsgType string
const (
MTUnknown = "unknown"
// Signing message CID. MsgMeta.Extra contains raw cbor message bytes
MTChainMsg = "message"
// Signing a blockheader. signing raw cbor block bytes (MsgMeta.Extra is empty)
MTBlock = "block"
// Signing a deal proposal. signing raw cbor proposal bytes (MsgMeta.Extra is empty)
MTDealProposal = "dealproposal"
// TODO: Deals, Vouchers, VRF
)
type MsgMeta struct {
Type MsgType
// Additional data related to what is signed. Should be verifiable with the
// signed bytes (e.g. CID(Extra).Bytes() == toSign)
Extra []byte
}
type WalletAPI interface {
WalletNew(context.Context, crypto.SigType) (address.Address, error)
WalletHas(context.Context, address.Address) (bool, error)
WalletList(context.Context) ([]address.Address, error)
WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta MsgMeta) (*crypto.Signature, error)
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
WalletDelete(context.Context, address.Address) error
}
+6
View File
@@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
return &out
}
func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI {
var out WalletStruct
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
return &out
}
+131 -3
View File
@@ -111,6 +111,7 @@ type FullNodeStruct struct {
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
SyncUnmarkAllBad func(ctx context.Context) error `perm:"admin"`
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
SyncValidateTipset func(ctx context.Context, tsk types.TipSetKey) (bool, error) `perm:"read"`
@@ -190,6 +191,7 @@ type FullNodeStruct struct {
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
StateWaitMsgLimited func(context.Context, cid.Cid, uint64, abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"`
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
@@ -212,10 +214,12 @@ type FullNodeStruct struct {
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
MsigGetVestingSchedule func(context.Context, address.Address, types.TipSetKey) (api.MsigVesting, error) `perm:"read"`
MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"`
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
MsigApprove func(context.Context, address.Address, uint64, address.Address) (cid.Cid, error) `perm:"sign"`
MsigApproveTxnHash func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
@@ -223,6 +227,7 @@ type FullNodeStruct struct {
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
MsigRemoveSigner func(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) `perm:"sign"`
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
@@ -360,6 +365,35 @@ type WorkerStruct struct {
}
}
type GatewayStruct struct {
Internal struct {
// TODO: does the gateway need perms?
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
ChainHead func(ctx context.Context) (*types.TipSet, error)
GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
}
}
type WalletStruct struct {
Internal struct {
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
WalletSign func(context.Context, address.Address, []byte, api.MsgMeta) (*crypto.Signature, error) `perm:"sign"`
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
WalletDelete func(context.Context, address.Address) error `perm:"write"`
}
}
// CommonStruct
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
@@ -749,6 +783,10 @@ func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
return c.Internal.SyncUnmarkBad(ctx, bcid)
}
func (c *FullNodeStruct) SyncUnmarkAllBad(ctx context.Context) error {
return c.Internal.SyncUnmarkAllBad(ctx)
}
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
return c.Internal.SyncCheckBad(ctx, bcid)
}
@@ -853,6 +891,10 @@ func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confide
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
}
func (c *FullNodeStruct) StateWaitMsgLimited(ctx context.Context, msgc cid.Cid, confidence uint64, limit abi.ChainEpoch) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsgLimited(ctx, msgc, confidence, limit)
}
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
return c.Internal.StateSearchMsg(ctx, msgc)
}
@@ -933,6 +975,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
}
func (c *FullNodeStruct) MsigGetVestingSchedule(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MsigVesting, error) {
return c.Internal.MsigGetVestingSchedule(ctx, a, tsk)
}
func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
}
@@ -945,8 +991,12 @@ func (c *FullNodeStruct) MsigPropose(ctx context.Context, msig address.Address,
return c.Internal.MsigPropose(ctx, msig, to, amt, src, method, params)
}
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
return c.Internal.MsigApprove(ctx, msig, txID, proposer, to, amt, src, method, params)
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, signer address.Address) (cid.Cid, error) {
return c.Internal.MsigApprove(ctx, msig, txID, signer)
}
func (c *FullNodeStruct) MsigApproveTxnHash(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
return c.Internal.MsigApproveTxnHash(ctx, msig, txID, proposer, to, amt, src, method, params)
}
func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
@@ -977,6 +1027,10 @@ func (c *FullNodeStruct) MsigSwapCancel(ctx context.Context, msig address.Addres
return c.Internal.MsigSwapCancel(ctx, msig, src, txID, oldAdd, newAdd)
}
func (c *FullNodeStruct) MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) {
return c.Internal.MsigRemoveSigner(ctx, msig, proposer, toRemove, decrease)
}
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
return c.Internal.MarketEnsureAvailable(ctx, addr, wallet, amt)
}
@@ -1367,7 +1421,81 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
return w.Internal.Closing(ctx)
}
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
return g.Internal.ChainHead(ctx)
}
func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
return g.Internal.ChainGetTipSet(ctx, tsk)
}
func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (g GatewayStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
return g.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
}
func (g GatewayStruct) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
return g.Internal.MpoolPush(ctx, sm)
}
func (g GatewayStruct) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
return g.Internal.MsigGetAvailableBalance(ctx, addr, tsk)
}
func (g GatewayStruct) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
return g.Internal.MsigGetVested(ctx, addr, start, end)
}
func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
return g.Internal.StateAccountKey(ctx, addr, tsk)
}
func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
return g.Internal.StateGetActor(ctx, actor, ts)
}
func (g GatewayStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
return g.Internal.StateLookupID(ctx, addr, tsk)
}
func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return g.Internal.StateWaitMsg(ctx, msg, confidence)
}
func (c *WalletStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
return c.Internal.WalletNew(ctx, typ)
}
func (c *WalletStruct) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
return c.Internal.WalletHas(ctx, addr)
}
func (c *WalletStruct) WalletList(ctx context.Context) ([]address.Address, error) {
return c.Internal.WalletList(ctx)
}
func (c *WalletStruct) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
return c.Internal.WalletSign(ctx, k, msg, meta)
}
func (c *WalletStruct) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) {
return c.Internal.WalletExport(ctx, a)
}
func (c *WalletStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
return c.Internal.WalletImport(ctx, ki)
}
func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) error {
return c.Internal.WalletDelete(ctx, addr)
}
var _ api.Common = &CommonStruct{}
var _ api.FullNode = &FullNodeStruct{}
var _ api.StorageMiner = &StorageMinerStruct{}
var _ api.WorkerAPI = &WorkerStruct{}
var _ api.GatewayAPI = &GatewayStruct{}
var _ api.WalletAPI = &WalletStruct{}
+26
View File
@@ -82,3 +82,29 @@ func NewWorkerRPC(ctx context.Context, addr string, requestHeader http.Header) (
return &res, closer, err
}
// NewGatewayRPC creates a new http jsonrpc client for a gateway node.
func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
var res apistruct.GatewayStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{
&res.Internal,
},
requestHeader,
opts...,
)
return &res, closer, err
}
func NewWalletRPC(ctx context.Context, addr string, requestHeader http.Header) (api.WalletAPI, jsonrpc.ClientCloser, error) {
var res apistruct.WalletStruct
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
[]interface{}{
&res.Internal,
},
requestHeader,
)
return &res, closer, err
}
+1 -8
View File
@@ -12,10 +12,7 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node"
"github.com/filecoin-project/lotus/node/impl"
)
@@ -37,11 +34,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
ctx := context.Background()
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
Network: build.ActorUpgradeNetworkVersion,
Height: upgradeHeight,
Migration: stmgr.UpgradeActorsV2,
}}))
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
+4 -4
View File
@@ -48,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, OneMiner)
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -85,7 +85,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, OneMiner)
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -149,7 +149,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, OneMiner)
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -204,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, OneMiner)
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
+3 -3
View File
@@ -25,7 +25,7 @@ var log = logging.Logger("apitest")
func (ts *testSuite) testMining(t *testing.T) {
ctx := context.Background()
apis, sn := ts.makeNodes(t, 1, OneMiner)
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
api := apis[0]
newHeads, err := api.ChainNotify(ctx)
@@ -54,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
}()
ctx := context.Background()
apis, sn := ts.makeNodes(t, 1, OneMiner)
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
api := apis[0]
newHeads, err := api.ChainNotify(ctx)
@@ -93,7 +93,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
// test making a deal with a fresh miner, and see if it starts to mine
ctx := context.Background()
n, sn := b(t, 1, []StorageMiner{
n, sn := b(t, OneFull, []StorageMiner{
{Full: 0, Preseal: PresealGenesis},
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
})
+1 -1
View File
@@ -33,7 +33,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 2, OneMiner)
n, sn := b(t, TwoFull, OneMiner)
paymentCreator := n[0]
paymentReceiver := n[1]
+43 -4
View File
@@ -4,11 +4,14 @@ import (
"context"
"testing"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"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/miner"
@@ -35,17 +38,27 @@ var PresealGenesis = -1
const GenesisPreseals = 2
// Options for setting up a mock storage miner
type StorageMiner struct {
Full int
Preseal int
}
type OptionGenerator func([]TestNode) node.Option
// Options for setting up a mock full node
type FullNodeOpts struct {
Lite bool // run node in "lite" mode
Opts OptionGenerator // generate dependency injection options
}
// APIBuilder is a function which is invoked in test suite to provide
// test nodes and networks
//
// fullOpts array defines options for each full node
// storage array defines storage nodes, numbers in the array specify full node
// index the storage node 'belongs' to
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
type APIBuilder func(t *testing.T, full []FullNodeOpts, storage []StorageMiner) ([]TestNode, []TestStorageNode)
type testSuite struct {
makeNodes APIBuilder
}
@@ -63,13 +76,39 @@ func TestApis(t *testing.T, b APIBuilder) {
t.Run("testMiningReal", ts.testMiningReal)
}
func DefaultFullOpts(nFull int) []FullNodeOpts {
full := make([]FullNodeOpts, nFull)
for i := range full {
full[i] = FullNodeOpts{
Opts: func(nodes []TestNode) node.Option {
return node.Options()
},
}
}
return full
}
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
var OneFull = DefaultFullOpts(1)
var TwoFull = DefaultFullOpts(2)
var FullNodeWithUpgradeAt = func(upgradeHeight abi.ChainEpoch) FullNodeOpts {
return FullNodeOpts{
Opts: func(nodes []TestNode) node.Option {
return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
Network: build.ActorUpgradeNetworkVersion,
Height: upgradeHeight,
Migration: stmgr.UpgradeActorsV2,
}})
},
}
}
func (ts *testSuite) testVersion(t *testing.T) {
build.RunningNodeType = build.NodeFull
ctx := context.Background()
apis, _ := ts.makeNodes(t, 1, OneMiner)
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
api := apis[0]
v, err := api.Version(ctx)
@@ -81,7 +120,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
func (ts *testSuite) testID(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, 1, OneMiner)
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
api := apis[0]
id, err := api.ID(ctx)
@@ -93,7 +132,7 @@ func (ts *testSuite) testID(t *testing.T) {
func (ts *testSuite) testConnectTwo(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, 2, OneMiner)
apis, _ := ts.makeNodes(t, TwoFull, OneMiner)
p, err := apis[0].NetPeers(ctx)
if err != nil {
+9 -12
View File
@@ -3,6 +3,7 @@ package test
import (
"context"
"fmt"
"sync/atomic"
"os"
"strings"
@@ -15,11 +16,9 @@ import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/lotus/node"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
bminer "github.com/filecoin-project/lotus/miner"
"github.com/filecoin-project/lotus/node/impl"
@@ -33,8 +32,10 @@ func init() {
}
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
ctx := context.Background()
n, sn := b(t, 1, OneMiner)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -48,11 +49,11 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
}
build.Clock.Sleep(time.Second)
mine := true
mine := int64(1)
done := make(chan struct{})
go func() {
defer close(done)
for mine {
for atomic.LoadInt64(&mine) != 0 {
build.Clock.Sleep(blocktime)
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
@@ -64,7 +65,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
mine = false
atomic.StoreInt64(&mine, 0)
<-done
}
@@ -133,11 +134,7 @@ func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration,
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
Network: build.ActorUpgradeNetworkVersion,
Height: upgradeHeight,
Migration: stmgr.UpgradeActorsV2,
}}))
n, sn := b(t, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
+12 -2
View File
@@ -1,2 +1,12 @@
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWCYDmiVU7yXfg8MsuCAwuMmueCrjeaqduFA8gMFTWCUJk
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWKap2ouokyEu2kF56CCBsgxx3e54TGzdzcbYhxk4DtSRr
/dns4/bootstrap-0.testnet.fildev.network/tcp/1347/p2p/12D3KooWJTUBUjtzWJGWU1XSiY21CwmHaCNLNYn2E7jqHEHyZaP7
/dns4/bootstrap-1.testnet.fildev.network/tcp/1347/p2p/12D3KooW9yeKXha4hdrJKq74zEo99T8DhriQdWNoojWnnQbsgB3v
/dns4/bootstrap-2.testnet.fildev.network/tcp/1347/p2p/12D3KooWCrx8yVG9U9Kf7w8KLN3Edkj5ZKDhgCaeMqQbcQUoB6CT
/dns4/bootstrap-4.testnet.fildev.network/tcp/1347/p2p/12D3KooWPkL9LrKRQgHtq7kn9ecNhGU9QaziG8R5tX8v9v7t3h34
/dns4/bootstrap-3.testnet.fildev.network/tcp/1347/p2p/12D3KooWKYSsbpgZ3HAjax5M1BXCwXLa6gVkUARciz7uN3FNtr7T
/dns4/bootstrap-5.testnet.fildev.network/tcp/1347/p2p/12D3KooWQYzqnLASJAabyMpPb1GcWZvNSe7JDcRuhdRqonFoiK9W
/dns4/lotus-bootstrap.forceup.cn/tcp/41778/p2p/12D3KooWFQsv3nRMUevZNWWsY1Wu6NUzUbawnWU5NcRhgKuJA37C
/dns4/bootstrap-0.starpool.in/tcp/12757/p2p/12D3KooWGHpBMeZbestVEWkfdnC9u7p6uFHXL1n7m1ZBqsEmiUzz
/dns4/bootstrap-1.starpool.in/tcp/12757/p2p/12D3KooWQZrGH1PxSNZPum99M1zNvjNFM33d1AAu5DcvdHptuU7u
/dns4/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt
/dns4/bootstrap-0.ipfsmain.cn/tcp/34721/p2p/12D3KooWQnwEGNqcM2nAcPtRR9rAX8Hrg4k9kJLCHoTR5chJfz6d
/dns4/bootstrap-1.ipfsmain.cn/tcp/34723/p2p/12D3KooWMKxMkD5DMpSWsW7dBddKxKT7L2GgbNuckz9otxvkvByP
Binary file not shown.
+13 -2
View File
@@ -3,6 +3,9 @@
package build
import (
"math"
"os"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/policy"
@@ -13,8 +16,11 @@ const BreezeGasTampingDuration = 0
const UpgradeSmokeHeight = -1
const UpgradeIgnitionHeight = -2
const UpgradeLiftoffHeight = -3
const UpgradeActorsV2Height = 10
const UpgradeRefuelHeight = -3
const UpgradeTapeHeight = -4
var UpgradeActorsV2Height = abi.ChainEpoch(10)
var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
@@ -25,6 +31,11 @@ func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
UpgradeActorsV2Height = math.MaxInt64
UpgradeLiftoffHeight = 11
}
BuildType |= Build2k
}
+1 -1
View File
@@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024
// Consensus / Network
const AllowableClockDriftSecs = uint64(1)
const NewestNetworkVersion = network.Version4
const NewestNetworkVersion = network.Version5
const ActorUpgradeNetworkVersion = network.Version4
// Epochs
+4 -2
View File
@@ -82,14 +82,16 @@ var (
UpgradeSmokeHeight abi.ChainEpoch = -1
UpgradeIgnitionHeight abi.ChainEpoch = -2
UpgradeLiftoffHeight abi.ChainEpoch = -3
UpgradeRefuelHeight abi.ChainEpoch = -3
UpgradeTapeHeight abi.ChainEpoch = -4
UpgradeActorsV2Height abi.ChainEpoch = 10
UpgradeLiftoffHeight abi.ChainEpoch = -5
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
}
NewestNetworkVersion = network.Version4
NewestNetworkVersion = network.Version5
ActorUpgradeNetworkVersion = network.Version4
Devnet = true
+20 -8
View File
@@ -5,6 +5,9 @@
package build
import (
"math"
"os"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/chain/actors/policy"
@@ -13,17 +16,21 @@ import (
)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
0: DrandIncentinet,
UpgradeSmokeHeight: DrandMainnet,
}
const UpgradeBreezeHeight = -1
const UpgradeBreezeHeight = 41280
const BreezeGasTampingDuration = 120
const UpgradeSmokeHeight = -2
const UpgradeSmokeHeight = 51000
const UpgradeIgnitionHeight = -3
const UpgradeIgnitionHeight = 94000
const UpgradeRefuelHeight = 130800
const UpgradeActorsV2Height = 500
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
const UpgradeTapeHeight = 140760
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
// Miners, clients, developers, custodians all need time to prepare.
@@ -31,14 +38,19 @@ const UpgradeActorsV2Height = 500
const UpgradeLiftoffHeight = 148888
func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(1 << 30))
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40))
policy.SetSupportedProofTypes(
abi.RegisteredSealProof_StackedDrg512MiBV1,
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
)
SetAddressNetwork(address.Testnet)
if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" {
SetAddressNetwork(address.Mainnet)
}
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
UpgradeActorsV2Height = math.MaxInt64
}
Devnet = false
}
+1 -1
View File
@@ -29,7 +29,7 @@ func buildType() string {
}
// BuildVersion is the local build version, set by build system
const BuildVersion = "0.8.1"
const BuildVersion = "0.10.0"
func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit
+1
View File
@@ -22,6 +22,7 @@ import (
var SystemActorAddr = builtin0.SystemActorAddr
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
var ReserveAddress = makeAddress("t090")
var RootVerifierAddress = makeAddress("t080")
// TODO: Why does actors have 2 different versions of this?
type SectorInfo = proof0.SectorInfo
@@ -0,0 +1,180 @@
package miner
import (
"errors"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/exitcode"
)
type DeadlinesDiff map[uint64]*DeadlineDiff
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
changed, err := pre.DeadlinesChanged(cur)
if err != nil {
return nil, err
}
if !changed {
return nil, nil
}
numDl, err := pre.NumDeadlines()
if err != nil {
return nil, err
}
dlDiff := make(DeadlinesDiff, numDl)
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
curDl, err := cur.LoadDeadline(idx)
if err != nil {
return err
}
diff, err := DiffDeadline(preDl, curDl)
if err != nil {
return err
}
dlDiff[idx] = diff
return nil
}); err != nil {
return nil, err
}
return &dlDiff, nil
}
type DeadlineDiff map[uint64]*PartitionDiff
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
changed, err := pre.PartitionsChanged(cur)
if err != nil {
return nil, err
}
if !changed {
return nil, nil
}
partDiff := make(DeadlineDiff)
if err := pre.ForEachPartition(func(idx uint64, prePart Partition) error {
// try loading current partition at this index
curPart, err := cur.LoadPartition(idx)
if err != nil {
if errors.Is(err, exitcode.ErrNotFound) {
// TODO correctness?
return nil // the partition was removed.
}
return err
}
// compare it with the previous partition
diff, err := DiffPartition(prePart, curPart)
if err != nil {
return err
}
partDiff[idx] = diff
return nil
}); err != nil {
return nil, err
}
// all previous partitions have been walked.
// all partitions in cur and not in prev are new... can they be faulty already?
// TODO is this correct?
if err := cur.ForEachPartition(func(idx uint64, curPart Partition) error {
if _, found := partDiff[idx]; found {
return nil
}
faults, err := curPart.FaultySectors()
if err != nil {
return err
}
recovering, err := curPart.RecoveringSectors()
if err != nil {
return err
}
partDiff[idx] = &PartitionDiff{
Removed: bitfield.New(),
Recovered: bitfield.New(),
Faulted: faults,
Recovering: recovering,
}
return nil
}); err != nil {
return nil, err
}
return &partDiff, nil
}
type PartitionDiff struct {
Removed bitfield.BitField
Recovered bitfield.BitField
Faulted bitfield.BitField
Recovering bitfield.BitField
}
func DiffPartition(pre, cur Partition) (*PartitionDiff, error) {
prevLiveSectors, err := pre.LiveSectors()
if err != nil {
return nil, err
}
curLiveSectors, err := cur.LiveSectors()
if err != nil {
return nil, err
}
removed, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
if err != nil {
return nil, err
}
prevRecoveries, err := pre.RecoveringSectors()
if err != nil {
return nil, err
}
curRecoveries, err := cur.RecoveringSectors()
if err != nil {
return nil, err
}
recovering, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
if err != nil {
return nil, err
}
prevFaults, err := pre.FaultySectors()
if err != nil {
return nil, err
}
curFaults, err := cur.FaultySectors()
if err != nil {
return nil, err
}
faulted, err := bitfield.SubtractBitField(curFaults, prevFaults)
if err != nil {
return nil, err
}
// all current good sectors
curActiveSectors, err := cur.ActiveSectors()
if err != nil {
return nil, err
}
// sectors that were previously fault and are now currently active are considered recovered.
recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
if err != nil {
return nil, err
}
return &PartitionDiff{
Removed: removed,
Recovered: recovered,
Faulted: faulted,
Recovering: recovering,
}, nil
}
+1
View File
@@ -51,6 +51,7 @@ type State interface {
MinerPower(address.Address) (Claim, bool, error)
MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error)
ListAllMiners() ([]address.Address, error)
ForEachClaim(func(miner address.Address, claim Claim) error) error
}
type Claim struct {
+19
View File
@@ -96,3 +96,22 @@ func (s *state0) ListAllMiners() ([]address.Address, error) {
return miners, nil
}
func (s *state0) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
claims, err := adt0.AsMap(s.store, s.Claims)
if err != nil {
return err
}
var claim power0.Claim
return claims.ForEach(&claim, func(k string) error {
a, err := address.NewFromBytes([]byte(k))
if err != nil {
return err
}
return cb(a, Claim{
RawBytePower: claim.RawBytePower,
QualityAdjPower: claim.QualityAdjPower,
})
})
}
+19
View File
@@ -96,3 +96,22 @@ func (s *state2) ListAllMiners() ([]address.Address, error) {
return miners, nil
}
func (s *state2) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
claims, err := adt2.AsMap(s.store, s.Claims)
if err != nil {
return err
}
var claim power2.Claim
return claims.ForEach(&claim, func(k string) error {
a, err := address.NewFromBytes([]byte(k))
if err != nil {
return err
}
return cb(a, Claim{
RawBytePower: claim.RawBytePower,
QualityAdjPower: claim.QualityAdjPower,
})
})
}
+1 -1
View File
@@ -57,7 +57,7 @@ func (s *state0) CumsumBaseline() (abi.StoragePower, error) {
}
func (s *state0) CumsumRealized() (abi.StoragePower, error) {
return s.State.CumsumBaseline, nil
return s.State.CumsumRealized, nil
}
func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
+1 -1
View File
@@ -60,7 +60,7 @@ func (s *state2) CumsumBaseline() (abi.StoragePower, error) {
}
func (s *state2) CumsumRealized() (abi.StoragePower, error) {
return s.State.CumsumBaseline, nil
return s.State.CumsumRealized, nil
}
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
+3 -3
View File
@@ -9,8 +9,8 @@ import (
type Version int
const (
Version0 = 0
Version2 = 2
Version0 Version = 0
Version2 Version = 2
)
// Converts a network version into an actors adt version.
@@ -18,7 +18,7 @@ func VersionForNetwork(version network.Version) Version {
switch version {
case network.Version0, network.Version1, network.Version2, network.Version3:
return Version0
case network.Version4:
case network.Version4, network.Version5:
return Version2
default:
panic(fmt.Sprintf("unsupported network version %d", version))
+4
View File
@@ -60,6 +60,10 @@ func (bts *BadBlockCache) Remove(c cid.Cid) {
bts.badBlocks.Remove(c)
}
func (bts *BadBlockCache) Purge() {
bts.badBlocks.Purge()
}
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
rval, ok := bts.badBlocks.Get(c)
if !ok {
+24 -2
View File
@@ -2,6 +2,7 @@ package events
import (
"context"
"sync"
"github.com/filecoin-project/go-state-types/abi"
"golang.org/x/xerrors"
@@ -17,6 +18,8 @@ type tsCacheAPI interface {
// tipSetCache implements a simple ring-buffer cache to keep track of recent
// tipsets
type tipSetCache struct {
mu sync.RWMutex
cache []*types.TipSet
start int
len int
@@ -35,6 +38,9 @@ func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache {
}
func (tsc *tipSetCache) add(ts *types.TipSet) error {
tsc.mu.Lock()
defer tsc.mu.Unlock()
if tsc.len > 0 {
if tsc.cache[tsc.start].Height() >= ts.Height() {
return xerrors.Errorf("tipSetCache.add: expected new tipset height to be at least %d, was %d", tsc.cache[tsc.start].Height()+1, ts.Height())
@@ -65,6 +71,13 @@ func (tsc *tipSetCache) add(ts *types.TipSet) error {
}
func (tsc *tipSetCache) revert(ts *types.TipSet) error {
tsc.mu.Lock()
defer tsc.mu.Unlock()
return tsc.revertUnlocked(ts)
}
func (tsc *tipSetCache) revertUnlocked(ts *types.TipSet) error {
if tsc.len == 0 {
return nil // this can happen, and it's fine
}
@@ -77,7 +90,7 @@ func (tsc *tipSetCache) revert(ts *types.TipSet) error {
tsc.start = normalModulo(tsc.start-1, len(tsc.cache))
tsc.len--
_ = tsc.revert(nil) // revert null block gap
_ = tsc.revertUnlocked(nil) // revert null block gap
return nil
}
@@ -95,7 +108,10 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error)
}
func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
tsc.mu.RLock()
if tsc.len == 0 {
tsc.mu.RUnlock()
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK)
}
@@ -103,6 +119,7 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
headH := tsc.cache[tsc.start].Height()
if height > headH {
tsc.mu.RUnlock()
return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache head: %d)", height, headH)
}
@@ -116,15 +133,20 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
}
if height < tail.Height() {
tsc.mu.RUnlock()
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key())
}
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
ts := tsc.cache[normalModulo(tsc.start-int(headH-height), clen)]
tsc.mu.RUnlock()
return ts, nil
}
func (tsc *tipSetCache) best() (*types.TipSet, error) {
tsc.mu.RLock()
best := tsc.cache[tsc.start]
tsc.mu.RUnlock()
if best == nil {
return tsc.storage.ChainHead(context.TODO())
}
+24 -12
View File
@@ -39,6 +39,7 @@ import (
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/journal"
"github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/node/repo"
@@ -71,7 +72,7 @@ type ChainGen struct {
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
w *wallet.Wallet
w *wallet.LocalWallet
eppProvs map[address.Address]WinningPoStProver
Miners []address.Address
@@ -122,6 +123,7 @@ var DefaultRemainderAccountActor = genesis.Actor{
}
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
j := journal.NilJournal()
// TODO: we really shouldn't modify a global variable here.
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
@@ -153,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
}
banker, err := w.GenerateKey(crypto.SigTypeSecp256k1)
banker, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
}
receievers := make([]address.Address, msgsPerBlock)
for r := range receievers {
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS)
receievers[r], err = w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
}
@@ -190,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, err
}
mk1, err := w.Import(k1)
mk1, err := w.WalletImport(context.Background(), k1)
if err != nil {
return nil, err
}
mk2, err := w.Import(k2)
mk2, err := w.WalletImport(context.Background(), k2)
if err != nil {
return nil, err
}
@@ -229,12 +231,12 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
}
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
genb, err := genesis2.MakeGenesisBlock(context.TODO(), j, bs, sys, tpl)
if err != nil {
return nil, xerrors.Errorf("make genesis block failed: %w", err)
}
cs := store.NewChainStore(bs, ds, sys)
cs := store.NewChainStore(bs, ds, sys, j)
genfb := &types.FullBlock{Header: genb.Genesis}
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
@@ -374,7 +376,13 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
return nil, nil, nil, xerrors.Errorf("get miner worker: %w", err)
}
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand)
sf := func(ctx context.Context, a address.Address, i []byte) (*crypto.Signature, error) {
return cg.w.WalletSign(ctx, a, i, api.MsgMeta{
Type: api.MTUnknown,
})
}
vrfout, err := ComputeVRF(ctx, sf, worker, ticketRand)
if err != nil {
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
}
@@ -506,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address {
return cg.banker
}
func (cg *ChainGen) Wallet() *wallet.Wallet {
func (cg *ChainGen) Wallet() *wallet.LocalWallet {
return cg.w
}
@@ -528,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
GasPremium: types.NewInt(0),
}
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
sig, err := cg.w.WalletSign(context.TODO(), cg.banker, msg.Cid().Bytes(), api.MsgMeta{
Type: api.MTUnknown, // testing
})
if err != nil {
return nil, err
}
@@ -559,7 +569,7 @@ type MiningCheckAPI interface {
}
type mca struct {
w *wallet.Wallet
w *wallet.LocalWallet
sm *stmgr.StateManager
pv ffiwrapper.Verifier
bcn beacon.Schedule
@@ -588,7 +598,9 @@ func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoc
}
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) {
return mca.w.Sign(ctx, a, v)
return mca.w.WalletSign(ctx, a, v, api.MsgMeta{
Type: api.MTUnknown,
})
}
type WinningPoStProver interface {
+7 -4
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/journal"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
@@ -26,7 +27,6 @@ import (
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
@@ -117,7 +117,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
}
state, err := state.NewStateTree(cst, actors.Version0)
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
if err != nil {
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
}
@@ -467,7 +467,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
return st, nil
}
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
if j == nil {
j = journal.NilJournal()
}
st, keyIDs, err := MakeInitialStateTree(ctx, bs, template)
if err != nil {
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
@@ -479,7 +482,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
}
// temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys, j)
// Verify PreSealed Data
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
+4 -3
View File
@@ -15,11 +15,10 @@ import (
"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/chain/wallet"
"github.com/filecoin-project/lotus/lib/sigs/bls"
)
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.WalletAPI, bt *api.BlockTemplate) (*types.FullBlock, error) {
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
if err != nil {
@@ -131,7 +130,9 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
}
sig, err := w.Sign(ctx, waddr, nosigbytes)
sig, err := w.WalletSign(ctx, waddr, nosigbytes, api.MsgMeta{
Type: api.MTBlock,
})
if err != nil {
return nil, xerrors.Errorf("failed to sign new block: %w", err)
}
+4 -2
View File
@@ -120,9 +120,10 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
return cid.Undef, err
}
fm.lk.Lock()
defer fm.lk.Unlock()
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
if err != nil {
fm.lk.Unlock()
return cid.Undef, err
}
@@ -138,7 +139,6 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
toAdd = types.NewInt(0)
}
fm.available[idAddr] = big.Add(avail, toAdd)
fm.lk.Unlock()
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
@@ -148,6 +148,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
params, err := actors.SerializeParams(&addr)
if err != nil {
fm.available[idAddr] = avail
return cid.Undef, err
}
@@ -159,6 +160,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
Params: params,
}, nil)
if err != nil {
fm.available[idAddr] = avail
return cid.Undef, err
}
+24 -14
View File
@@ -57,9 +57,10 @@ func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Add
}
type expectedResult struct {
addAmt abi.TokenAmount
shouldAdd bool
err error
addAmt abi.TokenAmount
shouldAdd bool
err error
cachedAvailable abi.TokenAmount
}
func TestAddFunds(t *testing.T) {
@@ -88,8 +89,9 @@ func TestAddFunds(t *testing.T) {
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
expectedResults: []expectedResult{
{
shouldAdd: false,
err: nil,
shouldAdd: false,
err: nil,
cachedAvailable: abi.NewTokenAmount(100),
},
},
},
@@ -102,18 +104,21 @@ func TestAddFunds(t *testing.T) {
err: nil,
},
{
addAmt: abi.NewTokenAmount(100),
shouldAdd: true,
err: nil,
addAmt: abi.NewTokenAmount(100),
shouldAdd: true,
err: nil,
cachedAvailable: abi.NewTokenAmount(200),
},
{
addAmt: abi.NewTokenAmount(50),
shouldAdd: true,
err: nil,
addAmt: abi.NewTokenAmount(50),
shouldAdd: true,
err: nil,
cachedAvailable: abi.NewTokenAmount(250),
},
{
shouldAdd: false,
err: nil,
shouldAdd: false,
err: nil,
cachedAvailable: abi.NewTokenAmount(250),
},
},
},
@@ -132,7 +137,8 @@ func TestAddFunds(t *testing.T) {
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
expectedResults: []expectedResult{
{
err: errors.New("something went wrong"),
err: errors.New("something went wrong"),
cachedAvailable: abi.NewTokenAmount(0),
},
},
},
@@ -183,6 +189,10 @@ func TestAddFunds(t *testing.T) {
} else {
require.EqualError(t, err, expected.err.Error())
}
if !expected.cachedAvailable.Nil() {
require.Equal(t, expected.cachedAvailable, fundMgr.available[addr])
}
}
})
}
+12 -6
View File
@@ -159,6 +159,7 @@ type MessagePool struct {
sigValCache *lru.TwoQueueCache
evtTypes [3]journal.EventType
journal journal.Journal
}
type msgSet struct {
@@ -316,7 +317,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
return types.BigInt{Int: requiredFunds}
}
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journal.Journal) (*MessagePool, error) {
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
@@ -325,6 +326,10 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
return nil, xerrors.Errorf("error loading mpool config: %w", err)
}
if j == nil {
j = journal.NilJournal()
}
mp := &MessagePool{
ds: ds,
addSema: make(chan struct{}, 1),
@@ -344,10 +349,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
netName: netName,
cfg: cfg,
evtTypes: [...]journal.EventType{
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"),
evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"),
evtTypeMpoolRepub: j.RegisterEventType("mpool", "repub"),
},
journal: j,
}
// enable initial prunes
@@ -744,7 +750,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict, untrusted bool)
Message: m,
}, localUpdates)
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
return MessagePoolEvt{
Action: "add",
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
@@ -865,7 +871,7 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
Message: m,
}, localUpdates)
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
return MessagePoolEvt{
Action: "remove",
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
+21 -21
View File
@@ -225,14 +225,14 @@ func TestMessagePool(t *testing.T) {
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
a := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
t.Fatal(err)
}
@@ -266,14 +266,14 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
a := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
t.Fatal(err)
}
@@ -315,7 +315,7 @@ func TestRevertMessages(t *testing.T) {
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -323,7 +323,7 @@ func TestRevertMessages(t *testing.T) {
a := tma.nextBlock()
b := tma.nextBlock()
sender, err := w.GenerateKey(crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
t.Fatal(err)
}
@@ -378,7 +378,7 @@ func TestPruningSimple(t *testing.T) {
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -386,7 +386,7 @@ func TestPruningSimple(t *testing.T) {
a := tma.nextBlock()
tma.applyBlock(t, a)
sender, err := w.GenerateKey(crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
t.Fatal(err)
}
@@ -422,7 +422,7 @@ func TestLoadLocal(t *testing.T) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -433,7 +433,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -443,7 +443,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -465,7 +465,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err)
}
mp, err = New(tma, ds, "mptest")
mp, err = New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -494,7 +494,7 @@ func TestClearAll(t *testing.T) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -505,7 +505,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -515,7 +515,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -548,7 +548,7 @@ func TestClearNonLocal(t *testing.T) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -559,7 +559,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -569,7 +569,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -609,7 +609,7 @@ func TestUpdates(t *testing.T) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -620,7 +620,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -630,7 +630,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
+4 -5
View File
@@ -11,7 +11,6 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/journal"
"github.com/ipfs/go-cid"
)
@@ -148,14 +147,14 @@ loop:
}
if len(msgs) > 0 {
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
msgsEv := make([]MessagePoolEvtMessage, 0, len(msgs))
for _, m := range msgs {
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
msgsEv = append(msgsEv, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
}
return MessagePoolEvt{
Action: "repub",
Messages: msgs,
Messages: msgsEv,
}
})
}
+4 -3
View File
@@ -1,6 +1,7 @@
package messagepool
import (
"context"
"testing"
"time"
@@ -21,7 +22,7 @@ func TestRepubMessages(t *testing.T) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "mptest")
mp, err := New(tma, ds, "mptest", nil)
if err != nil {
t.Fatal(err)
}
@@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
+33 -31
View File
@@ -13,6 +13,10 @@ import (
"sort"
"testing"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/build"
@@ -21,12 +25,10 @@ import (
"github.com/filecoin-project/lotus/chain/types/mock"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/filecoin-project/lotus/api"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
logging "github.com/ipfs/go-log"
)
func init() {
@@ -34,7 +36,7 @@ func init() {
MaxActorPendingMessages = 1000000
}
func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
func makeTestMessage(w *wallet.LocalWallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
msg := &types.Message{
From: from,
To: to,
@@ -45,7 +47,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
GasFeeCap: types.NewInt(100 + gasPrice),
GasPremium: types.NewInt(gasPrice),
}
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
if err != nil {
panic(err)
}
@@ -58,7 +60,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
tma := newTestMpoolAPI()
ds := datastore.NewMapDatastore()
mp, err := New(tma, ds, "test")
mp, err := New(tma, ds, "test", nil)
if err != nil {
panic(err)
}
@@ -75,7 +77,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -85,7 +87,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -313,7 +315,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -323,7 +325,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -389,7 +391,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -399,7 +401,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -533,7 +535,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -543,7 +545,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -596,7 +598,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -606,7 +608,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -675,7 +677,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -685,7 +687,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -744,7 +746,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -754,7 +756,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -841,7 +843,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -851,7 +853,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -908,7 +910,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -918,7 +920,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -984,7 +986,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
nActors := 10
// the actors
var actors []address.Address
var wallets []*wallet.Wallet
var wallets []*wallet.LocalWallet
for i := 0; i < nActors; i++ {
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
@@ -992,7 +994,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -1064,7 +1066,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
nActors := 300
// the actors
var actors []address.Address
var wallets []*wallet.Wallet
var wallets []*wallet.LocalWallet
for i := 0; i < nActors; i++ {
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
@@ -1072,7 +1074,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
t.Fatal(err)
}
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -1330,7 +1332,7 @@ readLoop:
}
actorMap := make(map[address.Address]address.Address)
actorWallets := make(map[address.Address]*wallet.Wallet)
actorWallets := make(map[address.Address]api.WalletAPI)
for _, m := range msgs {
baseNonce := baseNonces[m.Message.From]
@@ -1342,7 +1344,7 @@ readLoop:
t.Fatal(err)
}
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -1360,7 +1362,7 @@ readLoop:
m.Message.From = localActor
m.Message.Nonce -= baseNonce
sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes())
sig, err := w.WalletSign(context.TODO(), localActor, m.Message.Cid().Bytes(), api.MsgMeta{})
if err != nil {
t.Fatal(err)
}
+20 -14
View File
@@ -5,40 +5,37 @@ import (
"context"
"sync"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
logging "github.com/ipfs/go-log/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
const dsKeyActorNonce = "ActorNextNonce"
var log = logging.Logger("messagesigner")
type mpoolAPI interface {
type MpoolNonceAPI interface {
GetNonce(address.Address) (uint64, error)
}
// MessageSigner keeps track of nonces per address, and increments the nonce
// when signing a message
type MessageSigner struct {
wallet *wallet.Wallet
wallet api.WalletAPI
lk sync.Mutex
mpool mpoolAPI
mpool MpoolNonceAPI
ds datastore.Batching
}
func NewMessageSigner(wallet *wallet.Wallet, mpool *messagepool.MessagePool, ds dtypes.MetadataDS) *MessageSigner {
return newMessageSigner(wallet, mpool, ds)
}
func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataDS) *MessageSigner {
func NewMessageSigner(wallet api.WalletAPI, mpool MpoolNonceAPI, ds dtypes.MetadataDS) *MessageSigner {
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
return &MessageSigner{
wallet: wallet,
@@ -61,7 +58,16 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb
// Sign the message with the nonce
msg.Nonce = nonce
sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes())
mb, err := msg.ToStorageBlock()
if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err)
}
sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{
Type: api.MTChainMsg,
Extra: mb.RawData(),
})
if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w", err)
}
+5 -5
View File
@@ -47,13 +47,13 @@ func TestMessageSignerSignMessage(t *testing.T) {
ctx := context.Background()
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
from1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
from1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err)
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
from2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err)
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
to1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err)
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
to2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
require.NoError(t, err)
type msgSpec struct {
@@ -177,7 +177,7 @@ func TestMessageSignerSignMessage(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
mpool := newMockMpool()
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
ms := newMessageSigner(w, mpool, ds)
ms := NewMessageSigner(w, mpool, ds)
for _, m := range tt.msgs {
if len(m.mpoolNonce) == 1 {
+40 -16
View File
@@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/actors"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
cbg "github.com/whyrusleeping/cbor-gen"
@@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
// StateTree stores actors state by their ID.
type StateTree struct {
root adt.Map
version actors.Version // TODO
version types.StateTreeVersion
info cid.Cid
Store cbor.IpldStore
@@ -120,21 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
}
func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error) {
// VersionForNetwork returns the state tree version for the given network
// version.
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
if actors.VersionForNetwork(ver) == actors.Version0 {
return types.StateTreeVersion0
}
return types.StateTreeVersion1
}
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
switch ver {
case types.StateTreeVersion0:
return actors.Version0
case types.StateTreeVersion1:
return actors.Version2
default:
panic("unhandled state tree version")
}
}
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
var info cid.Cid
switch version {
case actors.Version0:
switch ver {
case types.StateTreeVersion0:
// info is undefined
case actors.Version2:
case types.StateTreeVersion1:
var err error
info, err = cst.Put(context.TODO(), new(types.StateInfo))
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
if err != nil {
return nil, err
}
default:
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
}
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
if err != nil {
return nil, err
}
@@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
return &StateTree{
root: root,
info: info,
version: version,
version: ver,
Store: cst,
snaps: newStateSnaps(),
}, nil
@@ -154,13 +175,16 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
if err := cst.Get(context.TODO(), c, &root); err != nil {
// We failed to decode as the new version, must be an old version.
root.Actors = c
root.Version = actors.Version0
root.Version = types.StateTreeVersion0
}
switch root.Version {
case actors.Version0, actors.Version2:
case types.StateTreeVersion0, types.StateTreeVersion1:
// Load the actual state-tree HAMT.
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
nd, err := adt.AsMap(
adt.WrapStore(context.TODO(), cst), root.Actors,
adtForSTVersion(root.Version),
)
if err != nil {
log.Errorf("loading hamt node %s failed: %s", c, err)
return nil, err
@@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
return &StateTree{
root: nd,
info: root.Info,
version: actors.Version(root.Version),
version: root.Version,
Store: cst,
snaps: newStateSnaps(),
}, nil
@@ -309,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
}
// If we're version 0, return a raw tree.
if st.version == actors.Version0 {
if st.version == types.StateTreeVersion0 {
return root, nil
}
// Otherwise, return a versioned tree.
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
}
func (st *StateTree) Snapshot(ctx context.Context) error {
@@ -400,7 +424,7 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
}
// Version returns the version of the StateTree data structure in use.
func (st *StateTree) Version() actors.Version {
func (st *StateTree) Version() types.StateTreeVersion {
return st.version
}
+6 -7
View File
@@ -13,13 +13,12 @@ import (
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
)
func BenchmarkStateTreeSet(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
func BenchmarkStateTreeSetFlush(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
func BenchmarkStateTree10kGetActor(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
b.Fatal(err)
}
@@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
func TestSetCache(t *testing.T) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
func TestSnapshots(t *testing.T) {
ctx := context.Background()
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
@@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
func TestStateTreeConsistency(t *testing.T) {
cst := cbor.NewMemCborStore()
// TODO: ActorUpgrade: this test tests pre actors v2
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
if err != nil {
t.Fatal(err)
}
+42 -2
View File
@@ -2,6 +2,7 @@ package stmgr
import (
"context"
"errors"
"fmt"
"github.com/filecoin-project/go-address"
@@ -17,17 +18,38 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
)
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
defer span.End()
// If no tipset is provided, try to find one without a fork.
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
// Search back till we find a height with no fork, or we reach the beginning.
for ts.Height() > 0 && sm.hasExpensiveFork(ctx, ts.Height()-1) {
var err error
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
}
}
}
bstate := ts.ParentState()
bheight := ts.Height()
// If we have to run an expensive migration, and we're not at genesis,
// return an error because the migration will take too long.
//
// We allow this at height 0 for at-genesis migrations (for testing).
if bheight-1 > 0 && sm.hasExpensiveFork(ctx, bheight-1) {
return nil, ErrExpensiveFork
}
// Run the (not expensive) migration.
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
if err != nil {
return nil, fmt.Errorf("failed to handle fork: %w", err)
@@ -44,7 +66,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
BaseFee: types.NewInt(0),
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
@@ -106,6 +128,24 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
// Search back till we find a height with no fork, or we reach the beginning.
// We need the _previous_ height to have no fork, because we'll
// run the fork logic in `sm.TipSetState`. We need the _current_
// height to have no fork, because we'll run it inside this
// function before executing the given message.
for ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
var err error
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
}
}
}
// When we're not at the genesis block, make sure we don't have an expensive migration.
if ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
return nil, ErrExpensiveFork
}
state, _, err := sm.TipSetState(ctx, ts)
@@ -138,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
+135 -30
View File
@@ -6,6 +6,8 @@ import (
"encoding/binary"
"math"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
@@ -22,23 +24,32 @@ import (
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/adt"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
bstore "github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/lotus/lib/bufbstore"
)
type UpgradeFunc func(context.Context, *StateManager, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error)
// UpgradeFunc is a migration function run at every upgrade.
//
// - The oldState is the state produced by the upgrade epoch.
// - The returned newState is the new state that will be used by the next epoch.
// - The height is the upgrade epoch height (already executed).
// - The tipset is the tipset for the last non-null block before the upgrade. Do
// not assume that ts.Height() is the upgrade height.
type UpgradeFunc func(ctx context.Context, sm *StateManager, cb ExecCallback, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error)
type Upgrade struct {
Height abi.ChainEpoch
Network network.Version
Expensive bool
Migration UpgradeFunc
}
@@ -47,7 +58,7 @@ type UpgradeSchedule []Upgrade
func DefaultUpgradeSchedule() UpgradeSchedule {
var us UpgradeSchedule
for _, u := range []Upgrade{{
updates := []Upgrade{{
Height: build.UpgradeBreezeHeight,
Network: network.Version1,
Migration: UpgradeFaucetBurnRecovery,
@@ -59,15 +70,49 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
Height: build.UpgradeIgnitionHeight,
Network: network.Version3,
Migration: UpgradeIgnition,
}, {
Height: build.UpgradeRefuelHeight,
Network: network.Version3,
Migration: UpgradeRefuel,
}, {
Height: build.UpgradeActorsV2Height,
Network: network.Version4,
Expensive: true,
Migration: UpgradeActorsV2,
}, {
Height: build.UpgradeTapeHeight,
Network: network.Version5,
}, {
Height: build.UpgradeLiftoffHeight,
Network: network.Version4,
Network: network.Version5,
Migration: UpgradeLiftoff,
}} {
}}
if build.UpgradeActorsV2Height == math.MaxInt64 { // disable actors upgrade
updates = []Upgrade{{
Height: build.UpgradeBreezeHeight,
Network: network.Version1,
Migration: UpgradeFaucetBurnRecovery,
}, {
Height: build.UpgradeSmokeHeight,
Network: network.Version2,
Migration: nil,
}, {
Height: build.UpgradeIgnitionHeight,
Network: network.Version3,
Migration: UpgradeIgnition,
}, {
Height: build.UpgradeRefuelHeight,
Network: network.Version3,
Migration: UpgradeRefuel,
}, {
Height: build.UpgradeLiftoffHeight,
Network: network.Version3,
Migration: UpgradeLiftoff,
}}
}
for _, u := range updates {
if u.Height < 0 {
// upgrade disabled
continue
@@ -109,7 +154,7 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
var err error
f, ok := sm.stateMigrations[height]
if ok {
retCid, err = f(ctx, sm, cb, root, ts)
retCid, err = f(ctx, sm, cb, root, height, ts)
if err != nil {
return cid.Undef, err
}
@@ -118,6 +163,11 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
return retCid, nil
}
func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEpoch) bool {
_, ok := sm.expensiveUpgrades[height]
return ok
}
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
fromAct, err := tree.GetActor(from)
if err != nil {
@@ -180,7 +230,7 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
return nil
}
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
// Some initial parameters
FundsForMiners := types.FromFil(1_000_000)
LookbackEpoch := abi.ChainEpoch(32000)
@@ -432,11 +482,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
return tree.Flush(ctx)
}
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
store := sm.cs.Store(ctx)
epoch := ts.Height() - 1
if build.UpgradeLiftoffHeight <= epoch {
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
}
@@ -489,12 +537,42 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return tree.Flush(ctx)
}
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
store := sm.cs.Store(ctx)
tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
}
epoch := ts.Height() - 1
addr, err := address.NewFromString("t0122")
if err != nil {
return cid.Undef, xerrors.Errorf("getting address: %w", err)
}
info, err := store.Put(ctx, new(types.StateInfo))
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
err = resetMultisigVesting(ctx, store, tree, builtin.ReserveAddress, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
err = resetMultisigVesting(ctx, store, tree, builtin.RootVerifierAddress, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
return tree.Flush(ctx)
}
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
buf := bufbstore.NewTieredBstore(sm.cs.Blockstore(), bstore.NewTemporarySync())
store := store.ActorStore(ctx, buf)
info, err := store.Put(ctx, new(types.StateInfo0))
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
}
@@ -504,22 +582,8 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err)
}
newStateTree, err := states2.LoadTree(store, newHamtRoot)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to load new state tree: %w", err)
}
// Check all state-tree invariants.
if msgs, err := states2.CheckStateInvariants(newStateTree, types.TotalFilecoinInt); err != nil {
return cid.Undef, xerrors.Errorf("failed to check new state tree: %w", err)
} else if !msgs.IsEmpty() {
// This error is going to be really nasty.
return cid.Undef, xerrors.Errorf("network upgrade failed: %v", msgs.Messages())
}
newRoot, err := store.Put(ctx, &types.StateRoot{
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
Version: actors.Version2,
Version: types.StateTreeVersion1,
Actors: newHamtRoot,
Info: info,
})
@@ -538,10 +602,19 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
}
{
from := buf
to := buf.Read()
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
}
}
return newRoot, nil
}
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
@@ -699,6 +772,7 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
return addr, nil
}
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) error {
gb, err := sm.cs.GetGenesis()
if err != nil {
@@ -748,3 +822,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
return nil
}
func resetMultisigVesting(ctx context.Context, store adt0.Store, tree *state.StateTree, addr address.Address, startEpoch abi.ChainEpoch, duration abi.ChainEpoch, balance abi.TokenAmount) error {
act, err := tree.GetActor(addr)
if err != nil {
return xerrors.Errorf("getting actor: %w", err)
}
if !builtin.IsMultisigActor(act.Code) {
return xerrors.Errorf("actor wasn't msig: %w", err)
}
var msigState multisig0.State
if err := store.Get(ctx, act.Head, &msigState); err != nil {
return xerrors.Errorf("reading multisig state: %w", err)
}
msigState.StartEpoch = startEpoch
msigState.UnlockDuration = duration
msigState.InitialBalance = balance
act.Head, err = store.Put(ctx, &msigState)
if err != nil {
return xerrors.Errorf("writing new multisig state: %w", err)
}
if err := tree.SetActor(addr, act); err != nil {
return xerrors.Errorf("setting multisig actor: %w", err)
}
return nil
}
+95 -12
View File
@@ -6,14 +6,21 @@ import (
"io"
"testing"
"github.com/ipfs/go-cid"
ipldcbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log"
"github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/runtime"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
@@ -24,11 +31,6 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/ipfs/go-cid"
ipldcbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log"
cbg "github.com/whyrusleeping/cbor-gen"
)
func init() {
@@ -76,7 +78,7 @@ func (ta testActor) Exports() []interface{} {
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
rt.ValidateImmediateCallerAcceptAny()
rt.StateCreate(&testActorState{11})
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
return abi.Empty
}
@@ -120,7 +122,7 @@ func TestForkHeightTriggers(t *testing.T) {
Network: 1,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
st, err := sm.StateTree(root)
@@ -173,7 +175,7 @@ func TestForkHeightTriggers(t *testing.T) {
var msgs []*types.SignedMessage
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()})
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
if err != nil {
t.Fatal(err)
}
@@ -185,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) {
Params: enc,
GasLimit: types.TestGasLimit,
}
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
if err != nil {
t.Fatal(err)
}
@@ -213,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) {
}
nonce++
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
if err != nil {
return nil, err
}
@@ -233,3 +235,84 @@ func TestForkHeightTriggers(t *testing.T) {
}
}
}
func TestForkRefuseCall(t *testing.T) {
logging.SetAllLoggers(logging.LevelInfo)
ctx := context.TODO()
cg, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
}
sm, err := NewStateManagerWithUpgradeSchedule(
cg.ChainStore(), UpgradeSchedule{{
Network: 1,
Expensive: true,
Height: testForkHeight,
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
return root, nil
}}})
if err != nil {
t.Fatal(err)
}
inv := vm.NewActorRegistry()
inv.Register(nil, testActor{})
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
nvm, err := vm.NewVM(ctx, vmopt)
if err != nil {
return nil, err
}
nvm.SetInvoker(inv)
return nvm, nil
})
cg.SetStateManager(sm)
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
if err != nil {
t.Fatal(err)
}
m := &types.Message{
From: cg.Banker(),
To: lotusinit.Address,
Method: builtin.MethodsInit.Exec,
Params: enc,
GasLimit: types.TestGasLimit,
Value: types.NewInt(0),
GasPremium: types.NewInt(0),
GasFeeCap: types.NewInt(0),
}
for i := 0; i < 50; i++ {
ts, err := cg.NextTipSet()
if err != nil {
t.Fatal(err)
}
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
switch ts.TipSet.TipSet().Height() {
case testForkHeight, testForkHeight + 1:
// If I had a fork, or I _will_ have a fork, it should fail.
require.Equal(t, ErrExpensiveFork, err)
default:
require.NoError(t, err)
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
}
// Call just runs on the parent state for a tipset, so we only
// expect an error at the fork height.
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
switch ts.TipSet.TipSet().Height() {
case testForkHeight + 1:
require.Equal(t, ErrExpensiveFork, err)
default:
require.NoError(t, err)
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
}
}
}
+76 -38
View File
@@ -2,6 +2,7 @@ package stmgr
import (
"context"
"errors"
"fmt"
"sync"
@@ -37,8 +38,16 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
)
const LookbackNoLimit = abi.ChainEpoch(-1)
var log = logging.Logger("statemgr")
type StateManagerAPI interface {
LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error)
LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
}
type versionSpec struct {
networkVersion network.Version
atOrBelow abi.ChainEpoch
@@ -53,6 +62,10 @@ type StateManager struct {
// Maps chain epochs to upgrade functions.
stateMigrations map[abi.ChainEpoch]UpgradeFunc
// A set of potentially expensive/time consuming upgrades. Explicit
// calls for, e.g., gas estimation fail against this epoch with
// ErrExpensiveFork.
expensiveUpgrades map[abi.ChainEpoch]struct{}
stCache map[string][]cid.Cid
compWait map[string]chan struct{}
@@ -78,6 +91,7 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
}
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us))
var networkVersions []versionSpec
lastVersion := network.Version0
if len(us) > 0 {
@@ -87,6 +101,9 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
if upgrade.Migration != nil {
stateMigrations[upgrade.Height] = upgrade.Migration
}
if upgrade.Expensive {
expensiveUpgrades[upgrade.Height] = struct{}{}
}
networkVersions = append(networkVersions, versionSpec{
networkVersion: lastVersion,
atOrBelow: upgrade.Height,
@@ -99,13 +116,14 @@ func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule
}
return &StateManager{
networkVersions: networkVersions,
latestVersion: lastVersion,
stateMigrations: stateMigrations,
newVM: vm.NewVM,
cs: cs,
stCache: make(map[string][]cid.Cid),
compWait: make(map[string]chan struct{}),
networkVersions: networkVersions,
latestVersion: lastVersion,
stateMigrations: stateMigrations,
expensiveUpgrades: expensiveUpgrades,
newVM: vm.NewVM,
cs: cs,
stCache: make(map[string][]cid.Cid),
compWait: make(map[string]chan struct{}),
}, nil
}
@@ -498,16 +516,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
return nil, fmt.Errorf("failed to load message: %w", err)
}
r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage())
if err != nil {
return nil, err
}
if r != nil {
return r, nil
}
_, r, _, err = sm.searchBackForMsg(ctx, ts, m)
_, r, _, err := sm.searchBackForMsg(ctx, ts, m, LookbackNoLimit)
if err != nil {
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
}
@@ -516,9 +525,9 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
}
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
// before returning.
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
// chain for at least confidence epochs without being reverted before returning.
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@@ -556,7 +565,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
var backFm cid.Cid
backSearchWait := make(chan struct{})
go func() {
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg)
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit)
if err != nil {
log.Warnf("failed to look back through chain for message: %w", err)
return
@@ -648,7 +657,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
return head, r, foundMsg, nil
}
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg)
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, LookbackNoLimit)
if err != nil {
log.Warnf("failed to look back through chain for message %s", mcid)
@@ -662,11 +671,33 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
return fts, r, foundMsg, nil
}
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
// searchBackForMsg searches up to limit tipsets backwards from the given
// tipset for a message receipt.
// If limit is
// - 0 then no tipsets are searched
// - 5 then five tipset are searched
// - LookbackNoLimit then there is no limit
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
limitHeight := from.Height() - limit
noLimit := limit == LookbackNoLimit
cur := from
curActor, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
if err != nil {
return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset")
}
mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from)
if err != nil {
return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err)
}
mNonce := m.VMMessage().Nonce
for {
if cur.Height() == 0 {
// If we've reached the genesis block, or we've reached the limit of
// how far back to look
if cur.Height() == 0 || !noLimit && cur.Height() <= limitHeight {
// it ain't here!
return nil, nil, cid.Undef, nil
}
@@ -677,32 +708,37 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
default:
}
act, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
if err != nil {
return nil, nil, cid.Cid{}, err
}
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
// either way, no reason to lookback, it ain't there
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
if curActor == nil || curActor.Nonce == 0 || curActor.Nonce < mNonce {
return nil, nil, cid.Undef, nil
}
ts, err := sm.cs.LoadTipSet(cur.Parents())
pts, err := sm.cs.LoadTipSet(cur.Parents())
if err != nil {
return nil, nil, cid.Undef, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err)
return nil, nil, cid.Undef, xerrors.Errorf("failed to load tipset during msg wait searchback: %w", err)
}
r, foundMsg, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage())
if err != nil {
return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %w", err)
act, err := sm.LoadActor(ctx, mFromId, pts)
actorNoExist := errors.Is(err, types.ErrActorNotFound)
if err != nil && !actorNoExist {
return nil, nil, cid.Cid{}, xerrors.Errorf("failed to load the actor: %w", err)
}
if r != nil {
return ts, r, foundMsg, nil
// check that between cur and parent tipset the nonce fell into range of our message
if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) {
r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage())
if err != nil {
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
}
if r != nil {
return pts, r, foundMsg, nil
}
}
cur = ts
cur = pts
curActor = act
}
}
@@ -1375,3 +1411,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
}
return actState, nil
}
var _ StateManagerAPI = (*StateManager)(nil)
+1 -1
View File
@@ -387,7 +387,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(ctx, vmopt)
vmi, err := sm.newVM(ctx, vmopt)
if err != nil {
return cid.Undef, nil, err
}
+1 -1
View File
@@ -31,7 +31,7 @@ func TestIndexSeeks(t *testing.T) {
ctx := context.TODO()
nbs := blockstore.NewTemporarySync()
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil, nil)
_, err = cs.Import(bytes.NewReader(gencar))
if err != nil {
+59 -4
View File
@@ -8,6 +8,7 @@ import (
"io"
"os"
"strconv"
"strings"
"sync"
"golang.org/x/sync/errgroup"
@@ -38,7 +39,9 @@ import (
lru "github.com/hashicorp/golang-lru"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
dstore "github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
car "github.com/ipld/go-car"
@@ -102,7 +105,7 @@ type HeadChangeEvt struct {
// 2. a block => messages references cache.
type ChainStore struct {
bs bstore.Blockstore
ds dstore.Datastore
ds dstore.Batching
heaviestLk sync.Mutex
heaviest *types.TipSet
@@ -124,11 +127,15 @@ type ChainStore struct {
vmcalls vm.SyscallBuilder
evtTypes [1]journal.EventType
journal journal.Journal
}
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder, j journal.Journal) *ChainStore {
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
if j == nil {
j = journal.NilJournal()
}
cs := &ChainStore{
bs: bs,
ds: ds,
@@ -137,10 +144,11 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
mmCache: c,
tsCache: tsc,
vmcalls: vmcalls,
journal: j,
}
cs.evtTypes = [1]journal.EventType{
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
evtTypeHeadChange: j.RegisterEventType("sync", "head_change"),
}
ci := NewChainIndex(cs.LoadTipSet)
@@ -379,7 +387,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
continue
}
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
cs.journal.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
return HeadChangeEvt{
From: r.old.Key(),
FromHeight: r.old.Height(),
@@ -441,6 +449,53 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
return nil
}
// FlushValidationCache removes all results of block validation from the
// chain metadata store. Usually the first step after a new chain import.
func (cs *ChainStore) FlushValidationCache() error {
log.Infof("clearing block validation cache...")
dsWalk, err := cs.ds.Query(query.Query{
// Potential TODO: the validation cache is not a namespace on its own
// but is rather constructed as prefixed-key `foo:bar` via .Instance(), which
// in turn does not work with the filter, which can match only on `foo/bar`
//
// If this is addressed (blockcache goes into its own sub-namespace) then
// strings.HasPrefix(...) below can be skipped
//
//Prefix: blockValidationCacheKeyPrefix.String()
KeysOnly: true,
})
if err != nil {
return xerrors.Errorf("failed to initialize key listing query: %w", err)
}
allKeys, err := dsWalk.Rest()
if err != nil {
return xerrors.Errorf("failed to run key listing query: %w", err)
}
batch, err := cs.ds.Batch()
if err != nil {
return xerrors.Errorf("failed to open a DS batch: %w", err)
}
delCnt := 0
for _, k := range allKeys {
if strings.HasPrefix(k.Key, blockValidationCacheKeyPrefix.String()) {
delCnt++
batch.Delete(datastore.RawKey(k.Key)) // nolint:errcheck
}
}
if err := batch.Commit(); err != nil {
return xerrors.Errorf("failed to commit the DS batch: %w", err)
}
log.Infof("%d block validation entries cleared.", delCnt)
return nil
}
// SetHead sets the chainstores current 'best' head node.
// This should only be called if something is broken and needs fixing
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
+2 -2
View File
@@ -62,7 +62,7 @@ func BenchmarkGetRandomness(b *testing.B) {
bs := blockstore.NewBlockstore(bds)
cs := store.NewChainStore(bs, mds, nil)
cs := store.NewChainStore(bs, mds, nil, nil)
b.ResetTimer()
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
}
nbs := blockstore.NewTemporary()
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil)
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil, nil)
root, err := cs.Import(buf)
if err != nil {
+28 -34
View File
@@ -120,12 +120,6 @@ func FetchMessagesByCids(
return err
}
// FIXME: We already sort in `fetchCids`, we are duplicating too much work,
// we don't need to pass the index.
if out[i] != nil {
return fmt.Errorf("received duplicate message")
}
out[i] = msg
return nil
})
@@ -149,10 +143,6 @@ func FetchSignedMessagesByCids(
return err
}
if out[i] != nil {
return fmt.Errorf("received duplicate message")
}
out[i] = smsg
return nil
})
@@ -172,37 +162,41 @@ func fetchCids(
cids []cid.Cid,
cb func(int, blocks.Block) error,
) error {
fetchedBlocks := bserv.GetBlocks(ctx, cids)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
cidIndex := make(map[cid.Cid]int)
for i, c := range cids {
cidIndex[c] = i
}
if len(cids) != len(cidIndex) {
return fmt.Errorf("duplicate CIDs in fetchCids input")
}
for i := 0; i < len(cids); i++ {
select {
case block, ok := <-fetchedBlocks:
if !ok {
// Closed channel, no more blocks fetched, check if we have all
// of the CIDs requested.
// FIXME: Review this check. We don't call the callback on the
// last index?
if i == len(cids)-1 {
break
}
return fmt.Errorf("failed to fetch all messages")
}
ix, ok := cidIndex[block.Cid()]
if !ok {
return fmt.Errorf("received message we didnt ask for")
}
if err := cb(ix, block); err != nil {
return err
}
for block := range bserv.GetBlocks(ctx, cids) {
ix, ok := cidIndex[block.Cid()]
if !ok {
// Ignore duplicate/unexpected blocks. This shouldn't
// happen, but we can be safe.
log.Errorw("received duplicate/unexpected block when syncing", "cid", block.Cid())
continue
}
// Record that we've received the block.
delete(cidIndex, block.Cid())
if err := cb(ix, block); err != nil {
return err
}
}
if len(cidIndex) > 0 {
err := ctx.Err()
if err == nil {
err = fmt.Errorf("failed to fetch %d messages for unknown reasons", len(cidIndex))
}
return err
}
return nil
+63
View File
@@ -0,0 +1,63 @@
package sub
import (
"context"
"testing"
address "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
)
type getter struct {
msgs []*types.Message
}
func (g *getter) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { panic("NYI") }
func (g *getter) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
ch := make(chan blocks.Block, len(g.msgs))
for _, m := range g.msgs {
by, err := m.Serialize()
if err != nil {
panic(err)
}
b, err := blocks.NewBlockWithCid(by, m.Cid())
if err != nil {
panic(err)
}
ch <- b
}
close(ch)
return ch
}
func TestFetchCidsWithDedup(t *testing.T) {
msgs := []*types.Message{}
for i := 0; i < 10; i++ {
msgs = append(msgs, &types.Message{
From: address.TestAddress,
To: address.TestAddress,
Nonce: uint64(i),
})
}
cids := []cid.Cid{}
for _, m := range msgs {
cids = append(cids, m.Cid())
}
g := &getter{msgs}
// the cids have a duplicate
res, err := FetchMessagesByCids(context.TODO(), g, append(cids, cids[0]))
t.Logf("err: %+v", err)
t.Logf("res: %+v", res)
if err == nil {
t.Errorf("there should be an error")
}
if err == nil && (res[0] == nil || res[len(res)-1] == nil) {
t.Fatalf("there is a nil message: first %p, last %p", res[0], res[len(res)-1])
}
}
+24 -8
View File
@@ -217,6 +217,12 @@ func (syncer *Syncer) Stop() {
// This should be called when connecting to new peers, and additionally
// when receiving new blocks from the network
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
defer func() {
if err := recover(); err != nil {
log.Errorf("panic in InformNewHead: ", err)
}
}()
ctx := context.Background()
if fts == nil {
log.Errorf("got nil tipset in InformNewHead")
@@ -731,7 +737,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, use
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
if err != nil {
return xerrors.Errorf("failed to compute lookback tipset state: %w", err)
return xerrors.Errorf("failed to compute lookback tipset state (epoch %d): %w", lbts.Height(), err)
}
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
@@ -1281,9 +1287,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
blockSet := []*types.TipSet{incoming}
// Parent of the new (possibly better) tipset that we need to fetch next.
at := incoming.Parents()
// we want to sync all the blocks until the height above the block we have
// we want to sync all the blocks until the height above our
// best tipset so far
untilHeight := known.Height() + 1
ss.SetHeight(blockSet[len(blockSet)-1].Height())
@@ -1377,13 +1385,17 @@ loop:
}
base := blockSet[len(blockSet)-1]
if base.Parents() == known.Parents() {
// common case: receiving a block thats potentially part of the same tipset as our best block
if base.IsChildOf(known) {
// common case: receiving blocks that are building on top of our best tipset
return blockSet, nil
}
if types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
// common case: receiving blocks that are building on top of our best tipset
knownParent, err := syncer.store.LoadTipSet(known.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
}
if base.IsChildOf(knownParent) {
// common case: receiving a block thats potentially part of the same tipset as our best block
return blockSet, nil
}
@@ -1514,7 +1526,7 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
ss.SetStage(api.StageMessages)
if batchErr != nil {
return xerrors.Errorf("failed to fetch messages: %w", err)
return xerrors.Errorf("failed to fetch messages: %w", batchErr)
}
for bsi := 0; bsi < len(bstout); bsi++ {
@@ -1714,7 +1726,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
return gen.VerifyVRF(ctx, worker, rand, evrf)
}
func (syncer *Syncer) State() []SyncerState {
func (syncer *Syncer) State() []SyncerStateSnapshot {
return syncer.syncmgr.State()
}
@@ -1728,6 +1740,10 @@ func (syncer *Syncer) UnmarkBad(blk cid.Cid) {
syncer.bad.Remove(blk)
}
func (syncer *Syncer) UnmarkAllBad() {
syncer.bad.Purge()
}
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
bbr, ok := syncer.bad.Has(blk)
return bbr.String(), ok
+9 -6
View File
@@ -38,7 +38,7 @@ type SyncManager interface {
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
// State retrieves the state of the sync workers.
State() []SyncerState
State() []SyncerStateSnapshot
}
type syncManager struct {
@@ -79,7 +79,7 @@ type syncResult struct {
const syncWorkerCount = 3
func NewSyncManager(sync SyncFunc) SyncManager {
return &syncManager{
sm := &syncManager{
bspThresh: 1,
peerHeads: make(map[peer.ID]*types.TipSet),
syncTargets: make(chan *types.TipSet),
@@ -90,6 +90,10 @@ func NewSyncManager(sync SyncFunc) SyncManager {
doSync: sync,
stop: make(chan struct{}),
}
for i := range sm.syncStates {
sm.syncStates[i] = new(SyncerState)
}
return sm
}
func (sm *syncManager) Start() {
@@ -128,8 +132,8 @@ func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
sm.incomingTipSets <- ts
}
func (sm *syncManager) State() []SyncerState {
ret := make([]SyncerState, 0, len(sm.syncStates))
func (sm *syncManager) State() []SyncerStateSnapshot {
ret := make([]SyncerStateSnapshot, 0, len(sm.syncStates))
for _, s := range sm.syncStates {
ret = append(ret, s.Snapshot())
}
@@ -405,8 +409,7 @@ func (sm *syncManager) scheduleWorkSent() {
}
func (sm *syncManager) syncWorker(id int) {
ss := &SyncerState{}
sm.syncStates[id] = ss
ss := sm.syncStates[id]
for {
select {
case ts, ok := <-sm.syncTargets:
+6 -6
View File
@@ -221,8 +221,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
var out api.FullNode
// TODO: Don't ignore stop
_, err := node.New(tu.ctx,
stop, err := node.New(tu.ctx,
node.FullAPI(&out),
node.Online(),
node.Repo(sourceRepo),
@@ -232,6 +231,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
)
require.NoError(tu.t, err)
tu.t.Cleanup(func() { _ = stop(context.Background()) })
lastTs := blocks[len(blocks)-1].Blocks
for _, lastB := range lastTs {
@@ -253,8 +253,7 @@ func (tu *syncTestUtil) addClientNode() int {
var out api.FullNode
// TODO: Don't ignore stop
_, err := node.New(tu.ctx,
stop, err := node.New(tu.ctx,
node.FullAPI(&out),
node.Online(),
node.Repo(repo.NewMemory(nil)),
@@ -264,6 +263,7 @@ func (tu *syncTestUtil) addClientNode() int {
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
)
require.NoError(tu.t, err)
tu.t.Cleanup(func() { _ = stop(context.Background()) })
tu.nds = append(tu.nds, out)
return len(tu.nds) - 1
@@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) {
GasPremium: types.NewInt(0),
}
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
require.NoError(t, err)
return &types.SignedMessage{
@@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) {
GasPremium: types.NewInt(0),
}
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
require.NoError(t, err)
return &types.SignedMessage{
+21 -25
View File
@@ -11,8 +11,7 @@ import (
"github.com/filecoin-project/lotus/chain/types"
)
type SyncerState struct {
lk sync.Mutex
type SyncerStateSnapshot struct {
Target *types.TipSet
Base *types.TipSet
Stage api.SyncStateStage
@@ -22,6 +21,11 @@ type SyncerState struct {
End time.Time
}
type SyncerState struct {
lk sync.Mutex
data SyncerStateSnapshot
}
func (ss *SyncerState) SetStage(v api.SyncStateStage) {
if ss == nil {
return
@@ -29,9 +33,9 @@ func (ss *SyncerState) SetStage(v api.SyncStateStage) {
ss.lk.Lock()
defer ss.lk.Unlock()
ss.Stage = v
ss.data.Stage = v
if v == api.StageSyncComplete {
ss.End = build.Clock.Now()
ss.data.End = build.Clock.Now()
}
}
@@ -42,13 +46,13 @@ func (ss *SyncerState) Init(base, target *types.TipSet) {
ss.lk.Lock()
defer ss.lk.Unlock()
ss.Target = target
ss.Base = base
ss.Stage = api.StageHeaders
ss.Height = 0
ss.Message = ""
ss.Start = build.Clock.Now()
ss.End = time.Time{}
ss.data.Target = target
ss.data.Base = base
ss.data.Stage = api.StageHeaders
ss.data.Height = 0
ss.data.Message = ""
ss.data.Start = build.Clock.Now()
ss.data.End = time.Time{}
}
func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
@@ -58,7 +62,7 @@ func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
ss.lk.Lock()
defer ss.lk.Unlock()
ss.Height = h
ss.data.Height = h
}
func (ss *SyncerState) Error(err error) {
@@ -68,21 +72,13 @@ func (ss *SyncerState) Error(err error) {
ss.lk.Lock()
defer ss.lk.Unlock()
ss.Message = err.Error()
ss.Stage = api.StageSyncErrored
ss.End = build.Clock.Now()
ss.data.Message = err.Error()
ss.data.Stage = api.StageSyncErrored
ss.data.End = build.Clock.Now()
}
func (ss *SyncerState) Snapshot() SyncerState {
func (ss *SyncerState) Snapshot() SyncerStateSnapshot {
ss.lk.Lock()
defer ss.lk.Unlock()
return SyncerState{
Base: ss.Base,
Target: ss.Target,
Stage: ss.Stage,
Height: ss.Height,
Message: ss.Message,
Start: ss.Start,
End: ss.End,
}
return ss.data
}
+8 -8
View File
@@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
scratch := make([]byte, 9)
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
return err
@@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Version (uint64) (uint64)
// t.Version (types.StateTreeVersion) (uint64)
{
@@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Version = uint64(extra)
t.Version = StateTreeVersion(extra)
}
// t.Actors (cid.Cid) (struct)
@@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
return nil
}
var lengthBufStateInfo = []byte{128}
var lengthBufStateInfo0 = []byte{128}
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
if _, err := w.Write(lengthBufStateInfo); err != nil {
if _, err := w.Write(lengthBufStateInfo0); err != nil {
return err
}
return nil
}
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo{}
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
*t = StateInfo0{}
br := cbg.GetPeeker(r)
scratch := make([]byte, 8)
+6 -2
View File
@@ -12,11 +12,15 @@ import (
type FIL BigInt
func (f FIL) String() string {
return f.Unitless() + " FIL"
}
func (f FIL) Unitless() string {
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
if r.Sign() == 0 {
return "0 FIL"
return "0"
}
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
}
func (f FIL) Format(s fmt.State, ch rune) {
+6 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/filecoin-project/go-state-types/crypto"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
@@ -22,7 +23,7 @@ func Address(i uint64) address.Address {
return a
}
func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage {
func MkMessage(from, to address.Address, nonce uint64, w *wallet.LocalWallet) *types.SignedMessage {
msg := &types.Message{
To: to,
From: from,
@@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.
GasPremium: types.NewInt(1),
}
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
if err != nil {
panic(err)
}
@@ -59,9 +60,11 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
var pcids []cid.Cid
var height abi.ChainEpoch
weight := types.NewInt(weightInc)
var timestamp uint64
if parents != nil {
pcids = parents.Cids()
height = parents.Height() + 1
timestamp = parents.MinTimestamp() + build.BlockDelaySecs
weight = types.BigAdd(parents.Blocks()[0].ParentWeight, weight)
}
@@ -79,6 +82,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
ParentWeight: weight,
Messages: c,
Height: height,
Timestamp: timestamp,
ParentStateRoot: pstateRoot,
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)),
+14 -3
View File
@@ -2,9 +2,20 @@ package types
import "github.com/ipfs/go-cid"
// StateTreeVersion is the version of the state tree itself, independent of the
// network version or the actors version.
type StateTreeVersion uint64
const (
// StateTreeVersion0 corresponds to actors < v2.
StateTreeVersion0 StateTreeVersion = iota
// StateTreeVersion1 corresponds to actors >= v2.
StateTreeVersion1
)
type StateRoot struct {
// State root version. Versioned along with actors (for now).
Version uint64
// State tree version.
Version StateTreeVersion
// Actors tree. The structure depends on the state root version.
Actors cid.Cid
// Info. The structure depends on the state root version.
@@ -12,4 +23,4 @@ type StateRoot struct {
}
// TODO: version this.
type StateInfo struct{}
type StateInfo0 struct{}
+5 -4
View File
@@ -1,6 +1,7 @@
package main
import (
"context"
"encoding/json"
"fmt"
"math/rand"
@@ -61,11 +62,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
panic(err)
}
blsk, err := w.GenerateKey(crypto.SigTypeBLS)
blsk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
panic(err)
}
bki, err := w.Export(blsk)
bki, err := w.WalletExport(context.Background(), blsk)
if err != nil {
panic(err)
}
@@ -85,11 +86,11 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
Signature: &bmsg.Signature,
}
secpk, err := w.GenerateKey(crypto.SigTypeBLS)
secpk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
if err != nil {
panic(err)
}
ski, err := w.Export(secpk)
ski, err := w.WalletExport(context.Background(), secpk)
if err != nil {
panic(err)
}
+3 -3
View File
@@ -70,12 +70,12 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth
log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver())
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params))
}
if err := act.predicate(rt, act.vmActor); err != nil {
return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err)
}
if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil {
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method)
}
if err := act.predicate(rt, act.vmActor); err != nil {
return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "unsupported actor: %s", err)
}
return act.methods[method](rt, params)
}
+5 -4
View File
@@ -49,6 +49,9 @@ func (m *Message) ValueReceived() abi.TokenAmount {
return m.msg.Value
}
// EnableGasTracing, if true, outputs gas tracing in execution traces.
var EnableGasTracing = false
type Runtime struct {
rt0.Message
rt0.Syscalls
@@ -477,7 +480,7 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
}
func (rt *Runtime) finilizeGasTracing() {
if enableTracing {
if EnableGasTracing {
if rt.lastGasCharge != nil {
rt.lastGasCharge.TimeTaken = time.Since(rt.lastGasChargeTime)
}
@@ -509,11 +512,9 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
}
var enableTracing = false
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
toUse := gas.Total()
if enableTracing {
if EnableGasTracing {
var callers [10]uintptr
cout := 0 //gruntime.Callers(2+skip, callers[:])
+20
View File
@@ -45,3 +45,23 @@ func TestRuntimePutErrors(t *testing.T) {
rt.StorePut(&NotAVeryGoodMarshaler{})
t.Error("expected panic")
}
func BenchmarkRuntime_CreateRuntimeChargeGas_TracingDisabled(b *testing.B) {
var (
cst = cbor.NewCborStore(nil)
gch = newGasCharge("foo", 1000, 1000)
)
b.ResetTimer()
EnableGasTracing = false
noop := func() bool { return EnableGasTracing }
for n := 0; n < b.N; n++ {
// flip the value and access it to make sure
// the compiler doesn't optimize away
EnableGasTracing = true
_ = noop()
EnableGasTracing = false
_ = (&Runtime{cst: cst}).chargeGasInternal(gch, 0)
}
}
+1 -1
View File
@@ -236,7 +236,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
}
rt := vm.makeRuntime(ctx, msg, origin, on, gasUsed, nac)
if enableTracing {
if EnableGasTracing {
rt.lastGasChargeTime = start
if parent != nil {
rt.lastGasChargeTime = parent.lastGasChargeTime
+81
View File
@@ -0,0 +1,81 @@
package wallet
import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
)
func GenerateKey(typ crypto.SigType) (*Key, error) {
pk, err := sigs.Generate(typ)
if err != nil {
return nil, err
}
ki := types.KeyInfo{
Type: kstoreSigType(typ),
PrivateKey: pk,
}
return NewKey(ki)
}
type Key struct {
types.KeyInfo
PublicKey []byte
Address address.Address
}
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
k := &Key{
KeyInfo: keyinfo,
}
var err error
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
if err != nil {
return nil, err
}
switch k.Type {
case KTSecp256k1:
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
}
case KTBLS:
k.Address, err = address.NewBLSAddress(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting BLS to address: %w", err)
}
default:
return nil, xerrors.Errorf("unknown key type")
}
return k, nil
}
func kstoreSigType(typ crypto.SigType) string {
switch typ {
case crypto.SigTypeBLS:
return KTBLS
case crypto.SigTypeSecp256k1:
return KTSecp256k1
default:
return ""
}
}
func ActSigType(typ string) crypto.SigType {
switch typ {
case KTBLS:
return crypto.SigTypeBLS
case KTSecp256k1:
return crypto.SigTypeSecp256k1
default:
return 0
}
}
+42
View File
@@ -0,0 +1,42 @@
package remotewallet
import (
"context"
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/node/modules/helpers"
)
type RemoteWallet struct {
api.WalletAPI
}
func SetupRemoteWallet(info string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (*RemoteWallet, error) {
ai := cliutil.ParseApiInfo(info)
url, err := ai.DialArgs()
if err != nil {
return nil, err
}
wapi, closer, err := client.NewWalletRPC(mctx, url, ai.AuthHeader())
if err != nil {
return nil, xerrors.Errorf("creating jsonrpc client: %w", err)
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
closer()
return nil
},
})
return &RemoteWallet{wapi}, nil
}
}
+48 -87
View File
@@ -12,6 +12,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
@@ -29,15 +30,20 @@ const (
KTSecp256k1 = "secp256k1"
)
type Wallet struct {
type LocalWallet struct {
keys map[address.Address]*Key
keystore types.KeyStore
lk sync.Mutex
}
func NewWallet(keystore types.KeyStore) (*Wallet, error) {
w := &Wallet{
type Default interface {
GetDefault() (address.Address, error)
SetDefault(a address.Address) error
}
func NewWallet(keystore types.KeyStore) (*LocalWallet, error) {
w := &LocalWallet{
keys: make(map[address.Address]*Key),
keystore: keystore,
}
@@ -45,18 +51,18 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
return w, nil
}
func KeyWallet(keys ...*Key) *Wallet {
func KeyWallet(keys ...*Key) *LocalWallet {
m := make(map[address.Address]*Key)
for _, key := range keys {
m[key.Address] = key
}
return &Wallet{
return &LocalWallet{
keys: m,
}
}
func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*crypto.Signature, error) {
func (w *LocalWallet) WalletSign(ctx context.Context, addr address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
ki, err := w.findKey(addr)
if err != nil {
return nil, err
@@ -68,7 +74,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*c
return sigs.Sign(ActSigType(ki.Type), ki.PrivateKey, msg)
}
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
func (w *LocalWallet) findKey(addr address.Address) (*Key, error) {
w.lk.Lock()
defer w.lk.Unlock()
@@ -96,7 +102,7 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
return k, nil
}
func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
func (w *LocalWallet) tryFind(addr address.Address) (types.KeyInfo, error) {
ki, err := w.keystore.Get(KNamePrefix + addr.String())
if err == nil {
@@ -110,14 +116,12 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
// We got an ErrKeyInfoNotFound error
// Try again, this time with the testnet prefix
aChars := []rune(addr.String())
prefixRunes := []rune(address.TestnetPrefix)
if len(prefixRunes) != 1 {
return types.KeyInfo{}, xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
tAddress, err := swapMainnetForTestnetPrefix(addr.String())
if err != nil {
return types.KeyInfo{}, err
}
aChars[0] = prefixRunes[0]
ki, err = w.keystore.Get(KNamePrefix + string(aChars))
ki, err = w.keystore.Get(KNamePrefix + tAddress)
if err != nil {
return types.KeyInfo{}, err
}
@@ -132,16 +136,19 @@ func (w *Wallet) tryFind(addr address.Address) (types.KeyInfo, error) {
return ki, nil
}
func (w *Wallet) Export(addr address.Address) (*types.KeyInfo, error) {
func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (*types.KeyInfo, error) {
k, err := w.findKey(addr)
if err != nil {
return nil, xerrors.Errorf("failed to find key to export: %w", err)
}
if k == nil {
return nil, xerrors.Errorf("key not found")
}
return &k.KeyInfo, nil
}
func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
func (w *LocalWallet) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
@@ -157,7 +164,7 @@ func (w *Wallet) Import(ki *types.KeyInfo) (address.Address, error) {
return k.Address, nil
}
func (w *Wallet) ListAddrs() ([]address.Address, error) {
func (w *LocalWallet) WalletList(ctx context.Context) ([]address.Address, error) {
all, err := w.keystore.List()
if err != nil {
return nil, xerrors.Errorf("listing keystore: %w", err)
@@ -190,7 +197,7 @@ func (w *Wallet) ListAddrs() ([]address.Address, error) {
return out, nil
}
func (w *Wallet) GetDefault() (address.Address, error) {
func (w *LocalWallet) GetDefault() (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
@@ -207,7 +214,7 @@ func (w *Wallet) GetDefault() (address.Address, error) {
return k.Address, nil
}
func (w *Wallet) SetDefault(a address.Address) error {
func (w *LocalWallet) SetDefault(a address.Address) error {
w.lk.Lock()
defer w.lk.Unlock()
@@ -229,19 +236,7 @@ func (w *Wallet) SetDefault(a address.Address) error {
return nil
}
func GenerateKey(typ crypto.SigType) (*Key, error) {
pk, err := sigs.Generate(typ)
if err != nil {
return nil, err
}
ki := types.KeyInfo{
Type: kstoreSigType(typ),
PrivateKey: pk,
}
return NewKey(ki)
}
func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
func (w *LocalWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
@@ -269,7 +264,7 @@ func (w *Wallet) GenerateKey(typ crypto.SigType) (address.Address, error) {
return k.Address, nil
}
func (w *Wallet) HasKey(addr address.Address) (bool, error) {
func (w *LocalWallet) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
k, err := w.findKey(addr)
if err != nil {
return false, err
@@ -277,11 +272,14 @@ func (w *Wallet) HasKey(addr address.Address) (bool, error) {
return k != nil, nil
}
func (w *Wallet) DeleteKey(addr address.Address) error {
func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) error {
k, err := w.findKey(addr)
if err != nil {
return xerrors.Errorf("failed to delete key %s : %w", addr, err)
}
if k == nil {
return nil // already not there
}
if err := w.keystore.Put(KTrashPrefix+k.Address.String(), k.KeyInfo); err != nil {
return xerrors.Errorf("failed to mark key %s as trashed: %w", addr, err)
@@ -291,63 +289,26 @@ func (w *Wallet) DeleteKey(addr address.Address) error {
return xerrors.Errorf("failed to delete key %s: %w", addr, err)
}
tAddr, err := swapMainnetForTestnetPrefix(addr.String())
if err != nil {
return xerrors.Errorf("failed to swap prefixes: %w", err)
}
// TODO: Does this always error in the not-found case? Just ignoring an error return for now.
_ = w.keystore.Delete(KNamePrefix + tAddr)
return nil
}
type Key struct {
types.KeyInfo
var _ api.WalletAPI = &LocalWallet{}
PublicKey []byte
Address address.Address
}
func NewKey(keyinfo types.KeyInfo) (*Key, error) {
k := &Key{
KeyInfo: keyinfo,
}
var err error
k.PublicKey, err = sigs.ToPublic(ActSigType(k.Type), k.PrivateKey)
if err != nil {
return nil, err
}
switch k.Type {
case KTSecp256k1:
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
}
case KTBLS:
k.Address, err = address.NewBLSAddress(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting BLS to address: %w", err)
}
default:
return nil, xerrors.Errorf("unknown key type")
func swapMainnetForTestnetPrefix(addr string) (string, error) {
aChars := []rune(addr)
prefixRunes := []rune(address.TestnetPrefix)
if len(prefixRunes) != 1 {
return "", xerrors.Errorf("unexpected prefix length: %d", len(prefixRunes))
}
return k, nil
}
func kstoreSigType(typ crypto.SigType) string {
switch typ {
case crypto.SigTypeBLS:
return KTBLS
case crypto.SigTypeSecp256k1:
return KTSecp256k1
default:
return ""
}
}
func ActSigType(typ string) crypto.SigType {
switch typ {
case KTBLS:
return crypto.SigTypeBLS
case KTSecp256k1:
return crypto.SigTypeSecp256k1
default:
return 0
}
aChars[0] = prefixRunes[0]
return string(aChars), nil
}
+12 -6
View File
@@ -449,11 +449,16 @@ var chainInspectUsage = &cli.Command{
bySender := make(map[string]int64)
byDest := make(map[string]int64)
byMethod := make(map[string]int64)
bySenderC := make(map[string]int64)
byDestC := make(map[string]int64)
byMethodC := make(map[string]int64)
var sum int64
for _, m := range msgs {
bySender[m.Message.From.String()] += m.Message.GasLimit
bySenderC[m.Message.From.String()]++
byDest[m.Message.To.String()] += m.Message.GasLimit
byDestC[m.Message.To.String()]++
sum += m.Message.GasLimit
code, err := lookupActorCode(m.Message.To)
@@ -464,7 +469,7 @@ var chainInspectUsage = &cli.Command{
mm := stmgr.MethodsMap[code][m.Message.Method]
byMethod[mm.Name] += m.Message.GasLimit
byMethodC[mm.Name]++
}
type keyGasPair struct {
@@ -496,19 +501,19 @@ var chainInspectUsage = &cli.Command{
fmt.Printf("By Sender:\n")
for i := 0; i < numRes && i < len(senderVals); i++ {
sv := senderVals[i]
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, bySenderC[sv.Key])
}
fmt.Println()
fmt.Printf("By Receiver:\n")
for i := 0; i < numRes && i < len(destVals); i++ {
sv := destVals[i]
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byDestC[sv.Key])
}
fmt.Println()
fmt.Printf("By Method:\n")
for i := 0; i < numRes && i < len(methodVals); i++ {
sv := methodVals[i]
fmt.Printf("%s\t%0.2f%%\t(%d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas)
fmt.Printf("%s\t%0.2f%%\t(total: %d, count: %d)\n", sv.Key, (100*float64(sv.Gas))/float64(sum), sv.Gas, byMethodC[sv.Key])
}
return nil
@@ -516,8 +521,9 @@ var chainInspectUsage = &cli.Command{
}
var chainListCmd = &cli.Command{
Name: "list",
Usage: "View a segment of the chain",
Name: "list",
Aliases: []string{"love"},
Usage: "View a segment of the chain",
Flags: []cli.Flag{
&cli.Uint64Flag{Name: "height"},
&cli.IntFlag{Name: "count", Value: 30},
+16 -7
View File
@@ -536,7 +536,7 @@ func interactiveDeal(cctx *cli.Context) error {
state = "miner"
case "miner":
fmt.Print("Miner Address (t0..): ")
fmt.Print("Miner Address (f0..): ")
var maddrStr string
_, err := fmt.Scan(&maddrStr)
@@ -1039,6 +1039,10 @@ var clientListDeals = &cli.Command{
Usage: "use color in display output",
Value: true,
},
&cli.BoolFlag{
Name: "show-failed",
Usage: "show failed/failing deals",
},
&cli.BoolFlag{
Name: "watch",
Usage: "watch deal updates in real-time, rather than a one time list",
@@ -1055,6 +1059,7 @@ var clientListDeals = &cli.Command{
verbose := cctx.Bool("verbose")
color := cctx.Bool("color")
watch := cctx.Bool("watch")
showFailed := cctx.Bool("show-failed")
localDeals, err := api.ClientListDeals(ctx)
if err != nil {
@@ -1071,7 +1076,7 @@ var clientListDeals = &cli.Command{
tm.Clear()
tm.MoveCursor(1, 1)
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color)
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color, showFailed)
if err != nil {
return err
}
@@ -1097,7 +1102,7 @@ var clientListDeals = &cli.Command{
}
}
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"))
return outputStorageDeals(ctx, os.Stdout, api, localDeals, cctx.Bool("verbose"), cctx.Bool("color"), showFailed)
},
}
@@ -1120,7 +1125,7 @@ func dealFromDealInfo(ctx context.Context, full api.FullNode, head *types.TipSet
}
}
func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, localDeals []api.DealInfo, verbose bool, color bool) error {
func outputStorageDeals(ctx context.Context, out io.Writer, full lapi.FullNode, localDeals []lapi.DealInfo, verbose bool, color bool, showFailed bool) error {
sort.Slice(localDeals, func(i, j int) bool {
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
})
@@ -1132,12 +1137,14 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
var deals []deal
for _, localDeal := range localDeals {
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
if showFailed || localDeal.State != storagemarket.StorageDealError {
deals = append(deals, dealFromDealInfo(ctx, full, head, localDeal))
}
}
if verbose {
w := tabwriter.NewWriter(out, 2, 4, 2, ' ', 0)
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tVerified\tMessage\n")
for _, d := range deals {
onChain := "N"
if d.OnChainDealState.SectorStartEpoch != -1 {
@@ -1150,7 +1157,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
}
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%v\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Verified, d.LocalDeal.Message)
}
return w.Flush()
}
@@ -1165,6 +1172,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
tablewriter.Col("Size"),
tablewriter.Col("Price"),
tablewriter.Col("Duration"),
tablewriter.Col("Verified"),
tablewriter.NewLineCol("Message"))
for _, d := range deals {
@@ -1194,6 +1202,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full api.FullNode, l
"PieceCID": piece,
"Size": types.SizeStr(types.NewInt(d.LocalDeal.Size)),
"Price": price,
"Verified": d.LocalDeal.Verified,
"Duration": d.LocalDeal.Duration,
"Message": d.LocalDeal.Message,
})
+21 -50
View File
@@ -11,8 +11,6 @@ import (
logging "github.com/ipfs/go-log/v2"
"github.com/mitchellh/go-homedir"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
@@ -20,6 +18,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/filecoin-project/lotus/node/repo"
)
@@ -46,37 +45,16 @@ func NewCliError(s string) error {
// ApiConnector returns API instance
type ApiConnector func() api.FullNode
type APIInfo struct {
Addr multiaddr.Multiaddr
Token []byte
}
func (a APIInfo) DialArgs() (string, error) {
_, addr, err := manet.DialArgs(a.Addr)
return "ws://" + addr + "/rpc/v0", err
}
func (a APIInfo) AuthHeader() http.Header {
if len(a.Token) != 0 {
headers := http.Header{}
headers.Add("Authorization", "Bearer "+string(a.Token))
return headers
}
log.Warn("API Token not set and requested, capabilities might be limited.")
return nil
}
// The flag passed on the command line with the listen address of the API
// server (only used by the tests)
func flagForAPI(t repo.RepoType) string {
switch t {
case repo.FullNode:
return "api"
return "api-url"
case repo.StorageMiner:
return "miner-api"
return "miner-api-url"
case repo.Worker:
return "worker-api"
return "worker-api-url"
default:
panic(fmt.Sprintf("Unknown repo type: %v", t))
}
@@ -122,7 +100,7 @@ func envForRepoDeprecation(t repo.RepoType) string {
}
}
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (cliutil.APIInfo, error) {
// Check if there was a flag passed with the listen address of the API
// server (only used by the tests)
apiFlag := flagForAPI(t)
@@ -130,11 +108,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
strma := ctx.String(apiFlag)
strma = strings.TrimSpace(strma)
apima, err := multiaddr.NewMultiaddr(strma)
if err != nil {
return APIInfo{}, err
}
return APIInfo{Addr: apima}, nil
return cliutil.APIInfo{Addr: strma}, nil
}
envKey := envForRepo(t)
@@ -148,36 +122,24 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
}
}
if ok {
sp := strings.SplitN(env, ":", 2)
if len(sp) != 2 {
log.Warnf("invalid env(%s) value, missing token or address", envKey)
} else {
ma, err := multiaddr.NewMultiaddr(sp[1])
if err != nil {
return APIInfo{}, xerrors.Errorf("could not parse multiaddr from env(%s): %w", envKey, err)
}
return APIInfo{
Addr: ma,
Token: []byte(sp[0]),
}, nil
}
return cliutil.ParseApiInfo(env), nil
}
repoFlag := flagForRepo(t)
p, err := homedir.Expand(ctx.String(repoFlag))
if err != nil {
return APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err)
return cliutil.APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err)
}
r, err := repo.NewFS(p)
if err != nil {
return APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err)
return cliutil.APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err)
}
ma, err := r.APIEndpoint()
if err != nil {
return APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err)
return cliutil.APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err)
}
token, err := r.APIToken()
@@ -185,8 +147,8 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err)
}
return APIInfo{
Addr: ma,
return cliutil.APIInfo{
Addr: ma.String(),
Token: token,
}, nil
}
@@ -266,6 +228,15 @@ func GetWorkerAPI(ctx *cli.Context) (api.WorkerAPI, jsonrpc.ClientCloser, error)
return client.NewWorkerRPC(ctx.Context, addr, headers)
}
func GetGatewayAPI(ctx *cli.Context) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
addr, headers, err := GetRawAPI(ctx, repo.FullNode)
if err != nil {
return nil, nil, err
}
return client.NewGatewayRPC(ctx.Context, addr, headers)
}
func DaemonContext(cctx *cli.Context) context.Context {
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
return mtCtx.(context.Context)
+1 -1
View File
@@ -35,7 +35,7 @@ func RunApp(app *cli.App) {
if os.Getenv("LOTUS_DEV") != "" {
log.Warnf("%+v", err)
} else {
fmt.Printf("ERROR: %s\n\n", err)
fmt.Fprintf(os.Stderr, "ERROR: %s\n\n", err) // nolint:errcheck
}
var phe *PrintHelpErr
if xerrors.As(err, &phe) {
+44 -5
View File
@@ -3,8 +3,10 @@ package cli
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"reflect"
"sort"
"strconv"
"text/tabwriter"
@@ -14,6 +16,8 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/stmgr"
cbg "github.com/whyrusleeping/cbor-gen"
"github.com/filecoin-project/go-state-types/big"
@@ -174,6 +178,10 @@ var msigInspectCmd = &cli.Command{
Name: "vesting",
Usage: "Include vesting details",
},
&cli.BoolFlag{
Name: "decode-params",
Usage: "Decode parameters of transaction proposals",
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
@@ -204,6 +212,11 @@ var msigInspectCmd = &cli.Command{
return err
}
ownId, err := api.StateLookupID(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
mstate, err := multisig.Load(store, act)
if err != nil {
return err
@@ -256,6 +269,7 @@ var msigInspectCmd = &cli.Command{
return xerrors.Errorf("reading pending transactions: %w", err)
}
decParams := cctx.Bool("decode-params")
fmt.Println("Transactions: ", len(pending))
if len(pending) > 0 {
var txids []int64
@@ -266,11 +280,36 @@ var msigInspectCmd = &cli.Command{
return txids[i] < txids[j]
})
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
w := tabwriter.NewWriter(os.Stdout, 8, 4, 2, ' ', 0)
fmt.Fprintf(w, "ID\tState\tApprovals\tTo\tValue\tMethod\tParams\n")
for _, txid := range txids {
tx := pending[txid]
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, "pending", len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
target := tx.To.String()
if tx.To == ownId {
target += " (self)"
}
targAct, err := api.StateGetActor(ctx, tx.To, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("failed to resolve 'To' address of multisig transaction %d: %w", txid, err)
}
method := stmgr.MethodsMap[targAct.Code][tx.Method]
paramStr := fmt.Sprintf("%x", tx.Params)
if decParams && tx.Method != 0 {
ptyp := reflect.New(method.Params.Elem()).Interface().(cbg.CBORUnmarshaler)
if err := ptyp.UnmarshalCBOR(bytes.NewReader(tx.Params)); err != nil {
return xerrors.Errorf("failed to decode parameters of transaction %d: %w", txid, err)
}
b, err := json.Marshal(ptyp)
if err != nil {
return xerrors.Errorf("could not json marshal parameter type: %w", err)
}
paramStr = string(b)
}
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), method.Name, tx.Method, paramStr)
}
if err := w.Flush(); err != nil {
return xerrors.Errorf("flushing output: %+v", err)
@@ -398,7 +437,7 @@ var msigProposeCmd = &cli.Command{
var msigApproveCmd = &cli.Command{
Name: "approve",
Usage: "Approve a multisig message",
ArgsUsage: "[multisigAddress messageId proposerAddress destination value <methodId methodParams> (optional)]",
ArgsUsage: "<multisigAddress messageId> [proposerAddress destination value [methodId methodParams]]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
@@ -484,7 +523,7 @@ var msigApproveCmd = &cli.Command{
from = defaddr
}
msgCid, err := api.MsigApprove(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
msgCid, err := api.MsigApproveTxnHash(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
if err != nil {
return err
}
@@ -1129,7 +1168,7 @@ var msigLockApproveCmd = &cli.Command{
return actErr
}
msgCid, err := api.MsigApprove(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
msgCid, err := api.MsigApproveTxnHash(ctx, msig, txid, prop, msig, big.Zero(), from, uint64(builtin2.MethodsMultisig.LockBalance), params)
if err != nil {
return err
}
+8 -8
View File
@@ -121,13 +121,13 @@ func TestPaymentChannelStatus(t *testing.T) {
create := make(chan string)
go func() {
// creator: paych add-funds <creator> <receiver> <amount>
cmd = []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)}
create <- creatorCLI.runCmd(paychAddFundsCmd, cmd)
}()
// Wait for the output to stop being "Channel does not exist"
for regexp.MustCompile(noChannelState).MatchString(out) {
cmd = []string{creatorAddr.String(), receiverAddr.String()}
cmd := []string{creatorAddr.String(), receiverAddr.String()}
out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd)
}
fmt.Println(out)
@@ -390,7 +390,7 @@ func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
}
func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) {
n, sn := builder.RPCMockSbBuilder(t, 2, test.OneMiner)
n, sn := builder.RPCMockSbBuilder(t, test.TwoFull, test.OneMiner)
paymentCreator := n[0]
paymentReceiver := n[1]
@@ -439,12 +439,12 @@ type mockCLI struct {
}
func newMockCLI(t *testing.T) *mockCLI {
// Create a CLI App with an --api flag so that we can specify which node
// Create a CLI App with an --api-url flag so that we can specify which node
// the command should be executed against
app := cli.NewApp()
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "api",
Name: "api-url",
Hidden: true,
},
}
@@ -476,8 +476,8 @@ func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
}
func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, error) {
// prepend --api=<node api listener address>
apiFlag := "--api=" + c.addr.String()
// prepend --api-url=<node api listener address>
apiFlag := "--api-url=" + c.addr.String()
input = append([]string{apiFlag}, input...)
fs := c.flagSet(cmd)
@@ -493,7 +493,7 @@ func (c *mockCLIClient) runCmdRaw(cmd *cli.Command, input []string) (string, err
}
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
// Apply app level flags (so we can process --api flag)
// Apply app level flags (so we can process --api-url flag)
fs := &flag.FlagSet{}
for _, f := range c.cctx.App.Flags {
err := f.Apply(fs)
+1 -2
View File
@@ -9,7 +9,6 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/node/repo"
manet "github.com/multiformats/go-multiaddr/net"
)
var pprofCmd = &cli.Command{
@@ -37,7 +36,7 @@ var PprofGoroutines = &cli.Command{
if err != nil {
return xerrors.Errorf("could not get API info: %w", err)
}
_, addr, err := manet.DialArgs(ainfo.Addr)
addr, err := ainfo.Host()
if err != nil {
return err
}
+95 -3
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"html/template"
"io"
"io/ioutil"
"os"
"reflect"
"sort"
@@ -32,6 +33,7 @@ import (
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/lotus/api"
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/state"
@@ -70,6 +72,7 @@ var stateCmd = &cli.Command{
stateMsgCostCmd,
stateMinerInfo,
stateMarketCmd,
stateExecTraceCmd,
},
}
@@ -313,6 +316,74 @@ var stateActiveSectorsCmd = &cli.Command{
},
}
var stateExecTraceCmd = &cli.Command{
Name: "exec-trace",
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"))
}
mcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("message cid was invalid: %s", err)
}
capi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msg, err := capi.ChainGetMessage(ctx, mcid)
if err != nil {
return err
}
lookup, err := capi.StateSearchMsg(ctx, mcid)
if err != nil {
return err
}
ts, err := capi.ChainGetTipSet(ctx, lookup.TipSet)
if err != nil {
return err
}
pts, err := capi.ChainGetTipSet(ctx, ts.Parents())
if err != nil {
return err
}
cso, err := capi.StateCompute(ctx, pts.Height(), nil, pts.Key())
if err != nil {
return err
}
var trace *api.InvocResult
for _, t := range cso.Trace {
if t.Msg.From == msg.From && t.Msg.Nonce == msg.Nonce {
trace = t
break
}
}
if trace == nil {
return fmt.Errorf("failed to find message in tipset trace output")
}
out, err := json.MarshalIndent(trace, "", " ")
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
var stateReplaySetCmd = &cli.Command{
Name: "replay",
Usage: "Replay a particular message within a tipset",
@@ -823,6 +894,10 @@ var stateComputeStateCmd = &cli.Command{
Name: "json",
Usage: "generate json output",
},
&cli.StringFlag{
Name: "compute-state-output",
Usage: "a json file containing pre-existing compute-state output, to generate html reports without rerunning state changes",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
@@ -862,9 +937,26 @@ var stateComputeStateCmd = &cli.Command{
}
}
stout, err := api.StateCompute(ctx, h, msgs, ts.Key())
if err != nil {
return err
var stout *lapi.ComputeStateOutput
if csofile := cctx.String("compute-state-output"); csofile != "" {
data, err := ioutil.ReadFile(csofile)
if err != nil {
return err
}
var o lapi.ComputeStateOutput
if err := json.Unmarshal(data, &o); err != nil {
return err
}
stout = &o
} else {
o, err := api.StateCompute(ctx, h, msgs, ts.Key())
if err != nil {
return err
}
stout = o
}
if cctx.Bool("json") {
+21 -5
View File
@@ -122,8 +122,14 @@ var syncMarkBadCmd = &cli.Command{
}
var syncUnmarkBadCmd = &cli.Command{
Name: "unmark-bad",
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
Name: "unmark-bad",
Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "all",
Usage: "drop the entire bad block cache",
},
},
ArgsUsage: "[blockCid]",
Action: func(cctx *cli.Context) error {
napi, closer, err := GetFullNodeAPI(cctx)
@@ -133,6 +139,10 @@ var syncUnmarkBadCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if cctx.Bool("all") {
return napi.SyncUnmarkAllBad(ctx)
}
if !cctx.Args().Present() {
return fmt.Errorf("must specify block cid to unmark")
}
@@ -233,7 +243,13 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
samples := 8
i := 0
var app, lastApp uint64
var firstApp, app, lastApp uint64
state, err := napi.SyncState(ctx)
if err != nil {
return err
}
firstApp = state.VMApplied
for {
state, err := napi.SyncState(ctx)
@@ -286,10 +302,10 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
if i%samples == 0 {
lastApp = app
app = state.VMApplied
app = state.VMApplied - firstApp
}
if i > 0 {
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
fmt.Printf("Validated %d messages (%d per second)\n", state.VMApplied-firstApp, (app-lastApp)*uint64(time.Second/tick)/uint64(samples))
lastLines++
}
+83
View File
@@ -0,0 +1,83 @@
package cliutil
import (
"net/http"
"net/url"
"regexp"
"strings"
logging "github.com/ipfs/go-log/v2"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)
var log = logging.Logger("cliutil")
var (
infoWithToken = regexp.MustCompile("^[a-zA-Z0-9\\-_]+?\\.[a-zA-Z0-9\\-_]+?\\.([a-zA-Z0-9\\-_]+)?:.+$")
)
type APIInfo struct {
Addr string
Token []byte
}
func ParseApiInfo(s string) APIInfo {
var tok []byte
if infoWithToken.Match([]byte(s)) {
sp := strings.SplitN(s, ":", 2)
tok = []byte(sp[0])
s = sp[1]
}
return APIInfo{
Addr: s,
Token: tok,
}
}
func (a APIInfo) DialArgs() (string, error) {
ma, err := multiaddr.NewMultiaddr(a.Addr)
if err == nil {
_, addr, err := manet.DialArgs(ma)
if err != nil {
return "", err
}
return "ws://" + addr + "/rpc/v0", nil
}
_, err = url.Parse(a.Addr)
if err != nil {
return "", err
}
return a.Addr + "/rpc/v0", nil
}
func (a APIInfo) Host() (string, error) {
ma, err := multiaddr.NewMultiaddr(a.Addr)
if err == nil {
_, addr, err := manet.DialArgs(ma)
if err != nil {
return "", err
}
return addr, nil
}
spec, err := url.Parse(a.Addr)
if err != nil {
return "", err
}
return spec.Host, nil
}
func (a APIInfo) AuthHeader() http.Header {
if len(a.Token) != 0 {
headers := http.Header{}
headers.Add("Authorization", "Bearer "+string(a.Token))
return headers
}
log.Warn("API Token not set and requested, capabilities might be limited.")
return nil
}
+1 -1
View File
@@ -183,7 +183,7 @@ var importBenchCmd = &cli.Command{
return nil
}
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier))
cs := store.NewChainStore(bs, ds, vm.Syscalls(verifier), nil)
stm := stmgr.NewStateManager(cs)
if cctx.Bool("global-profile") {
+131 -42
View File
@@ -6,85 +6,174 @@ import (
"time"
"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/build"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl/full"
"github.com/ipfs/go-cid"
"go.opencensus.io/trace"
)
const LookbackCap = time.Hour
const (
LookbackCap = time.Hour
stateWaitLookbackLimit = abi.ChainEpoch(20)
)
var (
ErrLookbackTooLong = fmt.Errorf("lookbacks of more than %s are disallowed", LookbackCap)
)
type GatewayAPI struct {
api api.FullNode
// gatewayDepsAPI defines the API methods that the GatewayAPI depends on
// (to make it easy to mock for tests)
type gatewayDepsAPI interface {
ChainHead(ctx context.Context) (*types.TipSet, error)
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error)
}
func (a *GatewayAPI) getTipsetTimestamp(ctx context.Context, tsk types.TipSetKey) (time.Time, error) {
type GatewayAPI struct {
api gatewayDepsAPI
}
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
if tsk.IsEmpty() {
return time.Now(), nil
return nil
}
ts, err := a.api.ChainGetTipSet(ctx, tsk)
if err != nil {
return time.Time{}, err
}
return time.Unix(int64(ts.Blocks()[0].Timestamp), 0), nil
}
func (a *GatewayAPI) checkTipset(ctx context.Context, ts types.TipSetKey) error {
when, err := a.getTipsetTimestamp(ctx, ts)
if err != nil {
return err
}
if time.Since(when) > time.Hour {
return a.checkTipset(ts)
}
func (a *GatewayAPI) checkTipset(ts *types.TipSet) error {
at := time.Unix(int64(ts.Blocks()[0].Timestamp), 0)
if err := a.checkTimestamp(at); err != nil {
return fmt.Errorf("bad tipset: %w", err)
}
return nil
}
func (a *GatewayAPI) checkTipsetHeight(ts *types.TipSet, h abi.ChainEpoch) error {
tsBlock := ts.Blocks()[0]
heightDelta := time.Duration(uint64(tsBlock.Height-h)*build.BlockDelaySecs) * time.Second
timeAtHeight := time.Unix(int64(tsBlock.Timestamp), 0).Add(-heightDelta)
if err := a.checkTimestamp(timeAtHeight); err != nil {
return fmt.Errorf("bad tipset height: %w", err)
}
return nil
}
func (a *GatewayAPI) checkTimestamp(at time.Time) error {
if time.Since(at) > LookbackCap {
return ErrLookbackTooLong
}
return nil
}
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
ctx, span := trace.StartSpan(ctx, "StateGetActor")
defer span.End()
if err := a.checkTipset(ctx, ts); err != nil {
return nil, fmt.Errorf("bad tipset: %w", err)
}
return a.api.StateGetActor(ctx, actor, ts)
}
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
ctx, span := trace.StartSpan(ctx, "ChainHead")
defer span.End()
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
return a.api.ChainHead(ctx)
}
func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
ctx, span := trace.StartSpan(ctx, "ChainGetTipSet")
defer span.End()
if err := a.checkTipset(ctx, tsk); err != nil {
return nil, fmt.Errorf("bad tipset: %w", err)
}
// TODO: since we're limiting lookbacks, should just cache this (could really even cache the json response bytes)
return a.api.ChainGetTipSet(ctx, tsk)
}
func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
ts, err := a.api.ChainGetTipSet(ctx, tsk)
if err != nil {
return nil, err
}
// Check if the tipset key refers to a tipset that's too far in the past
if err := a.checkTipset(ts); err != nil {
return nil, err
}
// Check if the height is too far in the past
if err := a.checkTipsetHeight(ts, h); err != nil {
return nil, err
}
return a.api.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (a *GatewayAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.GasEstimateMessageGas(ctx, msg, spec, tsk)
}
func (a *GatewayAPI) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
ctx, span := trace.StartSpan(ctx, "MpoolPush")
defer span.End()
// TODO: additional anti-spam checks
return a.api.MpoolPushUntrusted(ctx, sm)
}
func (a *GatewayAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return types.NewInt(0), err
}
return a.api.MsigGetAvailableBalance(ctx, addr, tsk)
}
func (a *GatewayAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
if err := a.checkTipsetKey(ctx, start); err != nil {
return types.NewInt(0), err
}
if err := a.checkTipsetKey(ctx, end); err != nil {
return types.NewInt(0), err
}
return a.api.MsigGetVested(ctx, addr, start, end)
}
func (a *GatewayAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return address.Undef, err
}
return a.api.StateAccountKey(ctx, addr, tsk)
}
func (a *GatewayAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.StateGetActor(ctx, actor, tsk)
}
func (a *GatewayAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return address.Undef, err
}
return a.api.StateLookupID(ctx, addr, tsk)
}
func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return a.api.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit)
}
var _ api.GatewayAPI = (*GatewayAPI)(nil)
var _ full.ChainModuleAPI = (*GatewayAPI)(nil)
var _ full.GasModuleAPI = (*GatewayAPI)(nil)
var _ full.MpoolModuleAPI = (*GatewayAPI)(nil)
var _ full.StateModuleAPI = (*GatewayAPI)(nil)
+191
View File
@@ -0,0 +1,191 @@
package main
import (
"context"
"sync"
"testing"
"time"
"github.com/filecoin-project/lotus/build"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/lotus/chain/types/mock"
"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/types"
"github.com/ipfs/go-cid"
)
func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
ctx := context.Background()
lookbackTimestamp := uint64(time.Now().Unix()) - uint64(LookbackCap.Seconds())
type args struct {
h abi.ChainEpoch
tskh abi.ChainEpoch
genesisTS uint64
}
tests := []struct {
name string
args args
expErr bool
}{{
name: "basic",
args: args{
h: abi.ChainEpoch(1),
tskh: abi.ChainEpoch(5),
},
}, {
name: "genesis",
args: args{
h: abi.ChainEpoch(0),
tskh: abi.ChainEpoch(5),
},
}, {
name: "same epoch as tipset",
args: args{
h: abi.ChainEpoch(5),
tskh: abi.ChainEpoch(5),
},
}, {
name: "tipset too old",
args: args{
// Tipset height is 5, genesis is at LookbackCap - 10 epochs.
// So resulting tipset height will be 5 epochs earlier than LookbackCap.
h: abi.ChainEpoch(1),
tskh: abi.ChainEpoch(5),
genesisTS: lookbackTimestamp - build.BlockDelaySecs*10,
},
expErr: true,
}, {
name: "lookup height too old",
args: args{
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap - 3 epochs.
// So
// - lookup height will be 2 epochs earlier than LookbackCap.
// - tipset height will be 2 epochs later than LookbackCap.
h: abi.ChainEpoch(1),
tskh: abi.ChainEpoch(5),
genesisTS: lookbackTimestamp - build.BlockDelaySecs*3,
},
expErr: true,
}, {
name: "tipset and lookup height within acceptable range",
args: args{
// Tipset height is 5, lookup height is 1, genesis is at LookbackCap.
// So
// - lookup height will be 1 epoch later than LookbackCap.
// - tipset height will be 5 epochs later than LookbackCap.
h: abi.ChainEpoch(1),
tskh: abi.ChainEpoch(5),
genesisTS: lookbackTimestamp,
},
}}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
mock := &mockGatewayDepsAPI{}
a := &GatewayAPI{api: mock}
// Create tipsets from genesis up to tskh and return the highest
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
got, err := a.ChainGetTipSetByHeight(ctx, tt.args.h, ts.Key())
if tt.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.args.h, got.Height())
}
})
}
}
type mockGatewayDepsAPI struct {
lk sync.RWMutex
tipsets []*types.TipSet
}
func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
m.lk.RLock()
defer m.lk.RUnlock()
return m.tipsets[len(m.tipsets)-1], nil
}
func (m *mockGatewayDepsAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
m.lk.RLock()
defer m.lk.RUnlock()
for _, ts := range m.tipsets {
if ts.Key() == tsk {
return ts, nil
}
}
return nil, nil
}
// createTipSets creates tipsets from genesis up to tskh and returns the highest
func (m *mockGatewayDepsAPI) createTipSets(h abi.ChainEpoch, genesisTimestamp uint64) *types.TipSet {
m.lk.Lock()
defer m.lk.Unlock()
targeth := h + 1 // add one for genesis block
if genesisTimestamp == 0 {
genesisTimestamp = uint64(time.Now().Unix()) - build.BlockDelaySecs*uint64(targeth)
}
var currts *types.TipSet
for currh := abi.ChainEpoch(0); currh < targeth; currh++ {
blks := mock.MkBlock(currts, 1, 1)
if currh == 0 {
blks.Timestamp = genesisTimestamp
}
currts = mock.TipSet(blks)
m.tipsets = append(m.tipsets, currts)
}
return m.tipsets[len(m.tipsets)-1]
}
func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
m.lk.Lock()
defer m.lk.Unlock()
return m.tipsets[h], nil
}
func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) MpoolPushUntrusted(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
panic("implement me")
}
+211
View File
@@ -0,0 +1,211 @@
package main
import (
"bytes"
"context"
"fmt"
"os"
"testing"
"time"
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/client"
"github.com/filecoin-project/lotus/api/test"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/node"
builder "github.com/filecoin-project/lotus/node/test"
)
func init() {
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
}
// TestEndToEnd tests that API calls can be made on a lite node that is
// connected through a gateway to a full API node
func TestEndToEnd(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
blocktime := 5 * time.Millisecond
ctx := context.Background()
full, lite, closer := startNodes(ctx, t, blocktime)
defer closer()
// The full node starts with a wallet
fullWalletAddr, err := full.WalletDefaultAddress(ctx)
require.NoError(t, err)
// Check the full node's wallet balance from the lite node
balance, err := lite.WalletBalance(ctx, fullWalletAddr)
require.NoError(t, err)
fmt.Println(balance)
// Create a wallet on the lite node
liteWalletAddr, err := lite.WalletNew(ctx, wallet.ActSigType("secp256k1"))
require.NoError(t, err)
// Send some funds from the full node to the lite node
err = sendFunds(ctx, t, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18))
require.NoError(t, err)
// Send some funds from the lite node back to the full node
err = sendFunds(ctx, t, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
require.NoError(t, err)
// Sign some data with the lite node wallet address
data := []byte("hello")
sig, err := lite.WalletSign(ctx, liteWalletAddr, data)
require.NoError(t, err)
// Verify the signature
ok, err := lite.WalletVerify(ctx, liteWalletAddr, data, sig)
require.NoError(t, err)
require.True(t, ok)
// Create some wallets on the lite node to use for testing multisig
var walletAddrs []address.Address
for i := 0; i < 4; i++ {
addr, err := lite.WalletNew(ctx, wallet.ActSigType("secp256k1"))
require.NoError(t, err)
walletAddrs = append(walletAddrs, addr)
err = sendFunds(ctx, t, lite, liteWalletAddr, addr, types.NewInt(1e15))
require.NoError(t, err)
}
// Create an msig with three of the addresses and threshold of two sigs
msigAddrs := walletAddrs[:3]
amt := types.NewInt(1000)
addProposal, err := lite.MsigCreate(ctx, 2, msigAddrs, abi.ChainEpoch(50), amt, liteWalletAddr, types.NewInt(0))
require.NoError(t, err)
res, err := lite.StateWaitMsg(ctx, addProposal, 1)
require.NoError(t, err)
require.EqualValues(t, 0, res.Receipt.ExitCode)
var execReturn init0.ExecReturn
err = execReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
require.NoError(t, err)
// Get available balance of msig: should be greater than zero and less
// than initial amount
msig := execReturn.IDAddress
msigBalance, err := lite.MsigGetAvailableBalance(ctx, msig, types.EmptyTSK)
require.NoError(t, err)
require.Greater(t, msigBalance.Int64(), int64(0))
require.Less(t, msigBalance.Int64(), amt.Int64())
// Propose to add a new address to the msig
addProposal, err = lite.MsigAddPropose(ctx, msig, walletAddrs[0], walletAddrs[3], false)
require.NoError(t, err)
res, err = lite.StateWaitMsg(ctx, addProposal, 1)
require.NoError(t, err)
require.EqualValues(t, 0, res.Receipt.ExitCode)
var proposeReturn multisig.ProposeReturn
err = proposeReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
require.NoError(t, err)
// Approve proposal (proposer is first (implicit) signer, approver is
// second signer
txnID := uint64(proposeReturn.TxnID)
approval1, err := lite.MsigAddApprove(ctx, msig, walletAddrs[1], txnID, walletAddrs[0], walletAddrs[3], false)
require.NoError(t, err)
res, err = lite.StateWaitMsg(ctx, approval1, 1)
require.NoError(t, err)
require.EqualValues(t, 0, res.Receipt.ExitCode)
var approveReturn multisig.ApproveReturn
err = approveReturn.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))
require.NoError(t, err)
require.True(t, approveReturn.Applied)
}
func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error {
msg := &types.Message{
From: fromAddr,
To: toAddr,
Value: amt,
}
sm, err := fromNode.MpoolPushMessage(ctx, msg, nil)
if err != nil {
return err
}
res, err := fromNode.StateWaitMsg(ctx, sm.Cid(), 1)
if err != nil {
return err
}
if res.Receipt.ExitCode != 0 {
return xerrors.Errorf("send funds failed with exit code %d", res.Receipt.ExitCode)
}
return nil
}
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
var closer jsonrpc.ClientCloser
// Create one miner and two full nodes.
// - Put a gateway server in front of full node 1
// - Start full node 2 in lite mode
// - Connect lite node -> gateway server -> full node
opts := append(
// Full node
test.OneFull,
// Lite node
test.FullNodeOpts{
Lite: true,
Opts: func(nodes []test.TestNode) node.Option {
fullNode := nodes[0]
// Create a gateway server in front of the full node
_, addr, err := builder.CreateRPCServer(&GatewayAPI{api: fullNode})
require.NoError(t, err)
// Create a gateway client API that connects to the gateway server
var gapi api.GatewayAPI
gapi, closer, err = client.NewGatewayRPC(ctx, addr, nil)
require.NoError(t, err)
// Provide the gateway API to dependency injection
return node.Override(new(api.GatewayAPI), gapi)
},
},
)
n, sn := builder.RPCMockSbBuilder(t, opts, test.OneMiner)
full := n[0]
lite := n[1]
miner := sn[0]
// Get the listener address for the full node
fullAddr, err := full.NetAddrsListen(ctx)
require.NoError(t, err)
// Connect the miner and the full node
err = miner.NetConnect(ctx, fullAddr)
require.NoError(t, err)
// Start mining blocks
bm := test.NewBlockMiner(ctx, t, miner, blocktime)
bm.MineBlocks()
return full, lite, closer
}
+2 -2
View File
@@ -40,12 +40,12 @@ func main() {
return fmt.Errorf("unrecognized key type: %q", cctx.String("type"))
}
kaddr, err := w.GenerateKey(kt)
kaddr, err := w.WalletNew(cctx.Context, kt)
if err != nil {
return err
}
ki, err := w.Export(kaddr)
ki, err := w.WalletExport(cctx.Context, kaddr)
if err != nil {
return err
}
+202 -82
View File
@@ -15,6 +15,7 @@ import (
"time"
"github.com/filecoin-project/lotus/chain/actors/builtin"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
@@ -37,6 +38,7 @@ import (
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/tools/stats"
@@ -342,6 +344,18 @@ var runCmd = &cli.Command{
Usage: "process ProveCommitSector messages",
Value: true,
},
&cli.BoolFlag{
Name: "windowed-post",
EnvVars: []string{"LOTUS_PCR_WINDOWED_POST"},
Usage: "process SubmitWindowedPoSt messages and refund gas fees",
Value: false,
},
&cli.BoolFlag{
Name: "storage-deals",
EnvVars: []string{"LOTUS_PCR_STORAGE_DEALS"},
Usage: "process PublishStorageDeals messages and refund gas fees",
Value: false,
},
&cli.IntFlag{
Name: "head-delay",
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
@@ -378,6 +392,18 @@ var runCmd = &cli.Command{
Usage: "percent of refund to issue",
Value: 110,
},
&cli.StringFlag{
Name: "pre-fee-cap-max",
EnvVars: []string{"LOTUS_PCR_PRE_FEE_CAP_MAX"},
Usage: "messages with a fee cap larger than this will be skipped when processing pre commit messages",
Value: "0.000000001",
},
&cli.StringFlag{
Name: "prove-fee-cap-max",
EnvVars: []string{"LOTUS_PCR_PROVE_FEE_CAP_MAX"},
Usage: "messages with a prove cap larger than this will be skipped when processing pre commit messages",
Value: "0.000000001",
},
},
Action: func(cctx *cli.Context) error {
go func() {
@@ -421,6 +447,8 @@ var runCmd = &cli.Command{
dryRun := cctx.Bool("dry-run")
preCommitEnabled := cctx.Bool("pre-commit")
proveCommitEnabled := cctx.Bool("prove-commit")
windowedPoStEnabled := cctx.Bool("windowed-post")
publishStorageDealsEnabled := cctx.Bool("storage-deals")
aggregateTipsets := cctx.Int("aggregate-tipsets")
minerRecoveryEnabled := cctx.Bool("miner-recovery")
minerRecoveryPeriod := abi.ChainEpoch(int64(cctx.Int("miner-recovery-period")))
@@ -428,6 +456,16 @@ var runCmd = &cli.Command{
minerRecoveryCutoff := uint64(cctx.Int("miner-recovery-cutoff"))
minerRecoveryBonus := uint64(cctx.Int("miner-recovery-bonus"))
preFeeCapMax, err := types.ParseFIL(cctx.String("pre-fee-cap-max"))
if err != nil {
return err
}
proveFeeCapMax, err := types.ParseFIL(cctx.String("prove-fee-cap-max"))
if err != nil {
return err
}
rf := &refunder{
api: api,
wallet: from,
@@ -438,6 +476,10 @@ var runCmd = &cli.Command{
dryRun: dryRun,
preCommitEnabled: preCommitEnabled,
proveCommitEnabled: proveCommitEnabled,
windowedPoStEnabled: windowedPoStEnabled,
publishStorageDealsEnabled: publishStorageDealsEnabled,
preFeeCapMax: types.BigInt(preFeeCapMax),
proveFeeCapMax: types.BigInt(proveFeeCapMax),
}
var refunds *MinersRefund = NewMinersRefund()
@@ -589,7 +631,12 @@ type refunder struct {
dryRun bool
preCommitEnabled bool
proveCommitEnabled bool
windowedPoStEnabled bool
publishStorageDealsEnabled bool
threshold big.Int
preFeeCapMax big.Int
proveFeeCapMax big.Int
}
func (r *refunder) FindMiners(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, owner, worker, control bool) (*MinersRefund, error) {
@@ -817,6 +864,147 @@ func (r *refunder) EnsureMinerMinimums(ctx context.Context, tipset *types.TipSet
return refunds, nil
}
func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
m := msg.Message
refundValue := types.NewInt(0)
var messageMethod string
switch m.Method {
case builtin0.MethodsMarket.PublishStorageDeals:
if !r.publishStorageDealsEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "PublishStorageDeals"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
}
return true, messageMethod, refundValue, nil
}
func (r *refunder) processTipsetStorageMinerActor(ctx context.Context, tipset *types.TipSet, msg api.Message, recp *types.MessageReceipt) (bool, string, types.BigInt, error) {
m := msg.Message
refundValue := types.NewInt(0)
var messageMethod string
switch m.Method {
case builtin0.MethodsMiner.SubmitWindowedPoSt:
if !r.windowedPoStEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "SubmitWindowedPoSt"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
case builtin0.MethodsMiner.ProveCommitSector:
if !r.proveCommitEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "ProveCommitSector"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
if m.GasFeeCap.GreaterThan(r.proveFeeCapMax) {
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.proveFeeCapMax)
return false, messageMethod, types.NewInt(0), nil
}
var sn abi.SectorNumber
var proveCommitSector miner0.ProveCommitSectorParams
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
return false, messageMethod, types.NewInt(0), nil
}
sn = proveCommitSector.SectorNumber
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
if err != nil {
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
if err != nil {
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
if err != nil {
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
if collateral.LessThan(big.Zero()) {
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = collateral
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
}
case builtin0.MethodsMiner.PreCommitSector:
if !r.preCommitEnabled {
return false, messageMethod, types.NewInt(0), nil
}
messageMethod = "PreCommitSector"
if recp.ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recp.ExitCode)
return false, messageMethod, types.NewInt(0), nil
}
if m.GasFeeCap.GreaterThan(r.preFeeCapMax) {
log.Debugw("skipping high fee cap message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "gas_fee_cap", m.GasFeeCap, "fee_cap_max", r.preFeeCapMax)
return false, messageMethod, types.NewInt(0), nil
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
return false, messageMethod, types.NewInt(0), nil
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
return false, messageMethod, types.NewInt(0), nil
}
refundValue = collateral
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
}
default:
return false, messageMethod, types.NewInt(0), nil
}
return true, messageMethod, refundValue, nil
}
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) {
cids := tipset.Cids()
if len(cids) == 0 {
@@ -841,9 +1029,9 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
return nil, nil
}
refundValue := types.NewInt(0)
tipsetRefunds := NewMinersRefund()
for i, msg := range msgs {
refundValue := types.NewInt(0)
m := msg.Message
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
@@ -852,91 +1040,23 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refu
continue
}
if !builtin.IsStorageMinerActor(a.Code) {
continue
}
var messageMethod string
var processed bool
switch m.Method {
case builtin0.MethodsMiner.ProveCommitSector:
if !r.proveCommitEnabled {
continue
}
messageMethod = "ProveCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var sn abi.SectorNumber
var proveCommitSector miner0.ProveCommitSectorParams
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
sn = proveCommitSector.SectorNumber
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, sn, tipset.Parents())
if err != nil {
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
if err != nil {
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
if err != nil {
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
}
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
if collateral.LessThan(big.Zero()) {
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", sn)
continue
}
refundValue = collateral
case builtin0.MethodsMiner.PreCommitSector:
if !r.preCommitEnabled {
continue
}
messageMethod = "PreCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
continue
}
refundValue = collateral
default:
continue
if m.To == market.Address {
processed, messageMethod, refundValue, err = r.processTipsetStorageMarketActor(ctx, tipset, msg, recps[i])
}
if r.refundPercent > 0 {
refundValue = types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.refundPercent)))
if builtin.IsStorageMinerActor(a.Code) {
processed, messageMethod, refundValue, err = r.processTipsetStorageMinerActor(ctx, tipset, msg, recps[i])
}
if err != nil {
log.Errorw("error while processing message", "cid", msg.Cid)
continue
}
if !processed {
continue
}
log.Debugw(
+61 -27
View File
@@ -7,6 +7,7 @@ import (
"github.com/docker/go-units"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"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"
@@ -33,16 +34,19 @@ import (
)
type accountInfo struct {
Address address.Address
Balance types.FIL
Type string
Power abi.StoragePower
Worker address.Address
Owner address.Address
InitialPledge types.FIL
PreCommits types.FIL
LockedFunds types.FIL
Sectors uint64
Address address.Address
Balance types.FIL
Type string
Power abi.StoragePower
Worker address.Address
Owner address.Address
InitialPledge types.FIL
PreCommits types.FIL
LockedFunds types.FIL
Sectors uint64
VestingStart abi.ChainEpoch
VestingDuration abi.ChainEpoch
VestingAmount types.FIL
}
var auditsCmd = &cli.Command{
@@ -115,10 +119,8 @@ var chainBalanceCmd = &cli.Command{
infos = append(infos, ai)
}
fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n")
for _, acc := range infos {
fmt.Printf("%s,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Power, acc.Worker, acc.Owner)
}
printAccountInfos(infos, false)
return nil
},
}
@@ -171,7 +173,7 @@ var chainBalanceStateCmd = &cli.Command{
bs := blockstore.NewBlockstore(ds)
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
cst := cbor.NewCborStore(bs)
store := adt.WrapStore(ctx, cst)
@@ -196,6 +198,7 @@ var chainBalanceStateCmd = &cli.Command{
LockedFunds: types.FIL(big.NewInt(0)),
InitialPledge: types.FIL(big.NewInt(0)),
PreCommits: types.FIL(big.NewInt(0)),
VestingAmount: types.FIL(big.NewInt(0)),
}
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
@@ -234,6 +237,32 @@ var chainBalanceStateCmd = &cli.Command{
ai.Worker = minfo.Worker
ai.Owner = minfo.Owner
}
if builtin.IsMultisigActor(act.Code) {
mst, err := multisig.Load(store, act)
if err != nil {
return err
}
ai.VestingStart, err = mst.StartEpoch()
if err != nil {
return err
}
ib, err := mst.InitialBalance()
if err != nil {
return err
}
ai.VestingAmount = types.FIL(ib)
ai.VestingDuration, err = mst.UnlockDuration()
if err != nil {
return err
}
}
infos = append(infos, ai)
return nil
})
@@ -241,22 +270,27 @@ var chainBalanceStateCmd = &cli.Command{
return xerrors.Errorf("failed to loop over actors: %w", err)
}
if minerInfo {
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n")
for _, acc := range infos {
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge, acc.LockedFunds, acc.PreCommits)
}
} else {
fmt.Printf("Address,Balance,Type\n")
for _, acc := range infos {
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance, acc.Type)
}
}
printAccountInfos(infos, minerInfo)
return nil
},
}
func printAccountInfos(infos []accountInfo, minerInfo bool) {
if minerInfo {
fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits,VestingStart,VestingDuration,VestingAmount\n")
for _, acc := range infos {
fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s,%d,%d,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge.Unitless(), acc.LockedFunds.Unitless(), acc.PreCommits.Unitless(), acc.VestingStart, acc.VestingDuration, acc.VestingAmount.Unitless())
}
} else {
fmt.Printf("Address,Balance,Type\n")
for _, acc := range infos {
fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance.Unitless(), acc.Type)
}
}
}
var chainPledgeCmd = &cli.Command{
Name: "stateroot-pledge",
Description: "Calculate sector pledge numbers",
@@ -309,7 +343,7 @@ var chainPledgeCmd = &cli.Command{
bs := blockstore.NewBlockstore(ds)
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
cst := cbor.NewCborStore(bs)
store := adt.WrapStore(ctx, cst)
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
cliutil "github.com/filecoin-project/lotus/cli/util"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2"
@@ -111,7 +112,7 @@ var consensusCheckCmd = &cli.Command{
if err != nil {
return err
}
ainfo := lcli.APIInfo{Addr: apima}
ainfo := cliutil.APIInfo{Addr: apima.String()}
addr, err := ainfo.DialArgs()
if err != nil {
return err
+1 -1
View File
@@ -83,7 +83,7 @@ var exportChainCmd = &cli.Command{
bs := blockstore.NewBlockstore(ds)
cs := store.NewChainStore(bs, mds, nil)
cs := store.NewChainStore(bs, mds, nil, nil)
if err := cs.Load(); err != nil {
return err
}
+1 -1
View File
@@ -52,7 +52,7 @@ var genesisVerifyCmd = &cli.Command{
}
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), nil)
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), nil, nil)
cf := cctx.Args().Get(0)
f, err := os.Open(cf)
+2 -2
View File
@@ -105,7 +105,7 @@ var keyinfoVerifyCmd = &cli.Command{
return err
}
if _, err := w.Import(&keyInfo); err != nil {
if _, err := w.WalletImport(cctx.Context, &keyInfo); err != nil {
return err
}
@@ -220,7 +220,7 @@ var keyinfoImportCmd = &cli.Command{
return err
}
addr, err := w.Import(&keyInfo)
addr, err := w.WalletImport(cctx.Context, &keyInfo)
if err != nil {
return err
}
+28 -5
View File
@@ -5,6 +5,8 @@ import (
"math"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/chain/types"
@@ -32,6 +34,10 @@ var noncefix = &cli.Command{
&cli.BoolFlag{
Name: "auto",
},
&cli.Int64Flag{
Name: "gas-fee-cap",
Usage: "specify gas fee cap for nonce filling messages",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetFullNodeAPI(cctx)
@@ -84,15 +90,32 @@ var noncefix = &cli.Command{
}
fmt.Printf("Creating %d filler messages (%d ~ %d)\n", end-start, start, end)
ts, err := api.ChainHead(ctx)
if err != nil {
return err
}
feeCap := big.Mul(ts.Blocks()[0].ParentBaseFee, big.NewInt(2)) // default fee cap to 2 * parent base fee
if fcf := cctx.Int64("gas-fee-cap"); fcf != 0 {
feeCap = abi.NewTokenAmount(fcf)
}
for i := start; i < end; i++ {
msg := &types.Message{
From: addr,
To: addr,
Value: types.NewInt(1),
Nonce: i,
From: addr,
To: addr,
Value: types.NewInt(0),
Nonce: i,
GasLimit: 1000000,
GasFeeCap: feeCap,
GasPremium: abi.NewTokenAmount(5),
}
smsg, err := api.WalletSignMessage(ctx, addr, msg)
if err != nil {
return err
}
_, err = api.MpoolPushMessage(ctx, msg, nil)
_, err = api.MpoolPush(ctx, smsg)
if err != nil {
return err
}
+1 -1
View File
@@ -162,7 +162,7 @@ var stateTreePruneCmd = &cli.Command{
bs := blockstore.NewBlockstore(ds)
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier))
cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier), nil)
if err := cs.Load(); err != nil {
return fmt.Errorf("loading chainstore: %w", err)
}
+2 -4
View File
@@ -5,8 +5,6 @@ import (
"testing"
"time"
"github.com/filecoin-project/lotus/node"
logging "github.com/ipfs/go-log/v2"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
@@ -64,8 +62,8 @@ func TestMinerAllInfo(t *testing.T) {
require.NoError(t, infoAllCmd.Action(cctx))
}
bp := func(t *testing.T, nFull int, storage []test.StorageMiner, opts ...node.Option) ([]test.TestNode, []test.TestStorageNode) {
n, sn = builder.Builder(t, nFull, storage, opts...)
bp := func(t *testing.T, fullOpts []test.FullNodeOpts, storage []test.StorageMiner) ([]test.TestNode, []test.TestStorageNode) {
n, sn = builder.Builder(t, fullOpts, storage)
t.Run("pre-info-all", run)
+3 -4
View File
@@ -464,13 +464,12 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
return err
}
if jrnl, err := journal.OpenFSJournal(lr, journal.DefaultDisabledEvents); err == nil {
journal.J = jrnl
} else {
j, err := journal.OpenFSJournal(lr, journal.EnvDisabledEvents())
if err != nil {
return fmt.Errorf("failed to open filesystem journal: %w", err)
}
m := miner.NewMiner(api, epp, a, slashfilter.New(mds))
m := miner.NewMiner(api, epp, a, slashfilter.New(mds), j)
{
if err := m.Start(ctx); err != nil {
return xerrors.Errorf("failed to start up genesis miner: %w", err)
+15 -8
View File
@@ -154,14 +154,14 @@ var setAskCmd = &cli.Command{
Name: "set-ask",
Usage: "Configure the miner's ask",
Flags: []cli.Flag{
&cli.Uint64Flag{
&cli.StringFlag{
Name: "price",
Usage: "Set the price of the ask for unverified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
Usage: "Set the price of the ask for unverified deals (specified as FIL / GiB / Epoch) to `PRICE`.",
Required: true,
},
&cli.Uint64Flag{
&cli.StringFlag{
Name: "verified-price",
Usage: "Set the price of the ask for verified deals (specified as attoFIL / GiB / Epoch) to `PRICE`",
Usage: "Set the price of the ask for verified deals (specified as FIL / GiB / Epoch) to `PRICE`",
Required: true,
},
&cli.StringFlag{
@@ -185,8 +185,15 @@ var setAskCmd = &cli.Command{
}
defer closer()
pri := types.NewInt(cctx.Uint64("price"))
vpri := types.NewInt(cctx.Uint64("verified-price"))
pri, err := types.ParseFIL(cctx.String("price"))
if err != nil {
return err
}
vpri, err := types.ParseFIL(cctx.String("verified-price"))
if err != nil {
return err
}
dur, err := time.ParseDuration("720h0m0s")
if err != nil {
@@ -229,7 +236,7 @@ var setAskCmd = &cli.Command{
return xerrors.Errorf("max piece size (w/bit-padding) %s cannot exceed miner sector size %s", types.SizeStr(types.NewInt(uint64(max))), types.SizeStr(types.NewInt(uint64(smax))))
}
return api.MarketSetAsk(ctx, pri, vpri, abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
return api.MarketSetAsk(ctx, types.BigInt(pri), types.BigInt(vpri), abi.ChainEpoch(qty), abi.PaddedPieceSize(min), abi.PaddedPieceSize(max))
},
}
@@ -281,7 +288,7 @@ var getAskCmd = &cli.Command{
rem = (time.Second * time.Duration(int64(dlt)*int64(build.BlockDelaySecs))).String()
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", ask.Price, ask.VerifiedPrice, types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%s\t%d\n", types.FIL(ask.Price), types.FIL(ask.VerifiedPrice), types.SizeStr(types.NewInt(uint64(ask.MinPieceSize))), types.SizeStr(types.NewInt(uint64(ask.MaxPieceSize))), ask.Expiry, rem, ask.SeqNo)
return w.Flush()
},
+8 -8
View File
@@ -33,7 +33,7 @@ var runCmd = &cli.Command{
Usage: "Start a lotus miner process",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "api",
Name: "miner-api",
Usage: "2345",
},
&cli.BoolFlag{
@@ -61,7 +61,7 @@ var runCmd = &cli.Command{
nodeApi, ncloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
return xerrors.Errorf("getting full node api: %w", err)
}
defer ncloser()
ctx := lcli.DaemonContext(cctx)
@@ -112,29 +112,29 @@ var runCmd = &cli.Command{
node.Online(),
node.Repo(r),
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("api") },
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("miner-api") },
node.Override(new(dtypes.APIEndpoint), func() (dtypes.APIEndpoint, error) {
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("api"))
return multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/" + cctx.String("miner-api"))
})),
node.Override(new(api.FullNode), nodeApi),
)
if err != nil {
return err
return xerrors.Errorf("creating node: %w", err)
}
endpoint, err := r.APIEndpoint()
if err != nil {
return err
return xerrors.Errorf("getting API endpoint: %w", err)
}
// Bootstrap with full node
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
if err != nil {
return err
return xerrors.Errorf("getting full node libp2p address: %w", err)
}
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
return err
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
}
log.Infof("Remote version %s", v)
+23
View File
@@ -31,6 +31,10 @@ const metaFile = "sectorstore.json"
var storageCmd = &cli.Command{
Name: "storage",
Usage: "manage sector storage",
Description: `Sectors can be stored across many filesystem paths. These
commands provide ways to manage the storage the miner will used to store sectors
long term for proving (references as 'store') as well as how sectors will be
stored while moving through the sealing pipeline (references as 'seal').`,
Subcommands: []*cli.Command{
storageAttachCmd,
storageListCmd,
@@ -41,6 +45,25 @@ var storageCmd = &cli.Command{
var storageAttachCmd = &cli.Command{
Name: "attach",
Usage: "attach local storage 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
storage system.
Each storage volume contains a configuration file which describes the
capabilities of the volume. When the '--init' flag is provided, this file will
be created using the additional flags.
Weight
A high weight value means data will be more likely to be stored in this path
Seal
Data for the sealing process will be stored here
Store
Finalized sectors that will be moved here for long term storage and be proven
over time
`,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "init",

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