Compare commits

...
185 Commits
Author SHA1 Message Date
Aayush Rajasekaran 1c6ea75f4b Merge pull request #4456 from filecoin-project/asr/changelog
Lotus version 1.0.0
2020-10-19 20:12:21 -04:00
Aayush Rajasekaran 1ee9fb44e2 Lotus version 1.0.0 2020-10-19 20:09:35 -04:00
Łukasz Magiera 473afc41e7 Merge pull request #4481 from filecoin-project/feat/optim-state-cache
state: optimize state snapshot address cache
2020-10-20 02:03:37 +02:00
Jakub Sztandera a055540c25 Fix lint
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-20 01:32:51 +02:00
Jakub Sztandera cb0513f4c1 Add test
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-20 01:30:40 +02:00
Jakub Sztandera be42dd824b state: optimize state snapshot address cache
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-20 00:43:51 +02:00
Łukasz Magiera 06c0444d45 Merge pull request #4480 from filecoin-project/fix/max-piece-size-reverting-to-default
Don't overwrite previously-configured maxPieceSize for a persisted ask
2020-10-19 22:55:55 +02:00
Łukasz Magiera bae735447d Merge pull request #4477 from filecoin-project/asr/state-api-fix
Fix StateReplay to use provided tipset
2020-10-19 22:54:03 +02:00
Ingar Shu 1974490ab0 Don't overwrite previously-configured maxPieceSize for a persisted ask 2020-10-19 13:12:28 -07:00
Aayush Rajasekaran d24d3e420d Fix StateReplay to use provided tipset 2020-10-19 14:27:04 -04:00
Łukasz Magiera 0f5aa9ba5c Merge pull request #4447 from filecoin-project/feat/mainnet-bootstrap-peers
replace bootstrap peers
2020-10-17 13:27:09 +02:00
Travis Person 4de8f50642 replace bootstrap peers 2020-10-16 19:13:33 +00:00
Łukasz Magiera 4a057d84b8 Merge pull request #4422 from filecoin-project/fix/message-list
fix message list api
2020-10-16 20:52:34 +02:00
Łukasz Magiera 111942b50b Merge pull request #4424 from filecoin-project/feat/retrieval-cli-deal-filter
Custom filters for retrieval deals
2020-10-16 18:41:40 +02:00
Łukasz Magiera 40e34b334a Merge pull request #4423 from filecoin-project/asr/shed-robust
Make audit balances capable of printing robust addresses
2020-10-16 17:52:10 +02:00
Łukasz Magiera 1a049a4f8e Merge pull request #4426 from filecoin-project/feat/lotus-gateway-spacegap
add endpoints needed by spacegap
2020-10-16 17:50:43 +02:00
Ingar Shu d0e4150cea Use separate config for Retrieval Filter 2020-10-16 08:30:55 -07:00
Aayush Rajasekaran 0775c6c9d5 Merge pull request #4429 from filecoin-project/asr/state-apis
Improve StateMsg APIs
2020-10-16 00:51:34 -04:00
Aayush Rajasekaran 2fd4a97698 Remove StateTransplant, modify StateReplay 2020-10-15 22:54:29 -04:00
Aayush Rajasekaran 89f46cb5cc Make ApplyRet's GasOutputs a pointer, return nil when unused 2020-10-15 21:20:53 -04:00
Aayush Rajasekaran 6f86b95f62 Remove StateMsgGasCost 2020-10-15 21:03:02 -04:00
whyrusleeping a71fbee2d1 bump lookback limit to 12 hours 2020-10-15 16:49:25 -07:00
Aayush Rajasekaran 99c07703f8 Add a new StateReplay CLI/API endpoint 2020-10-15 19:47:02 -04:00
whyrusleeping af1a422ddd statevminternal circ supply 2020-10-15 16:36:45 -07:00
whyrusleeping 8351420404 Add more endpoints for spacegap 2020-10-15 16:27:49 -07:00
Aayush Rajasekaran 7826cc0bab Rename StateReplay to StateTransplant 2020-10-15 19:14:53 -04:00
Aayush Rajasekaran cb801d47c7 Add GasCost to InvocResult 2020-10-15 18:48:51 -04:00
whyrusleeping 726eacbe03 add endpoints needed by spacegap 2020-10-15 13:54:58 -07:00
Whyrusleeping 17fcf30edd Merge pull request #4373 from filecoin-project/feat/gateway-wallet-verify
add WalletVerify to lotus-gateway
2020-10-15 15:42:38 -05:00
whyrusleeping eae7d62a2b docsgen 2020-10-15 12:07:41 -07:00
whyrusleeping 5bee85d57a incremental output for list-messages 2020-10-15 09:38:27 -07:00
Ingar Shu 0b7dc6971d Rebasing 2020-10-15 09:33:01 -07:00
Aayush Rajasekaran 8c7d2efe72 Make audit balances capable of printing robust addresses 2020-10-15 12:17:54 -04:00
whyrusleeping a931ff94e9 fix message list api 2020-10-15 08:54:36 -07:00
Łukasz Magiera c56ef260d5 Merge pull request #4421 from filecoin-project/fix/lite-msig-inspect
Ensure msig inspect cli works with lotus-lite
2020-10-15 15:11:34 +02:00
Łukasz Magiera 955d7f9c54 Merge pull request #4393 from filecoin-project/vectors/support-multiple-versions
conformance: support multiple protocol versions.
2020-10-15 14:29:23 +02:00
Raúl Kripalani 1fb9ed1c9a remove TODO. 2020-10-15 12:58:43 +01:00
Raúl Kripalani 7e6ede7563 update schema; test-vectors submodule. 2020-10-15 12:49:23 +01:00
Raúl Kripalani 4e659e30c5 fix lint errors. 2020-10-15 12:14:16 +01:00
Dirk McCormick f5d48b0e86 fix: lotus-gateway api tests 2020-10-15 12:47:24 +02:00
Dirk McCormick f74852bd73 test: add more msig cli tests 2020-10-15 12:45:02 +02:00
Dirk McCormick 9c99171cb8 fix: ensure msig inspect cli works with lotus-lite 2020-10-15 12:15:21 +02:00
Łukasz Magiera 90d2a92a2d Merge pull request #4415 from filecoin-project/feat/use-build-seconds-delay
Use build.BlockDelaySecs for deal start buffer
2020-10-15 11:56:43 +02:00
Łukasz Magiera 2818353418 Merge pull request #4398 from filecoin-project/feat/improve-msig-ux
improve the UX of multisig approves
2020-10-15 11:54:12 +02:00
whyrusleeping ccc780f35a fix wrong index 2020-10-14 23:16:31 -07:00
whyrusleeping fdb115e369 add command to propose changing multisig threshold 2020-10-14 23:10:00 -07:00
whyrusleeping 3bd2e2f777 fix typo 2020-10-14 23:04:15 -07:00
whyrusleeping 6d771d29c7 improve the UX of multisig approves 2020-10-14 23:04:15 -07:00
hannahhoward b29e3b5242 feat(markets): use build.BlockDelaySecs for start buffer
instead of constant from spec-actors which uses hardcoded start epoch, use one that factors in
possibility of different block time
2020-10-14 21:28:36 -07:00
Łukasz Magiera 8340124786 Merge pull request #4411 from filecoin-project/fix/slow-mpool-stortup
mpool: Don't block node startup loading messages
2020-10-15 03:58:36 +02:00
Łukasz Magiera 8f98c7d960 Merge pull request #4410 from filecoin-project/steb/fix-codecov-ignore
Increase code coverage!
2020-10-15 03:37:06 +02:00
Łukasz Magiera 3fb5334959 mpool: Don't block node startup loading messages 2020-10-15 03:36:55 +02:00
Steven Allen a40fc98e56 fix code coverage ignore
It looks like we need to use globs.
2020-10-14 18:21:16 -07:00
Aayush Rajasekaran 8bb84acbc5 Merge pull request #4409 from filecoin-project/asr/changelog
Lotus version 0.10.2
2020-10-14 21:18:53 -04:00
Łukasz Magiera 22f49f8946 Merge pull request #4366 from zgfzgf/feat-applyblocks-map
optimize map use struct{}
2020-10-15 03:04:57 +02:00
Łukasz Magiera 1350079503 Merge pull request #4353 from zgfzgf/feat-compute-tipSet-state
optimize code use ts.Cids
2020-10-15 03:03:39 +02:00
Aayush Rajasekaran 251374eca7 Lotus version 0.10.2 2020-10-14 21:01:26 -04:00
Łukasz Magiera a50a5366b2 Merge pull request #4392 from filecoin-project/daviddias-patch-1
Update SECURITY.md
2020-10-15 02:58:52 +02:00
Łukasz Magiera 52800f5dca Merge pull request #4222 from filecoin-project/feat/increase-inclusion-premium
Change default gas premium to for 10 block inclusion
2020-10-15 02:57:12 +02:00
Łukasz Magiera 958f169267 Merge pull request #4408 from filecoin-project/feat/better-gas-defaults
Improve gas defaults
2020-10-15 02:54:07 +02:00
Jakub Sztandera df6f4a572c Change default gas premium to for 6 block inclusion
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-15 02:53:40 +02:00
Łukasz Magiera 698b49b7ef Improve gas defaults 2020-10-15 02:46:47 +02:00
Łukasz Magiera 7e5b1ac272 Merge pull request #4407 from filecoin-project/steb/fix-blockcache-test-flake
give the TimeCacheBS tests a bit more time
2020-10-15 02:06:11 +02:00
Steven Allen 86e30729bf give the TimeCacheBS tests a bit more time
Otherwise, they flake once in a while.
2020-10-14 16:51:26 -07:00
Łukasz Magiera 7ccb2aabf0 Merge pull request #4406 from filecoin-project/steb/reduce-garbage
reduce garbage in blockstore
2020-10-15 01:49:01 +02:00
Steven Allen 811f1304e6 test timed cache blockstore 2020-10-14 16:17:55 -07:00
Łukasz Magiera 6de82364e9 Merge pull request #4396 from filecoin-project/feat/syncwait-watch
sync wait --watch
2020-10-15 00:14:02 +02:00
Łukasz Magiera d02d4bc275 Merge pull request #4403 from filecoin-project/frrist/fix-miner-shim-impls
fix: return true when deadlines changed
2020-10-15 00:13:36 +02:00
Łukasz Magiera 39670df6af Merge pull request #4125 from filecoin-project/feat/drand-cloudflare
Update drand endpoints
2020-10-15 00:01:06 +02:00
frrist 28823fb8e9 fix: bad indirection of deadline diffing 2020-10-14 14:50:59 -07:00
Steven Allen ddade32bd3 write bitswap blocks into a temporary, in-memory block cache
If they end up validating, we'll write them back to the underlying blockstore.
Otherwise, there's no reason to keep them.
2020-10-14 14:43:58 -07:00
Steven Allen 15fe998c68 add an timed-cache blockstore
This blockstore lets us write to a temporary scratch location where blocks older
than the specified cache time are automatically cleared.
2020-10-14 14:43:58 -07:00
Steven Allen 4b38809c0b in-memory blockstore
Instead of using an in-memory datastore and dealing with the overhead of
computing datastore keys, creating new blocks, etc, use an in-memory blockstore.
2020-10-14 14:43:58 -07:00
Steven Allen e2fbbdcb15 reject messages with invalid CIDs
These can't possibly be valid messages, so we should just drop the block.
2020-10-14 14:43:58 -07:00
Steven Allen bbc6de94fc write messages to a temp blockstore when validating 2020-10-14 14:43:52 -07:00
frrist ea1349205b fix: return true when partitions changed 2020-10-14 14:37:33 -07:00
frrist 470a565c34 fix: return true when deadlines changed 2020-10-14 14:27:35 -07:00
Łukasz Magiera 04bbeface6 Merge pull request #4402 from filecoin-project/feat/upgrade-markets-v0.9.1
Update to 0.9.1 bugfix release
2020-10-14 23:22:17 +02:00
hannahhoward 8df58064e3 feat(markets): update to 0.9.1 bugfix release 2020-10-14 13:20:18 -07:00
Łukasz Magiera 01de4cb2ec Merge pull request #4397 from filecoin-project/revert-4391-feat/https-api
Revert "Add support for /https, /http, /wss API multiaddresses."
2020-10-14 19:56:52 +02:00
Łukasz Magiera b060569fe9 Revert "Add support for /https, /http, /wss API multiaddresses." 2020-10-14 19:55:36 +02:00
Whyrusleeping dfd6fbfaa4 Merge pull request #4311 from filecoin-project/feat/msig-remove-cmd
Add propose remove
2020-10-14 11:36:55 -05:00
Łukasz Magiera d3d304bfd7 Merge pull request #4391 from filecoin-project/feat/https-api
Add support for /https, /http, /wss API multiaddresses.
2020-10-14 18:22:29 +02:00
Łukasz Magiera ab4f051b83 sync wait --watch 2020-10-14 18:17:18 +02:00
Whyrusleepinganddirkmc 12f36c5bda Update cmd/lotus-gateway/api.go
Co-authored-by: dirkmc <dirkmdev@gmail.com>
2020-10-14 09:22:25 -05:00
Raúl Kripalani 45cd510da1 conformance: support multiple protocol versions.
This PR introduces support for running multiple variants of a vector,
each of which targets a unique protocol version.

tvx tooling has been adapted to produce and parse the new version
of the schema.
2020-10-14 14:39:43 +01:00
David Dias 00a5083146 Update SECURITY.md 2020-10-14 15:11:30 +02:00
Hector Sanjuan c6ed6a0d65 Add support for /https, /http, /wss API multiaddresses.
Lotus API endpoint are by default expressed as multiaddresses (i.e. lotus auth
api-info) which end in /http, although they can be provided as standard URLs too.

There is an inconsistency here because despite the "http" part, Lotus will use "ws" protocol.

This lets lotus default to "ws" but honor whatever the user puts in the multiaddress (i.e.
/dns4/my.lotus.node/tcp/443/https) would work now using https, where before it uses "ws".
2020-10-14 14:58:58 +02:00
Łukasz Magiera 4ad8d85b13 Merge pull request #4278 from filecoin-project/tvx/trace-puts
tvx: trace puts to blockstore for inclusion in CAR.
2020-10-14 12:08:06 +02:00
Łukasz Magiera 465703b618 Merge pull request #4384 from filecoin-project/feat/4220
Use updated stored ask API
2020-10-14 12:03:07 +02:00
Aarsh Shah 30dd5d9644 use updated stored ask api 2020-10-14 11:39:57 +02:00
Aayush Rajasekaran 41bfeb56e2 Merge pull request #4386 from filecoin-project/asr/changelog
Lotus version 0.10.1
2020-10-14 02:34:18 -04:00
Aayush Rajasekaran 2e7cd024df Lotus version 0.10.1 2020-10-14 02:22:02 -04:00
Aayush Rajasekaran bf619862c3 Merge pull request #4382 from filecoin-project/asr/invoc-result
Add message CID to InvocResult
2020-10-14 02:06:09 -04:00
Aayush Rajasekaran 29e54c40be Merge pull request #4363 from filecoin-project/feat/update-markets-0.9.0
feat(markets): update markets 0.9.0 and add data transfer restart com…
2020-10-14 01:38:05 -04:00
Aayush Rajasekaran 308144ee6a Merge pull request #4350 from filecoin-project/asr/improve-fork
Avoid having the same message CID show up in execution traces
2020-10-14 01:22:16 -04:00
Aayush Rajasekaran ce54110228 Add message CID to InvocResult 2020-10-14 00:06:22 -04:00
Aayush Rajasekaran 458ea277fc Aggregate irregular state transitions into a single EexcutionTrace 2020-10-13 22:59:42 -04:00
hannahhoward 58662b79b3 fix(deps): use tagged go-fil-markets 0.9.0 2020-10-13 19:50:13 -07:00
Aayush Rajasekaran 7dbc8965be Apply nonces to implicit messages 2020-10-13 22:06:06 -04:00
Aayush Rajasekaran 2426700821 Don't transfer zero FIL during rebalancing fork 2020-10-13 22:06:06 -04:00
Łukasz Magiera 9c6ee802cc Merge pull request #4376 from filecoin-project/steb/fix-load-panic
fix a panic on startup when we fail to load the tipset
2020-10-14 01:02:01 +02:00
Steven Allen b61281ba4b fix a panic on startup when we fail to load the tipset
There may be a deeper issue here, but we need to handle this more gracefully
somehow. See #4358.
2020-10-13 15:06:47 -07:00
whyrusleeping 3d80c38064 support stateReadState in gateway 2020-10-13 14:23:08 -07:00
whyrusleeping 98c1aa7988 add WalletVerify to lotus-gateway 2020-10-13 13:31:20 -07:00
Łukasz Magiera d5cea9f402 Merge pull request #4367 from filecoin-project/fix/msg-search-off-by-one
Fix off by one tipset in searchBackForMsg
2020-10-13 22:11:24 +02:00
Jakub Sztandera ce548c8f95 Add test
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-13 20:02:43 +02:00
Jakub Sztandera 8987defb9d Fix BLS message ChainLength add more detail to ValidForBlockInclusion
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-13 20:02:42 +02:00
Łukasz Magiera 1a70dbe37d Merge pull request #4347 from filecoin-project/fix/sync/message-validation-state-height
fix(sync state): set state height to actual tipset height
2020-10-13 17:55:51 +02:00
Jakub Sztandera 87cd8c6725 Fix off by one tipset in searchBackForMsg
This way we will return the tipset the message was executed in

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-13 17:48:54 +02:00
zgfzgf 1eb2d0ae50 optimize map use struct{} 2020-10-13 22:34:07 +08:00
Jakub Sztandera 5fd0bf11ba Merge pull request #4338 from filecoin-project/feat/message-json-cids
types: Add CID fields to messages in json marshalers
2020-10-13 14:59:22 +02:00
hannahhoward 4edebcec2b feat(markets): update markets 0.9.0 and add data transfer restart command 2020-10-13 03:41:08 -07:00
zgfzgf 07d0b67628 optimize code use ts.Cids 2020-10-13 10:46:41 +08:00
Lucas Molas 9b4cac9612 fix(sync state): set state height to actual tipset height 2020-10-12 21:14:16 -03:00
Travis Person 8232cc8415 Merge pull request #4341 from filecoin-project/fix/lotus-pcr-skip-non-processes
lotus-pcr: ignore all other market messages
2020-10-12 16:07:57 -07:00
Travis Person be74a13736 lotus-pcr: ignore all other market messages 2020-10-12 21:41:48 +00:00
Aayush Rajasekaran 195d96ccc0 Merge pull request #4148 from filecoin-project/asr/circ-supply
Add a StateExactCirculatingSupply command
2020-10-12 17:02:07 -04:00
Ingar Shu 49155ace62 Use seal-duration in calculating the earliest StartEpoch that we will consider (#4337) 2020-10-12 17:45:37 -03:00
Aayush Rajasekaran 83624a8858 Rename StateVMCirculatingSupply to StateVMCirculatingSupplyInternal 2020-10-12 16:41:27 -04:00
Aayush Rajasekaran 96e1dfd8d7 Add an endpoint for precise circulating supply 2020-10-12 16:38:29 -04:00
Łukasz Magiera 61661fb1f0 docsgen 2020-10-12 20:47:09 +02:00
Łukasz Magiera 6c08120628 types: Add CID fields to messages in json marshalers 2020-10-12 20:46:47 +02:00
Łukasz Magiera 8d769f0c07 Merge pull request #4336 from filecoin-project/steb/params-mainnet
Rename params_testnet to params_mainnet
2020-10-12 20:18:23 +02:00
Steven Allen 79c5d2c6d2 Rename params_testnet to params_mainnet 2020-10-12 11:04:46 -07:00
Łukasz Magiera 224a96431f Merge pull request #4319 from filecoin-project/asr/repay-debt-cli
Add a CLI tool for miner's to repay debt
2020-10-12 19:24:40 +02:00
Hector Sanjuan 8001ed3030 Drand: add cloudflare. Use HTTP for PL nodes.
Adding Cloudflare ensures additional redundancy.

Switching to HTTP for PL nodes reduces latency and cost. Randomness is
verified after being received.
2020-10-12 19:15:56 +02:00
Łukasz Magiera 2855c2bc49 Merge pull request #4329 from shaodan/ux-workers-cores
Improve the UX for `lotus-miner sealing workers`
2020-10-12 16:45:26 +02:00
Łukasz Magiera 65883cbb6b Merge pull request #4290 from filecoin-project/feat/ledger-integration
adding in ledger support
2020-10-12 15:09:27 +02:00
Steven Allen 443131b214 Merge pull request #4328 from filecoin-project/steb/test-tape-upgrade
Test the tape upgrade
2020-10-12 00:27:18 -07:00
Łukasz Magiera 8b648cf77c ledger: Close device in WalletNew 2020-10-12 09:21:42 +02:00
Dan Shao c0961fb63d Improve the UX for lotus-miner sealing workers: add total number of cores 2020-10-12 15:07:56 +08:00
Steven Allen dc4e73c737 Test the tape upgrade 2020-10-12 00:01:25 -07:00
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 4ac2bee81c Update oni 2020-10-12 06:34:45 +02:00
Łukasz Magiera a2e0832a12 Fix lint 2020-10-12 06:17:00 +02: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
Aayush Rajasekaran b4215e5f46 Add a CLI tool for miner's to repay debt 2020-10-11 19:57:30 -04:00
Jakub Sztandera df7ee610cd Re-enable repub
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 01:29:19 +02:00
Jakub Sztandera fda8b932ba Ask for confirmation when creating a key
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 01:27:15 +02:00
Jakub Sztandera 7b4a5fc7ca Fixup off by one
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:50:29 +02:00
Jakub Sztandera d6c8276c7a Add support for WalletNew to ledger
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:48:23 +02:00
Jakub Sztandera 2b21fdef33 Refactor from crypto.SigType to types.KeyType
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:53 +02:00
Łukasz Magiera 6a232e7214 Basic multi-wallet support
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:41 +02:00
Jakub Sztandera 7ee6bafd23 Fix lint warn
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:41 +02:00
Jakub Sztandera 753d7b71a9 Fix hardened path printing, show 20 addresses after empty
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
Łukasz Magiera bb6a354b62 chain cli: decode params command
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
Łukasz Magiera 8ae66d6c6a Fix lint warnings
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
Łukasz Magiera 2c92157233 shed ledger: Some UX improvements
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
Łukasz Magiera 66d6113340 ledgerwallet: Validate signing bytes
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
Łukasz Magiera 99791a6953 lotus-wallet: ledger flag
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +02:00
whyrusleeping b35f9b56b4 WIP: adding in ledger support
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-12 00:07:40 +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
Jakub Sztandera 85be11fb75 Add propose remove
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-10-11 18:10:02 +02: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
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
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
Raúl Kripalani e0dcb0ec49 tvx: trace puts to blockstore for inclusion in CAR. 2020-10-09 22:20:15 +01:00
whyrusleeping 4cca3f19a3 add an api for removing multisig signers 2020-10-09 09:40:25 -07:00
whyrusleeping ef3987e2ab decode parameters for multisig transactions in inspect 2020-10-02 14:51:32 -07:00
132 changed files with 4336 additions and 929 deletions
+5 -1
View File
@@ -1,5 +1,9 @@
comment: off
ignore:
- "cbor_gen.go"
- "**/cbor_gen.go"
- "api/test/**/*"
- "api/test/*"
- "gen/**/*"
- "gen/*"
github_checks:
annotations: false
+91
View File
@@ -1,5 +1,96 @@
# Lotus changelog
# 1.0.0 / 2020-10-19
It's 1.0.0! This is an optional release of Lotus that introduces some UX improvements to the 0.10 series.
This very small release is largely cosmetic, and intended to flag the code that the Filecoin mainnet was launched with.
## API changes
- `StateMsgGasCost` has been removed. The equivalent information can be gained by calling `StateReplay`.
- A `GasCost` field has been added to the `InvocResult` type, meaning detailed gas costs will be returned when calling `StateReplay`, `StateCompute`, and `StateCall`.
- The behaviour of `StateReplay` in response to an empty tipset key has been changed. Instead of simply using the heaviest tipset (which is almost guaranteed to be an unsuccessful replay), we search now search the chain for the tipset that included the message, and replay the message in that tipset (we fail if no such tipset is found).
## Changes
- Increase code coverage! (https://github.com/filecoin-project/lotus/pull/4410)
- Mpool: Don't block node startup loading messages (https://github.com/filecoin-project/lotus/pull/4411)
- Improve the UX of multisig approves (https://github.com/filecoin-project/lotus/pull/4398)
- Use build.BlockDelaySecs for deal start buffer (https://github.com/filecoin-project/lotus/pull/4415)
- Conformance: support multiple protocol versions (https://github.com/filecoin-project/lotus/pull/4393)
- Ensure msig inspect cli works with lotus-lite (https://github.com/filecoin-project/lotus/pull/4421)
- Add command to (slowly) prune lotus chain datastore (https://github.com/filecoin-project/lotus/pull/3876)
- Add WalletVerify to lotus-gateway (https://github.com/filecoin-project/lotus/pull/4373)
- Improve StateMsg APIs (https://github.com/filecoin-project/lotus/pull/4429)
- Add endpoints needed by spacegap (https://github.com/filecoin-project/lotus/pull/4426)
- Make audit balances capable of printing robust addresses (https://github.com/filecoin-project/lotus/pull/4423)
- Custom filters for retrieval deals (https://github.com/filecoin-project/lotus/pull/4424)
- Fix message list api (https://github.com/filecoin-project/lotus/pull/4422)
- Replace bootstrap peers (https://github.com/filecoin-project/lotus/pull/4447)
- Don't overwrite previously-configured maxPieceSize for a persisted ask (https://github.com/filecoin-project/lotus/pull/4480)
- State: optimize state snapshot address cache (https://github.com/filecoin-project/lotus/pull/4481)
# 0.10.2 / 2020-10-14
This is an optional release of Lotus that updates markets to 0.9.1, which fixes an issue affecting deals that were mid-transfer when the node was upgraded to 0.9.0. This release also includes some tweaks to default gas values and minor performance improvements.
## Changes
- Use updated stored ask API (https://github.com/filecoin-project/lotus/pull/4384)
- tvx: trace puts to blockstore for inclusion in CAR. (https://github.com/filecoin-project/lotus/pull/4278)
- Add propose remove (https://github.com/filecoin-project/lotus/pull/4311)
- Update to 0.9.1 bugfix release (https://github.com/filecoin-project/lotus/pull/4402)
- Update drand endpoints (https://github.com/filecoin-project/lotus/pull/4125)
- fix: return true when deadlines changed (https://github.com/filecoin-project/lotus/pull/4403)
- sync wait --watch (https://github.com/filecoin-project/lotus/pull/4396)
- reduce garbage in blockstore (https://github.com/filecoin-project/lotus/pull/4406)
- give the TimeCacheBS tests a bit more time (https://github.com/filecoin-project/lotus/pull/4407)
- Improve gas defaults (https://github.com/filecoin-project/lotus/pull/4408)
- Change default gas premium to for 10 block inclusion (https://github.com/filecoin-project/lotus/pull/4222)
# 0.10.1 / 2020-10-14
This is an optional release of Lotus that updates markets to 0.9.0, which adds the ability to restart data transfers. This release also introduces Ledger support, and various UX improvements.
## Changes
- Test the tape upgrade (https://github.com/filecoin-project/lotus/pull/4328)
- Adding in Ledger support (https://github.com/filecoin-project/lotus/pull/4290)
- Improve the UX for lotus-miner sealing workers (https://github.com/filecoin-project/lotus/pull/4329)
- Add a CLI tool for miner's to repay debt (https://github.com/filecoin-project/lotus/pull/4319)
- Rename params_testnet to params_mainnet (https://github.com/filecoin-project/lotus/pull/4336)
- Use seal-duration in calculating the earliest StartEpoch (https://github.com/filecoin-project/lotus/pull/4337)
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
- Add an API endpoint to calculate the exact circulating supply (https://github.com/filecoin-project/lotus/pull/4148)
- lotus-pcr: ignore all other market messages (https://github.com/filecoin-project/lotus/pull/4341)
- Add message CID to InvocResult (https://github.com/filecoin-project/lotus/pull/4382)
- types: Add CID fields to messages in json marshalers (https://github.com/filecoin-project/lotus/pull/4338)
- fix(sync state): set state height to actual tipset height (https://github.com/filecoin-project/lotus/pull/4347)
- Fix off by one tipset in searchBackForMsg (https://github.com/filecoin-project/lotus/pull/4367)
- fix a panic on startup when we fail to load the tipset (https://github.com/filecoin-project/lotus/pull/4376)
- Avoid having the same message CID show up in execution traces (https://github.com/filecoin-project/lotus/pull/4350)
- feat(markets): update markets 0.9.0 and add data transfer restart (https://github.com/filecoin-project/lotus/pull/4363)
# 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.
+3 -9
View File
@@ -2,9 +2,7 @@
## Reporting a Vulnerability
For *critical* bugs, please send an email to security@filecoin.org.
The bug reporting process differs between bugs that are critical and may crash the network, and others that are unlikely to cause problems if malicious parties know about it. For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
For *critical* bugs, please consult our Security Policy and Responsible Disclosure Program information at https://github.com/filecoin-project/community/blob/master/SECURITY.md
Please try to provide a clear description of any bugs reported, along with how to reproduce the bug if possible. More detailed bug reports (especially those with a PoC included) will help us move forward much faster. Additionally, please avoid reporting bugs that already have open issues. Take a moment to search the issue list of the related GitHub repositories before writing up a new report.
@@ -20,10 +18,6 @@ Here are some examples of bugs we would consider 'critical':
This is not an exhaustive list, but should provide some idea of what we consider 'critical'.
## Supported Versions
## Reporting a non security bug
* TODO: This should be defined and set up by Mainnet launch.
| Version | Supported |
| ------- | ------------------ |
| Testnet | :white_check_mark: |
For non-critical bugs, please simply file a GitHub [issue](https://github.com/filecoin-project/lotus/issues/new?template=bug_report.md).
+45 -11
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"time"
datatransfer "github.com/filecoin-project/go-data-transfer"
"github.com/filecoin-project/go-state-types/network"
"github.com/ipfs/go-cid"
@@ -172,6 +173,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)
@@ -226,7 +230,9 @@ type FullNode interface {
// MethodGroup: Wallet
// WalletNew creates a new address in the wallet with the given sigType.
WalletNew(context.Context, crypto.SigType) (address.Address, error)
// Available key types: bls, secp256k1, secp256k1-ledger
// Support for numerical types: 1 - secp256k1, 2 - BLS is deprecated
WalletNew(context.Context, types.KeyType) (address.Address, error)
// WalletHas indicates whether the given address is in the wallet.
WalletHas(context.Context, address.Address) (bool, error)
// WalletList lists all the addresses in the wallet.
@@ -293,6 +299,8 @@ type FullNode interface {
// ClientListTransfers returns the status of all ongoing transfers of data
ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
// ClientRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer
ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error
// ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel
// which are stuck due to insufficient funds
ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error
@@ -307,19 +315,20 @@ type FullNode interface {
// MethodGroup: State
// The State methods are used to query, inspect, and interact with chain state.
// All methods take a TipSetKey as a parameter. The state looked up is the state at that tipset.
// Most methods take a TipSetKey as a parameter. The state looked up is the state at that tipset.
// A nil TipSetKey can be provided as a param, this will cause the heaviest tipset in the chain to be used.
// StateCall runs the given message and returns its result without any persisted changes.
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
// StateReplay returns the result of executing the indicated message, assuming it was executed in the indicated tipset.
// StateReplay replays a given message, assuming it was included in a block in the specified tipset.
// If no tipset key is provided, the appropriate tipset is looked up.
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
// StateGetActor returns the indicated actor's nonce and balance.
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
// StateReadState returns the indicated actor's state.
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error)
// StateListMessages looks back and returns all messages with a matching to or from address, stopping at the given height.
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
StateListMessages(ctx context.Context, match *MessageMatch, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error)
// StateNetworkName returns the name of the network the node is synced to
StateNetworkName(context.Context) (dtypes.NetworkName, error)
@@ -362,8 +371,6 @@ type FullNode interface {
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error)
// StateSearchMsg searches for a message in the chain, and returns its receipt and the tipset where it was executed
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
// StateMsgGasCost searches for a message in the chain, and returns details of the messages gas costs, including the penalty and miner tip
StateMsgGasCost(context.Context, cid.Cid, types.TipSetKey) (*MsgGasCost, error)
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
// message arrives on chain, and gets to the indicated confidence depth.
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
@@ -411,8 +418,12 @@ type FullNode interface {
// can issue. It takes the deal size and verified status as parameters.
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)
// StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
// StateCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.
// This is not used anywhere in the protocol itself, and is only for external consumption.
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
// StateVMCirculatingSupplyInternal returns an approximation of the circulating supply of Filecoin at the given tipset.
// This is the value reported by the runtime interface to actors code.
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (CirculatingSupply, error)
// StateNetworkVersion returns the network version at the given tipset
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
@@ -435,12 +446,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
@@ -468,6 +488,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
@@ -709,8 +736,10 @@ type RetrievalOrder struct {
}
type InvocResult struct {
MsgCid cid.Cid
Msg *types.Message
MsgRct *types.MessageReceipt
GasCost MsgGasCost
ExecutionTrace types.ExecutionTrace
Error string
Duration time.Duration
@@ -889,3 +918,8 @@ type MsigVesting struct {
StartEpoch abi.ChainEpoch
UnlockDuration abi.ChainEpoch
}
type MessageMatch struct {
To address.Address
From address.Address
}
+2
View File
@@ -10,9 +10,11 @@ import (
)
type GatewayAPI interface {
ChainHasObj(context.Context, cid.Cid) (bool, error)
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)
ChainReadObj(context.Context, cid.Cid) ([]byte, 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)
+1 -1
View File
@@ -35,7 +35,7 @@ type MsgMeta struct {
}
type WalletAPI interface {
WalletNew(context.Context, crypto.SigType) (address.Address, error)
WalletNew(context.Context, types.KeyType) (address.Address, error)
WalletHas(context.Context, address.Address) (bool, error)
WalletList(context.Context) ([]address.Address, error)
+47 -16
View File
@@ -15,6 +15,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
datatransfer "github.com/filecoin-project/go-data-transfer"
"github.com/filecoin-project/go-fil-markets/piecestore"
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-fil-markets/storagemarket"
@@ -111,6 +112,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"`
@@ -132,7 +134,7 @@ type FullNodeStruct struct {
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
@@ -164,6 +166,7 @@ type FullNodeStruct struct {
ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"`
ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"`
ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"`
ClientRestartDataTransfer func(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error `perm:"write"`
ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"`
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
@@ -188,7 +191,6 @@ type FullNodeStruct struct {
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
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"`
@@ -203,13 +205,14 @@ type FullNodeStruct struct {
StateChangedActors func(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) `perm:"read"`
StateGetReceipt func(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
StateListMessages func(ctx context.Context, match *api.MessageMatch, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
StateVerifierStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
StateCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
StateVMCirculatingSupplyInternal func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
@@ -217,7 +220,8 @@ type FullNodeStruct struct {
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"`
@@ -225,6 +229,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"`
@@ -365,9 +370,11 @@ type WorkerStruct struct {
type GatewayStruct struct {
Internal struct {
// TODO: does the gateway need perms?
ChainHasObj func(context.Context, cid.Cid) (bool, error)
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)
ChainReadObj func(context.Context, cid.Cid) ([]byte, 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)
@@ -381,7 +388,7 @@ type GatewayStruct struct {
type WalletStruct struct {
Internal struct {
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
WalletNew func(context.Context, types.KeyType) (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"`
@@ -548,6 +555,10 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan
return c.Internal.ClientDataTransferUpdates(ctx)
}
func (c *FullNodeStruct) ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error {
return c.Internal.ClientRestartDataTransfer(ctx, transferID, otherPeer, isInitiator)
}
func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error {
return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel)
}
@@ -628,7 +639,7 @@ func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.Chain
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
return c.Internal.WalletNew(ctx, typ)
}
@@ -780,6 +791,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)
}
@@ -876,10 +891,6 @@ func (c *FullNodeStruct) StateReadState(ctx context.Context, addr address.Addres
return c.Internal.StateReadState(ctx, addr, tsk)
}
func (c *FullNodeStruct) StateMsgGasCost(ctx context.Context, msgc cid.Cid, tsk types.TipSetKey) (*api.MsgGasCost, error) {
return c.Internal.StateMsgGasCost(ctx, msgc, tsk)
}
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
}
@@ -932,7 +943,7 @@ func (c *FullNodeStruct) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk t
return c.Internal.StateGetReceipt(ctx, msg, tsk)
}
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) {
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *api.MessageMatch, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) {
return c.Internal.StateListMessages(ctx, match, tsk, toht)
}
@@ -956,10 +967,14 @@ func (c *FullNodeStruct) StateDealProviderCollateralBounds(ctx context.Context,
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
}
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
return c.Internal.StateCirculatingSupply(ctx, tsk)
}
func (c *FullNodeStruct) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
return c.Internal.StateVMCirculatingSupplyInternal(ctx, tsk)
}
func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
return c.Internal.StateNetworkVersion(ctx, tsk)
}
@@ -984,8 +999,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) {
@@ -1016,6 +1035,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)
}
@@ -1406,6 +1429,10 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
return w.Internal.Closing(ctx)
}
func (g GatewayStruct) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) {
return g.Internal.ChainHasObj(ctx, c)
}
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
return g.Internal.ChainHead(ctx)
}
@@ -1418,6 +1445,10 @@ func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEp
return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (g GatewayStruct) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
return g.Internal.ChainReadObj(ctx, c)
}
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)
}
@@ -1450,7 +1481,7 @@ func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence
return g.Internal.StateWaitMsg(ctx, msg, confidence)
}
func (c *WalletStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
func (c *WalletStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
return c.Internal.WalletNew(ctx, typ)
}
+1
View File
@@ -87,6 +87,7 @@ func init() {
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
addExample(abi.ChainEpoch(10101))
addExample(crypto.SigTypeBLS)
addExample(types.KTBLS)
addExample(int64(9))
addExample(12.3)
addExample(123)
+1 -2
View File
@@ -26,7 +26,6 @@ import (
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
)
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
@@ -58,7 +57,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
bm.MineBlocks()
// send some funds to register the receiver
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
+114
View File
@@ -0,0 +1,114 @@
package test
import (
"context"
"fmt"
"testing"
"time"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/stmgr"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/lotus/node"
"github.com/filecoin-project/lotus/node/impl"
"github.com/stretchr/testify/require"
)
func TestTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration) {
t.Run("before", func(t *testing.T) { testTapeFix(t, b, blocktime, false) })
t.Run("after", func(t *testing.T) { testTapeFix(t, b, blocktime, true) })
}
func testTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration, after bool) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
upgradeSchedule := stmgr.UpgradeSchedule{{
Network: build.ActorUpgradeNetworkVersion,
Height: 1,
Migration: stmgr.UpgradeActorsV2,
}}
if after {
upgradeSchedule = append(upgradeSchedule, stmgr.Upgrade{
Network: network.Version5,
Height: 2,
})
}
n, sn := b(t, []FullNodeOpts{{Opts: func(_ []TestNode) node.Option {
return node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)
}}}, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
addrinfo, err := client.NetAddrsListen(ctx)
if err != nil {
t.Fatal(err)
}
if err := miner.NetConnect(ctx, addrinfo); err != nil {
t.Fatal(err)
}
build.Clock.Sleep(time.Second)
done := make(chan struct{})
go func() {
defer close(done)
for ctx.Err() == nil {
build.Clock.Sleep(blocktime)
if err := sn[0].MineOne(ctx, MineNext); err != nil {
if ctx.Err() != nil {
// context was canceled, ignore the error.
return
}
t.Error(err)
}
}
}()
defer func() {
cancel()
<-done
}()
err = miner.PledgeSector(ctx)
require.NoError(t, err)
// Wait till done.
var sectorNo abi.SectorNumber
for {
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
require.NoError(t, err)
fmt.Printf("Sectors: %d\n", len(s))
if len(s) == 1 {
sectorNo = s[0]
break
}
build.Clock.Sleep(100 * time.Millisecond)
}
fmt.Printf("All sectors is fsm\n")
// If before, we expect the precommit to fail
successState := api.SectorState(sealing.CommitFailed)
failureState := api.SectorState(sealing.Proving)
if after {
// otherwise, it should succeed.
successState, failureState = failureState, successState
}
for {
st, err := miner.SectorsStatus(ctx, sectorNo, false)
require.NoError(t, err)
if st.State == successState {
break
}
require.NotEqual(t, failureState, st.State)
build.Clock.Sleep(100 * time.Millisecond)
fmt.Println("WaitSeal")
}
}
+50 -1
View File
@@ -3,8 +3,10 @@ package test
import (
"context"
"testing"
"time"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/multiformats/go-multiaddr"
@@ -12,6 +14,8 @@ import (
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/miner"
@@ -74,6 +78,7 @@ func TestApis(t *testing.T, b APIBuilder) {
t.Run("testConnectTwo", ts.testConnectTwo)
t.Run("testMining", ts.testMining)
t.Run("testMiningReal", ts.testMiningReal)
t.Run("testSearchMsg", ts.testSearchMsg)
}
func DefaultFullOpts(nFull int) []FullNodeOpts {
@@ -96,7 +101,8 @@ 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,
// Skip directly to tape height so precommits work.
Network: network.Version5,
Height: upgradeHeight,
Migration: stmgr.UpgradeActorsV2,
}})
@@ -118,6 +124,49 @@ func (ts *testSuite) testVersion(t *testing.T) {
require.Equal(t, v.Version, build.BuildVersion)
}
func (ts *testSuite) testSearchMsg(t *testing.T) {
apis, miners := ts.makeNodes(t, OneFull, OneMiner)
api := apis[0]
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
senderAddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
msg := &types.Message{
From: senderAddr,
To: senderAddr,
Value: big.Zero(),
}
bm := NewBlockMiner(ctx, t, miners[0], 100*time.Millisecond)
bm.MineBlocks()
defer bm.Stop()
sm, err := api.MpoolPushMessage(ctx, msg, nil)
if err != nil {
t.Fatal(err)
}
res, err := api.StateWaitMsg(ctx, sm.Cid(), 1)
if err != nil {
t.Fatal(err)
}
if res.Receipt.ExitCode != 0 {
t.Fatal("did not successfully send message")
}
searchRes, err := api.StateSearchMsg(ctx, sm.Cid())
if err != nil {
t.Fatal(err)
}
if searchRes.TipSet != res.TipSet {
t.Fatalf("search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet)
}
}
func (ts *testSuite) testID(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
+7 -4
View File
@@ -3,6 +3,7 @@ package test
import (
"context"
"fmt"
"sync/atomic"
"os"
"strings"
@@ -31,7 +32,9 @@ func init() {
}
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
ctx := context.Background()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
n, sn := b(t, OneFull, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -46,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) {
@@ -62,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
}
+9 -6
View File
@@ -1,9 +1,12 @@
/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/bootstrap-0.mainnet.filops.net/tcp/1347/p2p/12D3KooWCVe8MmsEMes2FzgTpt9fXtmCY7wrq91GRiaC8PHSCCBj
/dns4/bootstrap-1.mainnet.filops.net/tcp/1347/p2p/12D3KooWCwevHg1yLCvktf2nvLu7L9894mcrJR4MsBCcm4syShVc
/dns4/bootstrap-2.mainnet.filops.net/tcp/1347/p2p/12D3KooWEWVwHGn2yR36gKLozmb4YjDJGerotAPGxmdWZx2nxMC4
/dns4/bootstrap-3.mainnet.filops.net/tcp/1347/p2p/12D3KooWKhgq8c7NQ9iGjbyK7v7phXvG6492HQfiDaGHLHLQjk7R
/dns4/bootstrap-4.mainnet.filops.net/tcp/1347/p2p/12D3KooWL6PsFNPhYftrJzGgF5U18hFoaVhfGk7xwzD8yVrHJ3Uc
/dns4/bootstrap-5.mainnet.filops.net/tcp/1347/p2p/12D3KooWLFynvDQiUpXoHroV1YxKHhPJgysQGH2k3ZGwtWzR4dFH
/dns4/bootstrap-6.mainnet.filops.net/tcp/1347/p2p/12D3KooWP5MwCiqdMETF9ub1P3MbCvQCcfconnYHbWg6sUJcDRQQ
/dns4/bootstrap-7.mainnet.filops.net/tcp/1347/p2p/12D3KooWRs3aY1p3juFjPy8gPN95PEQChm2QKGUCAdcDCC4EBMKf
/dns4/bootstrap-8.mainnet.filops.net/tcp/1347/p2p/12D3KooWScFR7385LTyR4zU1bYdzSiiAb5rnNABfVahPvVSzyTkR
/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
+1 -10
View File
@@ -35,6 +35,7 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
"https://api.drand.sh",
"https://api2.drand.sh",
"https://api3.drand.sh",
"https://drand.cloudflare.com",
},
Relays: []string{
"/dnsaddr/api.drand.sh/",
@@ -68,16 +69,6 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`,
},
DrandIncentinet: {
Servers: []string{
"https://pl-eu.incentinet.drand.sh",
"https://pl-us.incentinet.drand.sh",
"https://pl-sin.incentinet.drand.sh",
},
Relays: []string{
"/dnsaddr/pl-eu.incentinet.drand.sh/",
"/dnsaddr/pl-us.incentinet.drand.sh/",
"/dnsaddr/pl-sin.incentinet.drand.sh/",
},
ChainInfoJSON: `{"public_key":"8cad0c72c606ab27d36ee06de1d5b2db1faf92e447025ca37575ab3a8aac2eaae83192f846fc9e158bc738423753d000","period":30,"genesis_time":1595873820,"hash":"80c8b872c714f4c00fdd3daa465d5514049f457f01f85a4caf68cdcd394ba039","groupHash":"d9406aaed487f7af71851b4399448e311f2328923d454e971536c05398ce2d9b"}`,
},
}
+2 -1
View File
@@ -17,9 +17,10 @@ const BreezeGasTampingDuration = 0
const UpgradeSmokeHeight = -1
const UpgradeIgnitionHeight = -2
const UpgradeRefuelHeight = -3
const UpgradeTapeHeight = -4
var UpgradeActorsV2Height = abi.ChainEpoch(10)
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
@@ -30,6 +30,8 @@ const UpgradeRefuelHeight = 130800
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.
// We still have upgrades and state changes to do, but can happen after signaling timing here.
+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
+3 -2
View File
@@ -83,14 +83,15 @@ var (
UpgradeSmokeHeight abi.ChainEpoch = -1
UpgradeIgnitionHeight abi.ChainEpoch = -2
UpgradeRefuelHeight abi.ChainEpoch = -3
UpgradeTapeHeight abi.ChainEpoch = -4
UpgradeActorsV2Height abi.ChainEpoch = 10
UpgradeLiftoffHeight abi.ChainEpoch = -4
UpgradeLiftoffHeight abi.ChainEpoch = -5
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
}
NewestNetworkVersion = network.Version4
NewestNetworkVersion = network.Version5
ActorUpgradeNetworkVersion = network.Version4
Devnet = true
+2 -2
View File
@@ -29,7 +29,7 @@ func buildType() string {
}
// BuildVersion is the local build version, set by build system
const BuildVersion = "0.9.1"
const BuildVersion = "1.0.0"
func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit
@@ -83,7 +83,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
// semver versions of the rpc api exposed
var (
FullAPIVersion = newVer(0, 16, 0)
FullAPIVersion = newVer(0, 17, 0)
MinerAPIVersion = newVer(0, 15, 0)
WorkerAPIVersion = newVer(0, 15, 0)
)
+6 -3
View File
@@ -2,25 +2,28 @@ package builtin
import (
"github.com/filecoin-project/go-address"
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/types"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
)
var SystemActorAddr = builtin0.SystemActorAddr
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
var CronActorAddr = builtin0.CronActorAddr
var SaftAddress = makeAddress("t0122")
var ReserveAddress = makeAddress("t090")
var RootVerifierAddress = makeAddress("t080")
+6 -10
View File
@@ -7,9 +7,9 @@ import (
"github.com/filecoin-project/go-state-types/exitcode"
)
type DeadlinesDiff map[uint64]*DeadlineDiff
type DeadlinesDiff map[uint64]DeadlineDiff
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
func DiffDeadlines(pre, cur State) (DeadlinesDiff, error) {
changed, err := pre.DeadlinesChanged(cur)
if err != nil {
return nil, err
@@ -18,11 +18,7 @@ func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
return nil, nil
}
numDl, err := pre.NumDeadlines()
if err != nil {
return nil, err
}
dlDiff := make(DeadlinesDiff, numDl)
dlDiff := make(DeadlinesDiff)
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
curDl, err := cur.LoadDeadline(idx)
if err != nil {
@@ -39,12 +35,12 @@ func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
}); err != nil {
return nil, err
}
return &dlDiff, nil
return dlDiff, nil
}
type DeadlineDiff map[uint64]*PartitionDiff
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
func DiffDeadline(pre, cur Deadline) (DeadlineDiff, error) {
changed, err := pre.PartitionsChanged(cur)
if err != nil {
return nil, err
@@ -104,7 +100,7 @@ func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
return nil, err
}
return &partDiff, nil
return partDiff, nil
}
type PartitionDiff struct {
+19
View File
@@ -1,6 +1,7 @@
package miner
import (
"github.com/filecoin-project/go-state-types/big"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
@@ -148,6 +149,20 @@ type MinerInfo struct {
ConsensusFaultElapsed abi.ChainEpoch
}
func (mi MinerInfo) IsController(addr address.Address) bool {
if addr == mi.Owner || addr == mi.Worker {
return true
}
for _, ca := range mi.ControlAddresses {
if addr == ca {
return true
}
}
return false
}
type SectorExpiration struct {
OnTime abi.ChainEpoch
@@ -182,3 +197,7 @@ type LockedFunds struct {
InitialPledgeRequirement abi.TokenAmount
PreCommitDeposits abi.TokenAmount
}
func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount {
return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits))
}
+12 -4
View File
@@ -47,8 +47,16 @@ type partition0 struct {
store adt.Store
}
func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
return s.GetAvailableBalance(bal), nil
func (s *state0) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
defer func() {
if r := recover(); r != nil {
err = xerrors.Errorf("failed to get available balance: %w", r)
available = abi.NewTokenAmount(0)
}
}()
// this panics if the miner doesnt have enough funds to cover their locked pledge
available = s.GetAvailableBalance(bal)
return available, err
}
func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
@@ -266,7 +274,7 @@ func (s *state0) DeadlinesChanged(other State) (bool, error) {
return true, nil
}
return s.State.Deadlines.Equals(other0.Deadlines), nil
return !s.State.Deadlines.Equals(other0.Deadlines), nil
}
func (s *state0) Info() (MinerInfo, error) {
@@ -362,7 +370,7 @@ func (d *deadline0) PartitionsChanged(other Deadline) (bool, error) {
return true, nil
}
return d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
return !d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
}
func (d *deadline0) PostSubmissions() (bitfield.BitField, error) {
+12 -4
View File
@@ -45,8 +45,16 @@ type partition2 struct {
store adt.Store
}
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
return s.GetAvailableBalance(bal)
func (s *state2) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
defer func() {
if r := recover(); r != nil {
err = xerrors.Errorf("failed to get available balance: %w", r)
available = abi.NewTokenAmount(0)
}
}()
// this panics if the miner doesnt have enough funds to cover their locked pledge
available, err = s.GetAvailableBalance(bal)
return available, err
}
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
@@ -265,7 +273,7 @@ func (s *state2) DeadlinesChanged(other State) (bool, error) {
return true, nil
}
return s.State.Deadlines.Equals(other2.Deadlines), nil
return !s.State.Deadlines.Equals(other2.Deadlines), nil
}
func (s *state2) Info() (MinerInfo, error) {
@@ -361,7 +369,7 @@ func (d *deadline2) PartitionsChanged(other Deadline) (bool, error) {
return true, nil
}
return d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
return !d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
}
func (d *deadline2) PostSubmissions() (bitfield.BitField, error) {
+1
View File
@@ -45,6 +45,7 @@ type MessageBuilder interface {
// this type is the same between v0 and v2
type ProposalHashData = multisig2.ProposalHashData
type ProposeReturn = multisig2.ProposeReturn
func txnParams(id uint64, data *ProposalHashData) ([]byte, error) {
params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)}
+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
@@ -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 {
+1 -1
View File
@@ -12,7 +12,7 @@ import (
)
func TestPrintGroupInfo(t *testing.T) {
server := build.DrandConfigs[build.DrandIncentinet].Servers[0]
server := build.DrandConfigs[build.DrandDevnet].Servers[0]
c, err := hclient.New(server, nil, nil)
assert.NoError(t, err)
cg := c.(interface {
+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())
}
+2 -2
View File
@@ -155,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
}
banker, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
banker, err := w.WalletNew(context.Background(), types.KTSecp256k1)
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.WalletNew(context.Background(), crypto.SigTypeBLS)
receievers[r], err = w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
}
+23 -11
View File
@@ -59,6 +59,8 @@ var MaxUntrustedActorPendingMessages = 10
var MaxNonceGap = uint64(4)
var DefaultMaxFee = abi.TokenAmount(types.MustParseFIL("0.007"))
var (
ErrMessageTooBig = errors.New("message too big")
@@ -183,7 +185,7 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount {
func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) {
if maxFee.Equals(big.Zero()) {
maxFee = types.NewInt(build.FilecoinPrecision / 10)
maxFee = DefaultMaxFee
}
gl := types.NewInt(uint64(msg.GasLimit))
@@ -368,11 +370,23 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journ
return err
})
if err := mp.loadLocal(); err != nil {
log.Errorf("loading local messages: %+v", err)
}
mp.curTsLk.Lock()
mp.lk.Lock()
go mp.runLoop()
go func() {
err := mp.loadLocal()
mp.lk.Unlock()
mp.curTsLk.Unlock()
if err != nil {
log.Errorf("loading local messages: %+v", err)
}
log.Info("mpool ready")
mp.runLoop()
}()
return mp, nil
}
@@ -665,11 +679,12 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
return err
}
mp.curTsLk.Lock()
defer mp.curTsLk.Unlock()
curTs := mp.curTs
if curTs == nil {
return xerrors.Errorf("current tipset not loaded")
}
snonce, err := mp.getStateNonce(m.Message.From, curTs)
if err != nil {
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
@@ -679,9 +694,6 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
return xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow)
}
mp.lk.Lock()
defer mp.lk.Unlock()
_, err = mp.verifyMsgBeforeAdd(m, curTs, true)
if err != nil {
return err
+12 -13
View File
@@ -8,7 +8,6 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/mock"
@@ -232,7 +231,7 @@ func TestMessagePool(t *testing.T) {
a := tma.nextBlock()
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -273,7 +272,7 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
a := tma.nextBlock()
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
t.Fatal(err)
}
@@ -323,7 +322,7 @@ func TestRevertMessages(t *testing.T) {
a := tma.nextBlock()
b := tma.nextBlock()
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
t.Fatal(err)
}
@@ -386,7 +385,7 @@ func TestPruningSimple(t *testing.T) {
a := tma.nextBlock()
tma.applyBlock(t, a)
sender, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
sender, err := w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
t.Fatal(err)
}
@@ -433,7 +432,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -443,7 +442,7 @@ func TestLoadLocal(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -505,7 +504,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -515,7 +514,7 @@ func TestClearAll(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -559,7 +558,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -569,7 +568,7 @@ func TestClearNonLocal(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -620,7 +619,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -630,7 +629,7 @@ func TestUpdates(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
+3 -3
View File
@@ -5,8 +5,8 @@ import (
"testing"
"time"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/ipfs/go-datastore"
@@ -33,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -43,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
+21 -22
View File
@@ -18,7 +18,6 @@ import (
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"
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
"github.com/filecoin-project/lotus/chain/types"
@@ -77,7 +76,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -87,7 +86,7 @@ func TestMessageChains(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -315,7 +314,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -325,7 +324,7 @@ func TestMessageChainSkipping(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -391,7 +390,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -401,7 +400,7 @@ func TestBasicMessageSelection(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -535,7 +534,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -545,7 +544,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -598,7 +597,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -608,7 +607,7 @@ func TestPriorityMessageSelection(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -677,7 +676,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -687,7 +686,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -746,7 +745,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -756,7 +755,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -843,7 +842,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -853,7 +852,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -910,7 +909,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a1, err := w1.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -920,7 +919,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatal(err)
}
a2, err := w2.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -994,7 +993,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
t.Fatal(err)
}
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -1074,7 +1073,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
t.Fatal(err)
}
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -1344,7 +1343,7 @@ readLoop:
t.Fatal(err)
}
a, err := w.WalletNew(context.Background(), crypto.SigTypeSecp256k1)
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
+4 -5
View File
@@ -9,7 +9,6 @@ import (
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/stretchr/testify/require"
ds_sync "github.com/ipfs/go-datastore/sync"
@@ -47,13 +46,13 @@ func TestMessageSignerSignMessage(t *testing.T) {
ctx := context.Background()
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
from1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
from1, err := w.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
from2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
from2, err := w.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
to1, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
to1, err := w.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
to2, err := w.WalletNew(ctx, crypto.SigTypeSecp256k1)
to2, err := w.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
type msgSpec struct {
+46 -21
View File
@@ -26,16 +26,18 @@ var log = logging.Logger("statetree")
// StateTree stores actors state by their ID.
type StateTree struct {
root adt.Map
version types.StateTreeVersion
info cid.Cid
Store cbor.IpldStore
root adt.Map
version types.StateTreeVersion
info cid.Cid
Store cbor.IpldStore
lookupIDFun func(address.Address) (address.Address, error)
snaps *stateSnaps
}
type stateSnaps struct {
layers []*stateSnapLayer
layers []*stateSnapLayer
lastMaybeNonEmptyResolveCache int
}
type stateSnapLayer struct {
@@ -67,7 +69,12 @@ func (ss *stateSnaps) addLayer() {
func (ss *stateSnaps) dropLayer() {
ss.layers[len(ss.layers)-1] = nil // allow it to be GCed
ss.layers = ss.layers[:len(ss.layers)-1]
if ss.lastMaybeNonEmptyResolveCache == len(ss.layers) {
ss.lastMaybeNonEmptyResolveCache = len(ss.layers) - 1
}
}
func (ss *stateSnaps) mergeLastLayer() {
@@ -86,7 +93,13 @@ func (ss *stateSnaps) mergeLastLayer() {
}
func (ss *stateSnaps) resolveAddress(addr address.Address) (address.Address, bool) {
for i := len(ss.layers) - 1; i >= 0; i-- {
for i := ss.lastMaybeNonEmptyResolveCache; i >= 0; i-- {
if len(ss.layers[i].resolveCache) == 0 {
if ss.lastMaybeNonEmptyResolveCache == i {
ss.lastMaybeNonEmptyResolveCache = i - 1
}
continue
}
resa, ok := ss.layers[i].resolveCache[addr]
if ok {
return resa, true
@@ -97,6 +110,7 @@ func (ss *stateSnaps) resolveAddress(addr address.Address) (address.Address, boo
func (ss *stateSnaps) cacheResolveAddress(addr, resa address.Address) {
ss.layers[len(ss.layers)-1].resolveCache[addr] = resa
ss.lastMaybeNonEmptyResolveCache = len(ss.layers) - 1
}
func (ss *stateSnaps) getActor(addr address.Address) (*types.Actor, error) {
@@ -160,13 +174,15 @@ func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, e
return nil, err
}
return &StateTree{
s := &StateTree{
root: root,
info: info,
version: ver,
Store: cst,
snaps: newStateSnaps(),
}, nil
}
s.lookupIDFun = s.lookupIDinternal
return s, nil
}
func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
@@ -190,13 +206,15 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
return nil, err
}
return &StateTree{
s := &StateTree{
root: nd,
info: root.Info,
version: root.Version,
Store: cst,
snaps: newStateSnaps(),
}, nil
}
s.lookupIDFun = s.lookupIDinternal
return s, nil
default:
return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version)
}
@@ -213,17 +231,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
return nil
}
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`.
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
if addr.Protocol() == address.ID {
return addr, nil
}
resa, ok := st.snaps.resolveAddress(addr)
if ok {
return resa, nil
}
func (st *StateTree) lookupIDinternal(addr address.Address) (address.Address, error) {
act, err := st.GetActor(init_.Address)
if err != nil {
return address.Undef, xerrors.Errorf("getting init actor: %w", err)
@@ -241,6 +249,23 @@ func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
if err != nil {
return address.Undef, xerrors.Errorf("resolve address %s: %w", addr, err)
}
return a, err
}
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`.
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
if addr.Protocol() == address.ID {
return addr, nil
}
resa, ok := st.snaps.resolveAddress(addr)
if ok {
return resa, nil
}
a, err := st.lookupIDFun(addr)
if err != nil {
return a, err
}
st.snaps.cacheResolveAddress(addr, a)
+97
View File
@@ -73,6 +73,103 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
}
}
func TestResolveCache(t *testing.T) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
if err != nil {
t.Fatal(err)
}
nonId := address.NewForTestGetter()()
id, _ := address.NewIDAddress(1000)
st.lookupIDFun = func(a address.Address) (address.Address, error) {
if a == nonId {
return id, nil
}
return address.Undef, types.ErrActorNotFound
}
err = st.SetActor(nonId, &types.Actor{Nonce: 1})
if err != nil {
t.Fatal(err)
}
{
err = st.Snapshot(context.TODO())
if err != nil {
t.Fatal(err)
}
act, err := st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 1 {
t.Fatalf("expected nonce 1, got %d", act.Nonce)
}
err = st.SetActor(nonId, &types.Actor{Nonce: 2})
if err != nil {
t.Fatal(err)
}
act, err = st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 2 {
t.Fatalf("expected nonce 2, got %d", act.Nonce)
}
if err := st.Revert(); err != nil {
t.Fatal(err)
}
st.ClearSnapshot()
}
act, err := st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 1 {
t.Fatalf("expected nonce 1, got %d", act.Nonce)
}
{
err = st.Snapshot(context.TODO())
if err != nil {
t.Fatal(err)
}
act, err := st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 1 {
t.Fatalf("expected nonce 1, got %d", act.Nonce)
}
err = st.SetActor(nonId, &types.Actor{Nonce: 2})
if err != nil {
t.Fatal(err)
}
act, err = st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 2 {
t.Fatalf("expected nonce 2, got %d", act.Nonce)
}
st.ClearSnapshot()
}
act, err = st.GetActor(nonId)
if err != nil {
t.Fatal(err)
}
if act.Nonce != 2 {
t.Fatalf("expected nonce 2, got %d", act.Nonce)
}
}
func BenchmarkStateTree10kGetActor(b *testing.B) {
cst := cbor.NewMemCborStore()
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
+5 -2
View File
@@ -61,7 +61,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
Rand: store.NewChainRand(sm.cs, ts.Cids()),
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
CircSupplyCalc: sm.GetCirculatingSupply,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: types.NewInt(0),
}
@@ -113,6 +113,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
}
return &api.InvocResult{
MsgCid: msg.Cid(),
Msg: msg,
MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace,
@@ -174,7 +175,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
CircSupplyCalc: sm.GetCirculatingSupply,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
@@ -228,8 +229,10 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
}
return &api.InvocResult{
MsgCid: msg.Cid(),
Msg: msg,
MsgRct: &ret.MessageReceipt,
GasCost: MakeMsgGasCost(msg, ret),
ExecutionTrace: ret.ExecutionTrace,
Error: errs,
Duration: ret.Duration,
+108 -47
View File
@@ -79,9 +79,12 @@ func DefaultUpgradeSchedule() UpgradeSchedule {
Network: network.Version4,
Expensive: true,
Migration: UpgradeActorsV2,
}, {
Height: build.UpgradeTapeHeight,
Network: network.Version5,
}, {
Height: build.UpgradeLiftoffHeight,
Network: network.Version4,
Network: network.Version5,
Migration: UpgradeLiftoff,
}}
@@ -165,7 +168,7 @@ func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEp
return ok
}
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount, cb func(trace types.ExecutionTrace)) error {
fromAct, err := tree.GetActor(from)
if err != nil {
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
@@ -198,7 +201,6 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
From: from,
To: to,
Value: amt,
Nonce: math.MaxUint64,
}
fakeRct := &types.MessageReceipt{
ExitCode: 0,
@@ -206,22 +208,14 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
GasUsed: 0,
}
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
MessageReceipt: *fakeRct,
ActorErr: nil,
ExecutionTrace: types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: fakeRct,
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: nil,
},
Duration: 0,
GasCosts: vm.ZeroGasOutputs(),
}); err != nil {
return xerrors.Errorf("recording transfer: %w", err)
}
cb(types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: fakeRct,
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: nil,
})
}
return nil
@@ -262,11 +256,6 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
}
ReserveAddress, err := address.NewFromString("t090")
if err != nil {
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
}
tree, err := sm.StateTree(root)
if err != nil {
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
@@ -279,6 +268,10 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
}
var transfers []transfer
subcalls := make([]types.ExecutionTrace, 0)
transferCb := func(trace types.ExecutionTrace) {
subcalls = append(subcalls, trace)
}
// Take all excess funds away, put them into the reserve account
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
@@ -292,7 +285,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
if !sysAcc {
transfers = append(transfers, transfer{
From: addr,
To: ReserveAddress,
To: builtin.ReserveAddress,
Amt: act.Balance,
})
}
@@ -314,11 +307,13 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
available = st.GetAvailableBalance(act.Balance)
}
transfers = append(transfers, transfer{
From: addr,
To: ReserveAddress,
Amt: available,
})
if !available.IsZero() {
transfers = append(transfers, transfer{
From: addr,
To: builtin.ReserveAddress,
Amt: available,
})
}
}
return nil
})
@@ -328,7 +323,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
// Execute transfers from previous step
for _, t := range transfers {
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
}
}
@@ -367,7 +362,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
nbalance := big.Min(prevBalance, AccountCap)
if nbalance.Sign() != 0 {
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: addr,
Amt: nbalance,
})
@@ -394,7 +389,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
mfunds := minerFundsAlloc(power, totalPower)
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: minfo.Worker,
Amt: mfunds,
})
@@ -414,7 +409,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
if lbsectors.Length() > 0 {
transfersBack = append(transfersBack, transfer{
From: ReserveAddress,
From: builtin.ReserveAddress,
To: minfo.Worker,
Amt: BaseMinerBalance,
})
@@ -431,7 +426,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
}
for _, t := range transfersBack {
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
}
}
@@ -441,7 +436,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
if err != nil {
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
}
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
if err := doTransfer(tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance, transferCb); err != nil {
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
}
@@ -457,7 +452,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
}
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
if err := doTransfer(tree, builtin.ReserveAddress, reimbAddr, difference, transferCb); err != nil {
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
}
@@ -476,6 +471,39 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
return cid.Undef, xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
}
if cb != nil {
// record the transfer in execution traces
fakeMsg := &types.Message{
From: builtin.SystemActorAddr,
To: builtin.SystemActorAddr,
Value: big.Zero(),
Nonce: uint64(epoch),
}
fakeRct := &types.MessageReceipt{
ExitCode: 0,
Return: nil,
GasUsed: 0,
}
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
MessageReceipt: *fakeRct,
ActorErr: nil,
ExecutionTrace: types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: fakeRct,
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: subcalls,
},
Duration: 0,
GasCosts: nil,
}); err != nil {
return cid.Undef, xerrors.Errorf("recording transfers: %w", err)
}
}
return tree.Flush(ctx)
}
@@ -516,12 +544,12 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err)
}
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50)
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50, epoch)
if err != nil {
return cid.Undef, xerrors.Errorf("splitting first msig: %w", err)
}
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50)
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50, epoch)
if err != nil {
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
}
@@ -542,12 +570,7 @@ func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
}
addr, err := address.NewFromString("t0122")
if err != nil {
return cid.Undef, xerrors.Errorf("getting address: %w", err)
}
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
err = resetMultisigVesting(ctx, store, tree, builtin.SaftAddress, 0, 0, big.Zero())
if err != nil {
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
}
@@ -652,7 +675,7 @@ func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree,
return nil
}
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64) error {
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64, epoch abi.ChainEpoch) error {
if portions < 1 {
return xerrors.Errorf("cannot split into 0 portions")
}
@@ -721,6 +744,11 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
}
i := uint64(0)
subcalls := make([]types.ExecutionTrace, 0, portions)
transferCb := func(trace types.ExecutionTrace) {
subcalls = append(subcalls, trace)
}
for i < portions {
keyAddr, err := makeKeyAddr(addr, i)
if err != nil {
@@ -737,13 +765,46 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
return xerrors.Errorf("setting new msig actor state: %w", err)
}
if err := doTransfer(cb, tree, addr, idAddr, newIbal); err != nil {
if err := doTransfer(tree, addr, idAddr, newIbal, transferCb); err != nil {
return xerrors.Errorf("transferring split msig balance: %w", err)
}
i++
}
if cb != nil {
// record the transfer in execution traces
fakeMsg := &types.Message{
From: builtin.SystemActorAddr,
To: addr,
Value: big.Zero(),
Nonce: uint64(epoch),
}
fakeRct := &types.MessageReceipt{
ExitCode: 0,
Return: nil,
GasUsed: 0,
}
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
MessageReceipt: *fakeRct,
ActorErr: nil,
ExecutionTrace: types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: fakeRct,
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: subcalls,
},
Duration: 0,
GasCosts: nil,
}); err != nil {
return xerrors.Errorf("recording transfers: %w", err)
}
}
return nil
}
+111 -29
View File
@@ -7,6 +7,11 @@ import (
"sync"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
@@ -195,6 +200,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
func traceFunc(trace *[]*api.InvocResult) func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
return func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
ir := &api.InvocResult{
MsgCid: mcid,
Msg: msg,
MsgRct: &ret.MessageReceipt,
ExecutionTrace: ret.ExecutionTrace,
@@ -203,6 +209,9 @@ func traceFunc(trace *[]*api.InvocResult) func(mcid cid.Cid, msg *types.Message,
if ret.ActorErr != nil {
ir.Error = ret.ActorErr.Error()
}
if ret.GasCosts != nil {
ir.GasCost = MakeMsgGasCost(msg, ret)
}
*trace = append(*trace, ir)
return nil
}
@@ -229,7 +238,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
CircSupplyCalc: sm.GetCirculatingSupply,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: baseFee,
}
@@ -242,17 +251,12 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
}
runCron := func() error {
// TODO: this nonce-getting is a tiny bit ugly
ca, err := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
if err != nil {
return err
}
runCron := func(epoch abi.ChainEpoch) error {
cronMsg := &types.Message{
To: builtin0.CronActorAddr,
From: builtin0.SystemActorAddr,
Nonce: ca.Nonce,
Nonce: uint64(epoch),
Value: types.NewInt(0),
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
@@ -279,7 +283,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
for i := parentEpoch; i < epoch; i++ {
if i > parentEpoch {
// run cron for null rounds if any
if err := runCron(); err != nil {
if err := runCron(i); err != nil {
return cid.Undef, cid.Undef, err
}
@@ -308,7 +312,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
}
var receipts []cbg.CBORMarshaler
processedMsgs := map[cid.Cid]bool{}
processedMsgs := make(map[cid.Cid]struct{})
for _, b := range bms {
penalty := types.NewInt(0)
gasReward := big.Zero()
@@ -332,7 +336,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
return cid.Undef, cid.Undef, err
}
}
processedMsgs[m.Cid()] = true
processedMsgs[m.Cid()] = struct{}{}
}
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
@@ -345,15 +349,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
}
sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
if actErr != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", actErr)
}
rwMsg := &types.Message{
From: builtin0.SystemActorAddr,
To: reward.Address,
Nonce: sysAct.Nonce,
Nonce: uint64(epoch),
Value: types.NewInt(0),
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
@@ -376,7 +375,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
}
}
if err := runCron(); err != nil {
if err := runCron(epoch); err != nil {
return cid.Cid{}, cid.Cid{}, err
}
@@ -430,12 +429,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
parentEpoch = parent.Height
}
cids := make([]cid.Cid, len(blks))
for i, v := range blks {
cids[i] = v.Cid()
}
r := store.NewChainRand(sm.cs, cids)
r := store.NewChainRand(sm.cs, ts.Cids())
blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
if err != nil {
@@ -733,7 +727,7 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
}
if r != nil {
return pts, r, foundMsg, nil
return cur, r, foundMsg, nil
}
}
@@ -1294,7 +1288,16 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
return burnt.Balance, nil
}
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
cs, err := sm.GetVMCirculatingSupplyDetailed(ctx, height, st)
if err != nil {
return types.EmptyInt, err
}
return cs.FilCirculating, err
}
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
sm.genesisMsigLk.Lock()
defer sm.genesisMsigLk.Unlock()
if sm.preIgnitionGenInfos == nil {
@@ -1357,12 +1360,91 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
}
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
circ := big.Zero()
unCirc := big.Zero()
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
switch {
case actor.Balance.IsZero():
// Do nothing for zero-balance actors
break
case a == _init.Address ||
a == reward.Address ||
a == verifreg.Address ||
// The power actor itself should never receive funds
a == power.Address ||
a == builtin.SystemActorAddr ||
a == builtin.CronActorAddr ||
a == builtin.BurntFundsActorAddr ||
a == builtin.SaftAddress ||
a == builtin.ReserveAddress:
unCirc = big.Add(unCirc, actor.Balance)
case a == market.Address:
mst, err := market.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}
lb, err := mst.TotalLocked()
if err != nil {
return err
}
circ = big.Add(circ, big.Sub(actor.Balance, lb))
unCirc = big.Add(unCirc, lb)
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
circ = big.Add(circ, actor.Balance)
case builtin.IsStorageMinerActor(actor.Code):
mst, err := miner.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}
ab, err := mst.AvailableBalance(actor.Balance)
if err == nil {
circ = big.Add(circ, ab)
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
} else {
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
// In this case, the actor's entire balance is considered "uncirculating"
unCirc = big.Add(unCirc, actor.Balance)
}
case builtin.IsMultisigActor(actor.Code):
mst, err := multisig.Load(sm.cs.Store(ctx), actor)
if err != nil {
return err
}
lb, err := mst.LockedBalance(height)
if err != nil {
return err
}
ab := big.Sub(actor.Balance, lb)
circ = big.Add(circ, big.Max(ab, big.Zero()))
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
default:
return xerrors.Errorf("unexpected actor: %s", a)
}
return nil
})
if err != nil {
return big.Zero(), err
return types.EmptyInt, err
}
return csi.FilCirculating, nil
total := big.Add(circ, unCirc)
if !total.Equals(types.TotalFilecoinInt) {
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
}
return circ, nil
}
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
+14 -1
View File
@@ -383,7 +383,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
CircSupplyCalc: sm.GetCirculatingSupply,
CircSupplyCalc: sm.GetVMCirculatingSupply,
NtwkVersion: sm.GetNtwkVersion,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
@@ -701,3 +701,16 @@ func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi
return sum, nil
}
func MakeMsgGasCost(msg *types.Message, ret *vm.ApplyRet) api.MsgGasCost {
return api.MsgGasCost{
Message: msg.Cid(),
GasUsed: big.NewInt(ret.GasUsed),
BaseFeeBurn: ret.GasCosts.BaseFeeBurn,
OverEstimationBurn: ret.GasCosts.OverEstimationBurn,
MinerPenalty: ret.GasCosts.MinerPenalty,
MinerTip: ret.GasCosts.MinerTip,
Refund: ret.GasCosts.Refund,
TotalCost: big.Sub(msg.RequiredFunds(), ret.GasCosts.Refund),
}
}
+51 -1
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
@@ -446,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 {
+11
View File
@@ -37,6 +37,7 @@ import (
"github.com/filecoin-project/lotus/lib/bufbstore"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/node/impl/client"
)
var log = logging.Logger("sub")
@@ -44,6 +45,13 @@ var log = logging.Logger("sub")
var ErrSoftFailure = errors.New("soft validation failure")
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
var msgCidPrefix = cid.Prefix{
Version: 1,
Codec: cid.DagCBOR,
MhType: client.DefaultHashFunction,
MhLength: 32,
}
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bs bserv.BlockService, cmgr connmgr.ConnManager) {
// Timeout after (block time + propagation delay). This is useless at
// this point.
@@ -168,6 +176,9 @@ func fetchCids(
cidIndex := make(map[cid.Cid]int)
for i, c := range cids {
if c.Prefix() != msgCidPrefix {
return fmt.Errorf("invalid msg CID: %s", c)
}
cidIndex[c] = i
}
if len(cids) != len(cidIndex) {
+53 -41
View File
@@ -323,25 +323,35 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
return xerrors.Errorf("block %s has too many messages (%d)", fblk.Header.Cid(), msgc)
}
// Collect the CIDs of both types of messages separately: BLS and Secpk.
var bcids, scids []cid.Cid
for _, m := range fblk.BlsMessages {
bcids = append(bcids, m.Cid())
}
for _, m := range fblk.SecpkMessages {
scids = append(scids, m.Cid())
}
// TODO: IMPORTANT(GARBAGE). These message puts and the msgmeta
// computation need to go into the 'temporary' side of the blockstore when
// we implement that
blockstore := syncer.store.Blockstore()
bs := cbor.NewCborStore(blockstore)
// We use a temporary bstore here to avoid writing intermediate pieces
// into the blockstore.
blockstore := bstore.NewTemporary()
cst := cbor.NewCborStore(blockstore)
var bcids, scids []cid.Cid
for _, m := range fblk.BlsMessages {
c, err := store.PutMessage(blockstore, m)
if err != nil {
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
}
bcids = append(bcids, c)
}
for _, m := range fblk.SecpkMessages {
c, err := store.PutMessage(blockstore, m)
if err != nil {
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
}
scids = append(scids, c)
}
// Compute the root CID of the combined message trie.
smroot, err := computeMsgMeta(bs, bcids, scids)
smroot, err := computeMsgMeta(cst, bcids, scids)
if err != nil {
return xerrors.Errorf("validating msgmeta, compute failed: %w", err)
}
@@ -351,21 +361,8 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error {
return xerrors.Errorf("messages in full block did not match msgmeta root in header (%s != %s)", fblk.Header.Messages, smroot)
}
for _, m := range fblk.BlsMessages {
_, err := store.PutMessage(blockstore, m)
if err != nil {
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
}
}
for _, m := range fblk.SecpkMessages {
_, err := store.PutMessage(blockstore, m)
if err != nil {
return xerrors.Errorf("putting bls message to blockstore after msgmeta computation: %w", err)
}
}
return nil
// Finally, flush.
return vm.Copy(context.TODO(), blockstore, syncer.store.Blockstore(), smroot)
}
func (syncer *Syncer) LocalPeer() peer.ID {
@@ -1064,8 +1061,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return err
}
cst := cbor.NewCborStore(syncer.store.Blockstore())
st, err := state.LoadStateTree(cst, stateroot)
st, err := state.LoadStateTree(syncer.store.Store(ctx), stateroot)
if err != nil {
return xerrors.Errorf("failed to load base state tree: %w", err)
}
@@ -1111,21 +1107,28 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return nil
}
store := adt0.WrapStore(ctx, cst)
// Validate message arrays in a temporary blockstore.
tmpbs := bstore.NewTemporary()
tmpstore := adt0.WrapStore(ctx, cbor.NewCborStore(tmpbs))
bmArr := adt0.MakeEmptyArray(store)
bmArr := adt0.MakeEmptyArray(tmpstore)
for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
}
c := cbg.CborCid(m.Cid())
if err := bmArr.Set(uint64(i), &c); err != nil {
c, err := store.PutMessage(tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := bmArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
}
}
smArr := adt0.MakeEmptyArray(store)
smArr := adt0.MakeEmptyArray(tmpstore)
for i, m := range b.SecpkMessages {
if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
@@ -1142,8 +1145,12 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
}
c := cbg.CborCid(m.Cid())
if err := smArr.Set(uint64(i), &c); err != nil {
c, err := store.PutMessage(tmpbs, m)
if err != nil {
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
}
k := cbg.CborCid(c)
if err := smArr.Set(uint64(i), &k); err != nil {
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
}
}
@@ -1158,7 +1165,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return err
}
mrcid, err := cst.Put(ctx, &types.MsgMeta{
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
BlsMessages: bmroot,
SecpkMessages: smroot,
})
@@ -1170,7 +1177,8 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return fmt.Errorf("messages didnt match message root in header")
}
return nil
// Finally, flush.
return vm.Copy(ctx, tmpbs, syncer.store.Blockstore(), mrcid)
}
func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signature, msgs []cid.Cid, pubks [][]byte) error {
@@ -1478,7 +1486,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*types.TipSet) error {
ss := extractSyncState(ctx)
ss.SetHeight(0)
ss.SetHeight(headers[len(headers)-1].Height())
return syncer.iterFullTipsets(ctx, headers, func(ctx context.Context, fts *store.FullTipSet) error {
log.Debugw("validating tipset", "height", fts.TipSet().Height(), "size", len(fts.TipSet().Cids()))
@@ -1726,7 +1734,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()
}
@@ -1740,6 +1748,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:
+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
}
+9
View File
@@ -81,5 +81,14 @@ func ParseFIL(s string) (FIL, error) {
return FIL{r.Num()}, nil
}
func MustParseFIL(s string) FIL {
n, err := ParseFIL(s)
if err != nil {
panic(err)
}
return n
}
var _ encoding.TextMarshaler = (*FIL)(nil)
var _ encoding.TextUnmarshaler = (*FIL)(nil)
+45 -1
View File
@@ -1,7 +1,10 @@
package types
import (
"encoding/json"
"fmt"
"github.com/filecoin-project/go-state-types/crypto"
)
var (
@@ -9,9 +12,50 @@ var (
ErrKeyExists = fmt.Errorf("key already exists")
)
// KeyType defines a type of a key
type KeyType string
func (kt *KeyType) UnmarshalJSON(bb []byte) error {
{
// first option, try unmarshaling as string
var s string
err := json.Unmarshal(bb, &s)
if err == nil {
*kt = KeyType(s)
return nil
}
}
{
var b byte
err := json.Unmarshal(bb, &b)
if err != nil {
return fmt.Errorf("could not unmarshal KeyType either as string nor integer: %w", err)
}
bst := crypto.SigType(b)
switch bst {
case crypto.SigTypeBLS:
*kt = KTBLS
case crypto.SigTypeSecp256k1:
*kt = KTSecp256k1
default:
return fmt.Errorf("unknown sigtype: %d", bst)
}
log.Warnf("deprecation: integer style 'KeyType' is deprecated, switch to string style")
return nil
}
}
const (
KTBLS KeyType = "bls"
KTSecp256k1 KeyType = "secp256k1"
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
)
// KeyInfo is used for storing keys in KeyStore
type KeyInfo struct {
Type string
Type KeyType
PrivateKey []byte
}
+16 -1
View File
@@ -2,6 +2,7 @@ package types
import (
"bytes"
"encoding/json"
"fmt"
"github.com/filecoin-project/go-state-types/abi"
@@ -106,6 +107,20 @@ func (m *Message) Cid() cid.Cid {
return b.Cid()
}
type mCid struct {
*RawMessage
CID cid.Cid
}
type RawMessage Message
func (m *Message) MarshalJSON() ([]byte, error) {
return json.Marshal(&mCid{
RawMessage: (*RawMessage)(m),
CID: m.Cid(),
})
}
func (m *Message) RequiredFunds() BigInt {
return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
}
@@ -180,7 +195,7 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error {
// since prices might vary with time, this is technically semantic validation
if m.GasLimit < minGas {
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
return xerrors.Errorf("'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d", m.GasLimit, minGas)
}
return nil
+66
View File
@@ -1,11 +1,14 @@
package types
import (
"encoding/json"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/specs-actors/actors/builtin"
)
@@ -70,3 +73,66 @@ func TestEqualCall(t *testing.T) {
require.True(t, m1.EqualCall(m3))
require.False(t, m1.EqualCall(m4))
}
func TestMessageJson(t *testing.T) {
m := &Message{
To: builtin.StoragePowerActorAddr,
From: builtin.SystemActorAddr,
Nonce: 34,
Value: big.Zero(),
GasLimit: 123,
GasFeeCap: big.NewInt(234),
GasPremium: big.NewInt(234),
Method: 6,
Params: []byte("hai"),
}
b, err := json.Marshal(m)
require.NoError(t, err)
exp := []byte("{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}}")
fmt.Println(string(b))
require.Equal(t, exp, b)
var um Message
require.NoError(t, json.Unmarshal(b, &um))
require.EqualValues(t, *m, um)
}
func TestSignedMessageJson(t *testing.T) {
m := Message{
To: builtin.StoragePowerActorAddr,
From: builtin.SystemActorAddr,
Nonce: 34,
Value: big.Zero(),
GasLimit: 123,
GasFeeCap: big.NewInt(234),
GasPremium: big.NewInt(234),
Method: 6,
Params: []byte("hai"),
}
sm := &SignedMessage{
Message: m,
Signature: crypto.Signature{},
}
b, err := json.Marshal(sm)
require.NoError(t, err)
exp := []byte("{\"Message\":{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}},\"Signature\":{\"Type\":0,\"Data\":null},\"CID\":{\"/\":\"bafy2bzacea5ainifngxj3rygaw2hppnyz2cw72x5pysqty2x6dxmjs5qg2uus\"}}")
fmt.Println(string(b))
require.Equal(t, exp, b)
var um SignedMessage
require.NoError(t, json.Unmarshal(b, &um))
require.EqualValues(t, *sm, um)
}
+23 -1
View File
@@ -2,6 +2,7 @@ package types
import (
"bytes"
"encoding/json"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
@@ -62,8 +63,29 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
return buf.Bytes(), nil
}
type smCid struct {
*RawSignedMessage
CID cid.Cid
}
type RawSignedMessage SignedMessage
func (sm *SignedMessage) MarshalJSON() ([]byte, error) {
return json.Marshal(&smCid{
RawSignedMessage: (*RawSignedMessage)(sm),
CID: sm.Cid(),
})
}
func (sm *SignedMessage) ChainLength() int {
ser, err := sm.Serialize()
var ser []byte
var err error
if sm.Signature.Type == crypto.SigTypeBLS {
// BLS chain message length doesn't include signature
ser, err = sm.Message.Serialize()
} else {
ser, err = sm.Serialize()
}
if err != nil {
panic(err)
}
+2 -3
View File
@@ -11,7 +11,6 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/types"
@@ -62,7 +61,7 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
panic(err)
}
blsk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
blsk, err := w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
panic(err)
}
@@ -86,7 +85,7 @@ func MakeMessageSigningVectors() []vectors.MessageSigningVector {
Signature: &bmsg.Signature,
}
secpk, err := w.WalletNew(context.Background(), crypto.SigTypeBLS)
secpk, err := w.WalletNew(context.Background(), types.KTBLS)
if err != nil {
panic(err)
}
+8 -8
View File
@@ -214,7 +214,7 @@ type ApplyRet struct {
ActorErr aerrors.ActorError
ExecutionTrace types.ExecutionTrace
Duration time.Duration
GasCosts GasOutputs
GasCosts *GasOutputs
}
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
@@ -361,7 +361,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
GasCosts: GasOutputs{},
GasCosts: nil,
Duration: time.Since(start),
}, actorErr
}
@@ -397,7 +397,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ExitCode: exitcode.SysErrOutOfGas,
GasUsed: 0,
},
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
@@ -417,7 +417,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
@@ -434,7 +434,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
GasUsed: 0,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
@@ -450,7 +450,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
@@ -466,7 +466,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
},
ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid,
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
@@ -560,7 +560,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
GasCosts: gasOutputs,
GasCosts: &gasOutputs,
Duration: time.Since(start),
}, nil
}
+14 -21
View File
@@ -10,13 +10,17 @@ import (
"github.com/filecoin-project/lotus/lib/sigs"
)
func GenerateKey(typ crypto.SigType) (*Key, error) {
pk, err := sigs.Generate(typ)
func GenerateKey(typ types.KeyType) (*Key, error) {
ctyp := ActSigType(typ)
if ctyp == crypto.SigTypeUnknown {
return nil, xerrors.Errorf("unknown sig type: %s", typ)
}
pk, err := sigs.Generate(ctyp)
if err != nil {
return nil, err
}
ki := types.KeyInfo{
Type: kstoreSigType(typ),
Type: typ,
PrivateKey: pk,
}
return NewKey(ki)
@@ -41,41 +45,30 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
}
switch k.Type {
case KTSecp256k1:
case types.KTSecp256k1:
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
}
case KTBLS:
case types.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 nil, xerrors.Errorf("unsupported key type: %s", k.Type)
}
return k, nil
}
func kstoreSigType(typ crypto.SigType) string {
func ActSigType(typ types.KeyType) crypto.SigType {
switch typ {
case crypto.SigTypeBLS:
return KTBLS
case crypto.SigTypeSecp256k1:
return KTSecp256k1
default:
return ""
}
}
func ActSigType(typ string) crypto.SigType {
switch typ {
case KTBLS:
case types.KTBLS:
return crypto.SigTypeBLS
case KTSecp256k1:
case types.KTSecp256k1:
return crypto.SigTypeSecp256k1
default:
return 0
return crypto.SigTypeUnknown
}
}
+242
View File
@@ -0,0 +1,242 @@
package ledgerwallet
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/query"
logging "github.com/ipfs/go-log"
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
var log = logging.Logger("wallet-ledger")
type LedgerWallet struct {
ds datastore.Datastore
}
func NewWallet(ds dtypes.MetadataDS) *LedgerWallet {
return &LedgerWallet{ds}
}
type LedgerKeyInfo struct {
Address address.Address
Path []uint32
}
var _ api.WalletAPI = (*LedgerWallet)(nil)
func (lw LedgerWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
ki, err := lw.getKeyInfo(signer)
if err != nil {
return nil, err
}
fl, err := ledgerfil.FindLedgerFilecoinApp()
if err != nil {
return nil, err
}
defer fl.Close() // nolint:errcheck
if meta.Type != api.MTChainMsg {
return nil, fmt.Errorf("ledger can only sign chain messages")
}
{
var cmsg types.Message
if err := cmsg.UnmarshalCBOR(bytes.NewReader(meta.Extra)); err != nil {
return nil, xerrors.Errorf("unmarshalling message: %w", err)
}
_, bc, err := cid.CidFromBytes(toSign)
if err != nil {
return nil, xerrors.Errorf("getting cid from signing bytes: %w", err)
}
if !cmsg.Cid().Equals(bc) {
return nil, xerrors.Errorf("cid(meta.Extra).bytes() != toSign")
}
}
sig, err := fl.SignSECP256K1(ki.Path, meta.Extra)
if err != nil {
return nil, err
}
return &crypto.Signature{
Type: crypto.SigTypeSecp256k1,
Data: sig.SignatureBytes(),
}, nil
}
func (lw LedgerWallet) getKeyInfo(addr address.Address) (*LedgerKeyInfo, error) {
kib, err := lw.ds.Get(keyForAddr(addr))
if err != nil {
return nil, err
}
var out LedgerKeyInfo
if err := json.Unmarshal(kib, &out); err != nil {
return nil, xerrors.Errorf("unmarshalling ledger key info: %w", err)
}
return &out, nil
}
func (lw LedgerWallet) WalletDelete(ctx context.Context, k address.Address) error {
return lw.ds.Delete(keyForAddr(k))
}
func (lw LedgerWallet) WalletExport(ctx context.Context, k address.Address) (*types.KeyInfo, error) {
return nil, fmt.Errorf("cannot export keys from ledger wallets")
}
func (lw LedgerWallet) WalletHas(ctx context.Context, k address.Address) (bool, error) {
_, err := lw.ds.Get(keyForAddr(k))
if err == nil {
return true, nil
}
if err == datastore.ErrNotFound {
return false, nil
}
return false, err
}
func (lw LedgerWallet) WalletImport(ctx context.Context, kinfo *types.KeyInfo) (address.Address, error) {
var ki LedgerKeyInfo
if err := json.Unmarshal(kinfo.PrivateKey, &ki); err != nil {
return address.Undef, err
}
return lw.importKey(ki)
}
func (lw LedgerWallet) importKey(ki LedgerKeyInfo) (address.Address, error) {
if ki.Address == address.Undef {
return address.Undef, fmt.Errorf("no address given in imported key info")
}
if len(ki.Path) != filHdPathLen {
return address.Undef, fmt.Errorf("bad hd path len: %d, expected: %d", len(ki.Path), filHdPathLen)
}
bb, err := json.Marshal(ki)
if err != nil {
return address.Undef, xerrors.Errorf("marshaling key info: %w", err)
}
if err := lw.ds.Put(keyForAddr(ki.Address), bb); err != nil {
return address.Undef, err
}
return ki.Address, nil
}
func (lw LedgerWallet) WalletList(ctx context.Context) ([]address.Address, error) {
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
if err != nil {
return nil, err
}
defer res.Close() // nolint:errcheck
var out []address.Address
for {
res, ok := res.NextSync()
if !ok {
break
}
var ki LedgerKeyInfo
if err := json.Unmarshal(res.Value, &ki); err != nil {
return nil, err
}
out = append(out, ki.Address)
}
return out, nil
}
const hdHard = 0x80000000
var filHDBasePath = []uint32{hdHard | 44, hdHard | 461, hdHard, 0}
var filHdPathLen = 5
func (lw LedgerWallet) WalletNew(ctx context.Context, t types.KeyType) (address.Address, error) {
if t != types.KTSecp256k1Ledger {
return address.Undef, fmt.Errorf("unsupported key type: '%s', only '%s' supported",
t, types.KTSecp256k1Ledger)
}
res, err := lw.ds.Query(query.Query{Prefix: dsLedgerPrefix})
if err != nil {
return address.Undef, err
}
defer res.Close() // nolint:errcheck
var maxi int64 = -1
for {
res, ok := res.NextSync()
if !ok {
break
}
var ki LedgerKeyInfo
if err := json.Unmarshal(res.Value, &ki); err != nil {
return address.Undef, err
}
if i := ki.Path[filHdPathLen-1]; maxi == -1 || maxi < int64(i) {
maxi = int64(i)
}
}
fl, err := ledgerfil.FindLedgerFilecoinApp()
if err != nil {
return address.Undef, xerrors.Errorf("finding ledger: %w", err)
}
defer fl.Close() // nolint:errcheck
path := append(append([]uint32(nil), filHDBasePath...), uint32(maxi+1))
_, _, addr, err := fl.GetAddressPubKeySECP256K1(path)
if err != nil {
return address.Undef, xerrors.Errorf("getting public key from ledger: %w", err)
}
log.Warnf("creating key: %s, accept the key in ledger device", addr)
_, _, addr, err = fl.ShowAddressPubKeySECP256K1(path)
if err != nil {
return address.Undef, xerrors.Errorf("verifying public key with ledger: %w", err)
}
a, err := address.NewFromString(addr)
if err != nil {
return address.Undef, fmt.Errorf("parsing address: %w", err)
}
var lki LedgerKeyInfo
lki.Address = a
lki.Path = path
return lw.importKey(lki)
}
func (lw *LedgerWallet) Get() api.WalletAPI {
if lw == nil {
return nil
}
return lw
}
var dsLedgerPrefix = "/ledgerkey/"
func keyForAddr(addr address.Address) datastore.Key {
return datastore.NewKey(dsLedgerPrefix + addr.String())
}
+170
View File
@@ -0,0 +1,170 @@
package wallet
import (
"context"
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
"github.com/filecoin-project/lotus/chain/wallet/remotewallet"
)
type MultiWallet struct {
fx.In // "constructed" with fx.In instead of normal constructor
Local *LocalWallet `optional:"true"`
Remote *remotewallet.RemoteWallet `optional:"true"`
Ledger *ledgerwallet.LedgerWallet `optional:"true"`
}
type getif interface {
api.WalletAPI
// workaround for the fact that iface(*struct(nil)) != nil
Get() api.WalletAPI
}
func firstNonNil(wallets ...getif) api.WalletAPI {
for _, w := range wallets {
if w.Get() != nil {
return w
}
}
return nil
}
func nonNil(wallets ...getif) []api.WalletAPI {
var out []api.WalletAPI
for _, w := range wallets {
if w.Get() == nil {
continue
}
out = append(out, w)
}
return out
}
func (m MultiWallet) find(ctx context.Context, address address.Address, wallets ...getif) (api.WalletAPI, error) {
ws := nonNil(wallets...)
for _, w := range ws {
have, err := w.WalletHas(ctx, address)
if err != nil {
return nil, err
}
if have {
return w, nil
}
}
return nil, nil
}
func (m MultiWallet) WalletNew(ctx context.Context, keyType types.KeyType) (address.Address, error) {
var local getif = m.Local
if keyType == types.KTSecp256k1Ledger {
local = m.Ledger
}
w := firstNonNil(m.Remote, local)
if w == nil {
return address.Undef, xerrors.Errorf("no wallet backends supporting key type: %s", keyType)
}
return w.WalletNew(ctx, keyType)
}
func (m MultiWallet) WalletHas(ctx context.Context, address address.Address) (bool, error) {
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
return w != nil, err
}
func (m MultiWallet) WalletList(ctx context.Context) ([]address.Address, error) {
var out []address.Address
seen := map[address.Address]struct{}{}
ws := nonNil(m.Remote, m.Ledger, m.Local)
for _, w := range ws {
l, err := w.WalletList(ctx)
if err != nil {
return nil, err
}
for _, a := range l {
if _, ok := seen[a]; ok {
continue
}
seen[a] = struct{}{}
out = append(out, a)
}
}
return out, nil
}
func (m MultiWallet) WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta api.MsgMeta) (*crypto.Signature, error) {
w, err := m.find(ctx, signer, m.Remote, m.Ledger, m.Local)
if err != nil {
return nil, err
}
if w == nil {
return nil, xerrors.Errorf("key not found")
}
return w.WalletSign(ctx, signer, toSign, meta)
}
func (m MultiWallet) WalletExport(ctx context.Context, address address.Address) (*types.KeyInfo, error) {
w, err := m.find(ctx, address, m.Remote, m.Local)
if err != nil {
return nil, err
}
if w == nil {
return nil, xerrors.Errorf("key not found")
}
return w.WalletExport(ctx, address)
}
func (m MultiWallet) WalletImport(ctx context.Context, info *types.KeyInfo) (address.Address, error) {
var local getif = m.Local
if info.Type == types.KTSecp256k1Ledger {
local = m.Ledger
}
w := firstNonNil(m.Remote, local)
if w == nil {
return address.Undef, xerrors.Errorf("no wallet backends configured")
}
return w.WalletImport(ctx, info)
}
func (m MultiWallet) WalletDelete(ctx context.Context, address address.Address) error {
for {
w, err := m.find(ctx, address, m.Remote, m.Ledger, m.Local)
if err != nil {
return err
}
if w == nil {
return nil
}
if err := w.WalletDelete(ctx, address); err != nil {
return err
}
}
}
var _ api.WalletAPI = MultiWallet{}
+8
View File
@@ -40,3 +40,11 @@ func SetupRemoteWallet(info string) func(mctx helpers.MetricsCtx, lc fx.Lifecycl
return &RemoteWallet{wapi}, nil
}
}
func (w *RemoteWallet) Get() api.WalletAPI {
if w == nil {
return nil
}
return w
}
+28 -3
View File
@@ -26,8 +26,6 @@ const (
KNamePrefix = "wallet-"
KTrashPrefix = "trash-"
KDefault = "default"
KTBLS = "bls"
KTSecp256k1 = "secp256k1"
)
type LocalWallet struct {
@@ -141,6 +139,9 @@ func (w *LocalWallet) WalletExport(ctx context.Context, addr address.Address) (*
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
}
@@ -233,7 +234,7 @@ func (w *LocalWallet) SetDefault(a address.Address) error {
return nil
}
func (w *LocalWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
func (w *LocalWallet) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
w.lk.Lock()
defer w.lk.Unlock()
@@ -274,6 +275,9 @@ func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) er
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)
@@ -294,6 +298,14 @@ func (w *LocalWallet) WalletDelete(ctx context.Context, addr address.Address) er
return nil
}
func (w *LocalWallet) Get() api.WalletAPI {
if w == nil {
return nil
}
return w
}
var _ api.WalletAPI = &LocalWallet{}
func swapMainnetForTestnetPrefix(addr string) (string, error) {
@@ -306,3 +318,16 @@ func swapMainnetForTestnetPrefix(addr string) (string, error) {
aChars[0] = prefixRunes[0]
return string(aChars), nil
}
type nilDefault struct{}
func (n nilDefault) GetDefault() (address.Address, error) {
return address.Undef, nil
}
func (n nilDefault) SetDefault(a address.Address) error {
return xerrors.Errorf("not supported; local wallet disabled")
}
var NilDefault nilDefault
var _ Default = NilDefault
+70 -2
View File
@@ -3,6 +3,7 @@ package cli
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"os"
@@ -53,6 +54,7 @@ var chainCmd = &cli.Command{
slashConsensusFault,
chainGasPriceCmd,
chainInspectUsage,
chainDecodeCmd,
},
}
@@ -521,8 +523,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},
@@ -1233,3 +1236,68 @@ var chainGasPriceCmd = &cli.Command{
return nil
},
}
var chainDecodeCmd = &cli.Command{
Name: "decode",
Usage: "decode various types",
Subcommands: []*cli.Command{
chainDecodeParamsCmd,
},
}
var chainDecodeParamsCmd = &cli.Command{
Name: "params",
Usage: "Decode message params",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
},
},
ArgsUsage: "[toAddr method hexParams]",
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() != 3 {
return ShowHelp(cctx, fmt.Errorf("incorrect number of arguments"))
}
to, err := address.NewFromString(cctx.Args().First())
if err != nil {
return xerrors.Errorf("parsing toAddr: %w", err)
}
method, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
if err != nil {
return xerrors.Errorf("parsing method id: %w", err)
}
params, err := hex.DecodeString(cctx.Args().Get(2))
if err != nil {
return xerrors.Errorf("parsing hex params: %w", err)
}
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
act, err := api.StateGetActor(ctx, to, ts.Key())
if err != nil {
return xerrors.Errorf("getting actor: %w", err)
}
pstr, err := jsonParams(act.Code, abi.MethodNum(method), params)
if err != nil {
return err
}
fmt.Println(pstr)
return nil
},
}
+62
View File
@@ -3,6 +3,7 @@ package cli
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@@ -82,6 +83,7 @@ var clientCmd = &cli.Command{
WithCategory("util", clientCarGenCmd),
WithCategory("util", clientInfoCmd),
WithCategory("util", clientListTransfers),
WithCategory("util", clientRestartTransfer),
},
}
@@ -1326,6 +1328,66 @@ var clientInfoCmd = &cli.Command{
},
}
var clientRestartTransfer = &cli.Command{
Name: "restart-transfer",
Usage: "Force restart a stalled data transfer",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "peerid",
Usage: "narrow to transfer with specific peer",
},
&cli.BoolFlag{
Name: "initiator",
Usage: "specify only transfers where peer is/is not initiator",
Value: true,
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
transferUint, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
if err != nil {
return fmt.Errorf("Error reading transfer ID: %w", err)
}
transferID := datatransfer.TransferID(transferUint)
initiator := cctx.Bool("initiator")
var other peer.ID
if pidstr := cctx.String("peerid"); pidstr != "" {
p, err := peer.Decode(pidstr)
if err != nil {
return err
}
other = p
} else {
channels, err := api.ClientListDataTransfers(ctx)
if err != nil {
return err
}
found := false
for _, channel := range channels {
if channel.IsInitiator == initiator && channel.TransferID == transferID {
other = channel.OtherPeer
found = true
break
}
}
if !found {
return errors.New("unable to find matching data transfer")
}
}
return api.ClientRestartDataTransfer(ctx, transferID, other, initiator)
},
}
var clientListTransfers = &cli.Command{
Name: "list-transfers",
Usage: "List ongoing data transfers for deals",
+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) {
+268 -55
View File
@@ -3,8 +3,9 @@ package cli
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"reflect"
"sort"
"strconv"
"text/tabwriter"
@@ -14,12 +15,15 @@ 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"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-address"
cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
@@ -37,10 +41,18 @@ import (
var multisigCmd = &cli.Command{
Name: "msig",
Usage: "Interact with a multisig wallet",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "confidence",
Usage: "number of block confirmations to wait for",
Value: int(build.MessageConfidence),
},
},
Subcommands: []*cli.Command{
msigCreateCmd,
msigInspectCmd,
msigProposeCmd,
msigRemoveProposeCmd,
msigApproveCmd,
msigAddProposeCmd,
msigAddApproveCmd,
@@ -52,6 +64,7 @@ var multisigCmd = &cli.Command{
msigLockApproveCmd,
msigLockCancelCmd,
msigVestedCmd,
msigProposeThresholdCmd,
},
}
@@ -141,14 +154,14 @@ var msigCreateCmd = &cli.Command{
}
// wait for it to get mined into a block
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
// check it executed successfully
if wait.Receipt.ExitCode != 0 {
fmt.Println("actor creation failed!")
fmt.Fprintln(cctx.App.Writer, "actor creation failed!")
return err
}
@@ -158,7 +171,7 @@ var msigCreateCmd = &cli.Command{
if err := execreturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
return err
}
fmt.Println("Created new multisig: ", execreturn.IDAddress, execreturn.RobustAddress)
fmt.Fprintln(cctx.App.Writer, "Created new multisig: ", execreturn.IDAddress, execreturn.RobustAddress)
// TODO: maybe register this somewhere
return nil
@@ -174,6 +187,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 +221,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
@@ -213,25 +235,25 @@ var msigInspectCmd = &cli.Command{
return err
}
fmt.Printf("Balance: %s\n", types.FIL(act.Balance))
fmt.Printf("Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked)))
fmt.Fprintf(cctx.App.Writer, "Balance: %s\n", types.FIL(act.Balance))
fmt.Fprintf(cctx.App.Writer, "Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked)))
if cctx.Bool("vesting") {
ib, err := mstate.InitialBalance()
if err != nil {
return err
}
fmt.Printf("InitialBalance: %s\n", types.FIL(ib))
fmt.Fprintf(cctx.App.Writer, "InitialBalance: %s\n", types.FIL(ib))
se, err := mstate.StartEpoch()
if err != nil {
return err
}
fmt.Printf("StartEpoch: %d\n", se)
fmt.Fprintf(cctx.App.Writer, "StartEpoch: %d\n", se)
ud, err := mstate.UnlockDuration()
if err != nil {
return err
}
fmt.Printf("UnlockDuration: %d\n", ud)
fmt.Fprintf(cctx.App.Writer, "UnlockDuration: %d\n", ud)
}
signers, err := mstate.Signers()
@@ -242,10 +264,10 @@ var msigInspectCmd = &cli.Command{
if err != nil {
return err
}
fmt.Printf("Threshold: %d / %d\n", threshold, len(signers))
fmt.Println("Signers:")
fmt.Fprintf(cctx.App.Writer, "Threshold: %d / %d\n", threshold, len(signers))
fmt.Fprintln(cctx.App.Writer, "Signers:")
for _, s := range signers {
fmt.Printf("\t%s\n", s)
fmt.Fprintf(cctx.App.Writer, "\t%s\n", s)
}
pending := make(map[int64]multisig.Transaction)
@@ -256,7 +278,8 @@ var msigInspectCmd = &cli.Command{
return xerrors.Errorf("reading pending transactions: %w", err)
}
fmt.Println("Transactions: ", len(pending))
decParams := cctx.Bool("decode-params")
fmt.Fprintln(cctx.App.Writer, "Transactions: ", len(pending))
if len(pending) > 0 {
var txids []int64
for txid := range pending {
@@ -266,11 +289,36 @@ var msigInspectCmd = &cli.Command{
return txids[i] < txids[j]
})
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
w := tabwriter.NewWriter(cctx.App.Writer, 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)
@@ -370,7 +418,7 @@ var msigProposeCmd = &cli.Command{
fmt.Println("send proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -398,7 +446,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",
@@ -406,14 +454,18 @@ var msigApproveCmd = &cli.Command{
},
},
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() < 5 {
return ShowHelp(cctx, fmt.Errorf("must pass multisig address, message ID, proposer address, destination, and value"))
if cctx.Args().Len() < 2 {
return ShowHelp(cctx, fmt.Errorf("must pass at least multisig address and message ID"))
}
if cctx.Args().Len() > 5 && cctx.Args().Len() != 7 {
return ShowHelp(cctx, fmt.Errorf("usage: msig approve <msig addr> <message ID> <proposer address> <desination> <value> [ <method> <params> ]"))
}
if cctx.Args().Len() > 2 && cctx.Args().Len() != 5 {
return ShowHelp(cctx, fmt.Errorf("usage: msig approve <msig addr> <message ID> <proposer address> <desination> <value>"))
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
@@ -431,42 +483,121 @@ var msigApproveCmd = &cli.Command{
return err
}
proposer, err := address.NewFromString(cctx.Args().Get(2))
if err != nil {
return err
var from address.Address
if cctx.IsSet("from") {
f, err := address.NewFromString(cctx.String("from"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
if proposer.Protocol() != address.ID {
proposer, err = api.StateLookupID(ctx, proposer, types.EmptyTSK)
var msgCid cid.Cid
if cctx.Args().Len() == 2 {
msgCid, err = api.MsigApprove(ctx, msig, txid, from)
if err != nil {
return err
}
} else {
proposer, err := address.NewFromString(cctx.Args().Get(2))
if err != nil {
return err
}
if proposer.Protocol() != address.ID {
proposer, err = api.StateLookupID(ctx, proposer, types.EmptyTSK)
if err != nil {
return err
}
}
dest, err := address.NewFromString(cctx.Args().Get(3))
if err != nil {
return err
}
value, err := types.ParseFIL(cctx.Args().Get(4))
if err != nil {
return err
}
var method uint64
var params []byte
if cctx.Args().Len() == 7 {
m, err := strconv.ParseUint(cctx.Args().Get(5), 10, 64)
if err != nil {
return err
}
method = m
p, err := hex.DecodeString(cctx.Args().Get(6))
if err != nil {
return err
}
params = p
}
msgCid, err = api.MsigApproveTxnHash(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
if err != nil {
return err
}
}
dest, err := address.NewFromString(cctx.Args().Get(3))
fmt.Println("sent approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
value, err := types.ParseFIL(cctx.Args().Get(4))
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("approve returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
var msigRemoveProposeCmd = &cli.Command{
Name: "propose-remove",
Usage: "Propose to remove a signer",
ArgsUsage: "[multisigAddress signer]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "decrease-threshold",
Usage: "whether the number of required signers should be decreased",
},
&cli.StringFlag{
Name: "from",
Usage: "account to send the propose message from",
},
},
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 2 {
return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address"))
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
var method uint64
var params []byte
if cctx.Args().Len() == 7 {
m, err := strconv.ParseUint(cctx.Args().Get(5), 10, 64)
if err != nil {
return err
}
method = m
p, err := hex.DecodeString(cctx.Args().Get(6))
if err != nil {
return err
}
params = p
addr, err := address.NewFromString(cctx.Args().Get(1))
if err != nil {
return err
}
var from address.Address
@@ -484,22 +615,29 @@ var msigApproveCmd = &cli.Command{
from = defaddr
}
msgCid, err := api.MsigApprove(ctx, msig, txid, proposer, dest, types.BigInt(value), from, method, params)
msgCid, err := api.MsigRemoveSigner(ctx, msig, from, addr, cctx.Bool("decrease-threshold"))
if err != nil {
return err
}
fmt.Println("sent approval in message: ", msgCid)
fmt.Println("sent remove proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("approve returned exit %d", wait.Receipt.ExitCode)
return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode)
}
var ret multisig.ProposeReturn
err = ret.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
if err != nil {
return xerrors.Errorf("decoding proposal return: %w", err)
}
fmt.Printf("TxnID: %d", ret.TxnID)
return nil
},
}
@@ -560,9 +698,9 @@ var msigAddProposeCmd = &cli.Command{
return err
}
fmt.Println("sent add proposal in message: ", msgCid)
fmt.Fprintln(cctx.App.Writer, "sent add proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -644,7 +782,7 @@ var msigAddApproveCmd = &cli.Command{
fmt.Println("sent add approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -721,7 +859,7 @@ var msigAddCancelCmd = &cli.Command{
fmt.Println("sent add cancellation in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -793,7 +931,7 @@ var msigSwapProposeCmd = &cli.Command{
fmt.Println("sent swap proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -875,7 +1013,7 @@ var msigSwapApproveCmd = &cli.Command{
fmt.Println("sent swap approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -952,7 +1090,7 @@ var msigSwapCancelCmd = &cli.Command{
fmt.Println("sent swap cancellation in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -1039,7 +1177,7 @@ var msigLockProposeCmd = &cli.Command{
fmt.Println("sent lock proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -1129,14 +1267,14 @@ 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
}
fmt.Println("sent lock approval in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -1228,7 +1366,7 @@ var msigLockCancelCmd = &cli.Command{
fmt.Println("sent lock cancellation in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
@@ -1302,3 +1440,78 @@ var msigVestedCmd = &cli.Command{
return nil
},
}
var msigProposeThresholdCmd = &cli.Command{
Name: "propose-threshold",
Usage: "Propose setting a different signing threshold on the account",
ArgsUsage: "<multisigAddress newM>",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "account to send the proposal from",
},
},
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() != 2 {
return ShowHelp(cctx, fmt.Errorf("must pass multisig address and new threshold value"))
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msig, err := address.NewFromString(cctx.Args().Get(0))
if err != nil {
return err
}
newM, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
if err != nil {
return err
}
var from address.Address
if cctx.IsSet("from") {
f, err := address.NewFromString(cctx.String("from"))
if err != nil {
return err
}
from = f
} else {
defaddr, err := api.WalletDefaultAddress(ctx)
if err != nil {
return err
}
from = defaddr
}
params, actErr := actors.SerializeParams(&msig0.ChangeNumApprovalsThresholdParams{
NewThreshold: newM,
})
if actErr != nil {
return actErr
}
msgCid, err := api.MsigPropose(ctx, msig, msig, types.NewInt(0), from, uint64(builtin2.MethodsMultisig.ChangeNumApprovalsThreshold), params)
if err != nil {
return fmt.Errorf("failed to propose change of threshold: %w", err)
}
fmt.Println("sent change threshold proposal in message: ", msgCid)
wait, err := api.StateWaitMsg(ctx, msgCid, uint64(cctx.Int("confidence")))
if err != nil {
return err
}
if wait.Receipt.ExitCode != 0 {
return fmt.Errorf("change threshold proposal returned exit %d", wait.Receipt.ExitCode)
}
return nil
},
}
+55
View File
@@ -0,0 +1,55 @@
package cli
import (
"context"
"os"
"testing"
"time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api/test"
clitest "github.com/filecoin-project/lotus/cli/test"
builder "github.com/filecoin-project/lotus/node/test"
)
// TestMultisig does a basic test to exercise the multisig CLI
// commands
func TestMultisig(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
blocktime := 5 * time.Millisecond
ctx := context.Background()
nodes, _ := startNodes(ctx, t, blocktime)
clientNode := nodes[0]
clitest.RunMultisigTest(t, Commands, clientNode)
}
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) ([]test.TestNode, []address.Address) {
n, sn := builder.RPCMockSbBuilder(t, test.OneFull, test.OneMiner)
full := n[0]
miner := sn[0]
// Get everyone connected
addrs, err := full.NetAddrsListen(ctx)
if err != nil {
t.Fatal(err)
}
if err := miner.NetConnect(ctx, addrs); err != nil {
t.Fatal(err)
}
// Start mining blocks
bm := test.NewBlockMiner(ctx, t, miner, blocktime)
bm.MineBlocks()
// Get the creator's address
creatorAddr, err := full.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
// Create mock CLI
return n, []address.Address{creatorAddr}
}
+2 -2
View File
@@ -29,7 +29,6 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
builder "github.com/filecoin-project/lotus/node/test"
)
@@ -415,7 +414,7 @@ func startTwoNodesOneMiner(ctx context.Context, t *testing.T, blocktime time.Dur
bm.MineBlocks()
// Send some funds to register the receiver
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
if err != nil {
t.Fatal(err)
}
@@ -438,6 +437,7 @@ type mockCLI struct {
out *bytes.Buffer
}
// TODO: refactor to use the methods in cli/test/mockcli.go
func newMockCLI(t *testing.T) *mockCLI {
// Create a CLI App with an --api-url flag so that we can specify which node
// the command should be executed against
+104 -132
View File
@@ -60,7 +60,7 @@ var stateCmd = &cli.Command{
stateSectorCmd,
stateGetActorCmd,
stateLookupIDCmd,
stateReplaySetCmd,
stateReplayCmd,
stateSectorSizeCmd,
stateReadStateCmd,
stateListMessagesCmd,
@@ -69,7 +69,6 @@ var stateCmd = &cli.Command{
stateGetDealSetCmd,
stateWaitMsgCmd,
stateSearchMsgCmd,
stateMsgCostCmd,
stateMinerInfo,
stateMarketCmd,
stateExecTraceCmd,
@@ -384,20 +383,27 @@ var stateExecTraceCmd = &cli.Command{
},
}
var stateReplaySetCmd = &cli.Command{
var stateReplayCmd = &cli.Command{
Name: "replay",
Usage: "Replay a particular message within a tipset",
ArgsUsage: "[tipsetKey messageCid]",
Usage: "Replay a particular message",
ArgsUsage: "<messageCid>",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "show-trace",
Usage: "print out full execution trace for given message",
},
&cli.BoolFlag{
Name: "detailed-gas",
Usage: "print out detailed gas costs for given message",
},
},
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() < 1 {
fmt.Println("usage: [tipset] <message cid>")
fmt.Println("The last cid passed will be used as the message CID")
fmt.Println("All preceding ones will be used as the tipset")
if cctx.Args().Len() != 1 {
fmt.Println("must provide cid of message to replay")
return nil
}
args := cctx.Args().Slice()
mcid, err := cid.Decode(args[len(args)-1])
mcid, err := cid.Decode(cctx.Args().First())
if err != nil {
return fmt.Errorf("message cid was invalid: %s", err)
}
@@ -410,52 +416,7 @@ var stateReplaySetCmd = &cli.Command{
ctx := ReqContext(cctx)
var ts *types.TipSet
{
var tscids []cid.Cid
for _, s := range args[:len(args)-1] {
c, err := cid.Decode(s)
if err != nil {
return fmt.Errorf("tipset cid was invalid: %s", err)
}
tscids = append(tscids, c)
}
if len(tscids) > 0 {
var headers []*types.BlockHeader
for _, c := range tscids {
h, err := fapi.ChainGetBlock(ctx, c)
if err != nil {
return err
}
headers = append(headers, h)
}
ts, err = types.NewTipSet(headers)
if err != nil {
return err
}
} else {
var r *api.MsgLookup
r, err = fapi.StateWaitMsg(ctx, mcid, build.MessageConfidence)
if err != nil {
return xerrors.Errorf("finding message in chain: %w", err)
}
childTs, err := fapi.ChainGetTipSet(ctx, r.TipSet)
if err != nil {
return xerrors.Errorf("loading tipset: %w", err)
}
ts, err = fapi.ChainGetTipSet(ctx, childTs.Parents())
if err != nil {
return err
}
}
}
res, err := fapi.StateReplay(ctx, ts.Key(), mcid)
res, err := fapi.StateReplay(ctx, types.EmptyTSK, mcid)
if err != nil {
return xerrors.Errorf("replay call failed: %w", err)
}
@@ -464,10 +425,25 @@ var stateReplaySetCmd = &cli.Command{
fmt.Printf("Exit code: %d\n", res.MsgRct.ExitCode)
fmt.Printf("Return: %x\n", res.MsgRct.Return)
fmt.Printf("Gas Used: %d\n", res.MsgRct.GasUsed)
if cctx.Bool("detailed-gas") {
fmt.Printf("Base Fee Burn: %d\n", res.GasCost.BaseFeeBurn)
fmt.Printf("Overestimaton Burn: %d\n", res.GasCost.OverEstimationBurn)
fmt.Printf("Miner Penalty: %d\n", res.GasCost.MinerPenalty)
fmt.Printf("Miner Tip: %d\n", res.GasCost.MinerTip)
fmt.Printf("Refund: %d\n", res.GasCost.Refund)
}
fmt.Printf("Total Message Cost: %d\n", res.GasCost.TotalCost)
if res.MsgRct.ExitCode != 0 {
fmt.Printf("Error message: %q\n", res.Error)
}
if cctx.Bool("show-trace") {
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", res.Msg.From, res.Msg.To, res.Msg.Value, res.Msg.Method, res.Msg.Params, res.MsgRct.ExitCode, res.MsgRct.Return)
printInternalExecutions("\t", res.ExecutionTrace.Subcalls)
}
return nil
},
}
@@ -837,33 +813,66 @@ var stateListMessagesCmd = &cli.Command{
froma = a
}
toh := cctx.Uint64("toheight")
toh := abi.ChainEpoch(cctx.Uint64("toheight"))
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
msgs, err := api.StateListMessages(ctx, &types.Message{To: toa, From: froma}, ts.Key(), abi.ChainEpoch(toh))
if err != nil {
return err
if ts == nil {
head, err := api.ChainHead(ctx)
if err != nil {
return err
}
ts = head
}
for _, c := range msgs {
if cctx.Bool("cids") {
fmt.Println(c.String())
continue
windowSize := abi.ChainEpoch(100)
cur := ts
for cur.Height() > toh {
if ctx.Err() != nil {
return ctx.Err()
}
m, err := api.ChainGetMessage(ctx, c)
end := toh
if cur.Height()-windowSize > end {
end = cur.Height() - windowSize
}
msgs, err := api.StateListMessages(ctx, &lapi.MessageMatch{To: toa, From: froma}, cur.Key(), end)
if err != nil {
return err
}
b, err := json.MarshalIndent(m, "", " ")
for _, c := range msgs {
if cctx.Bool("cids") {
fmt.Println(c.String())
continue
}
m, err := api.ChainGetMessage(ctx, c)
if err != nil {
return err
}
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err
}
fmt.Println(string(b))
}
if end <= 0 {
break
}
next, err := api.ChainGetTipSetByHeight(ctx, end-1, cur.Key())
if err != nil {
return err
}
fmt.Println(string(b))
cur = next
}
return nil
@@ -1424,60 +1433,6 @@ var stateSearchMsgCmd = &cli.Command{
},
}
var stateMsgCostCmd = &cli.Command{
Name: "msg-cost",
Usage: "Get the detailed gas costs of a message",
ArgsUsage: "[messageCid]",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("must specify message cid to get gas costs for")
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
msg, err := cid.Decode(cctx.Args().First())
if err != nil {
return err
}
tsk := types.EmptyTSK
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
if ts != nil {
tsk = ts.Key()
}
mgc, err := api.StateMsgGasCost(ctx, msg, tsk)
if err != nil {
return err
}
if mgc != nil {
fmt.Printf("Message CID: %s", mgc.Message)
fmt.Printf("\nGas Used: %d", mgc.GasUsed)
fmt.Printf("\nBase Fee Burn: %d", mgc.BaseFeeBurn)
fmt.Printf("\nOverestimation Burn: %d", mgc.OverEstimationBurn)
fmt.Printf("\nMiner Tip: %d", mgc.MinerTip)
fmt.Printf("\nRefund: %d", mgc.Refund)
fmt.Printf("\nTotal Cost: %d", mgc.TotalCost)
fmt.Printf("\nMiner Penalty: %d", mgc.MinerPenalty)
} else {
fmt.Print("message was not found on chain")
}
return nil
},
}
var stateCallCmd = &cli.Command{
Name: "call",
Usage: "Invoke a method on an actor locally",
@@ -1688,7 +1643,14 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er
var stateCircSupplyCmd = &cli.Command{
Name: "circulating-supply",
Usage: "Get the current circulating supply of filecoin",
Usage: "Get the exact current circulating supply of Filecoin",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "vm-supply",
Usage: "calculates the approximation of the circulating supply used internally by the VM (instead of the exact amount)",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -1703,16 +1665,26 @@ var stateCircSupplyCmd = &cli.Command{
return err
}
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return err
}
if cctx.IsSet("vm-supply") {
circ, err := api.StateVMCirculatingSupplyInternal(ctx, ts.Key())
if err != nil {
return err
}
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
fmt.Println("Mined: ", types.FIL(circ.FilMined))
fmt.Println("Vested: ", types.FIL(circ.FilVested))
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
fmt.Println("Circulating supply: ", types.FIL(circ.FilCirculating))
fmt.Println("Mined: ", types.FIL(circ.FilMined))
fmt.Println("Vested: ", types.FIL(circ.FilVested))
fmt.Println("Burnt: ", types.FIL(circ.FilBurnt))
fmt.Println("Locked: ", types.FIL(circ.FilLocked))
} else {
circ, err := api.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return err
}
fmt.Println("Exact circulating supply: ", types.FIL(circ))
return nil
}
return nil
},
+21 -5
View File
@@ -84,6 +84,12 @@ var syncStatusCmd = &cli.Command{
var syncWaitCmd = &cli.Command{
Name: "wait",
Usage: "Wait for sync to be complete",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "watch",
Usage: "don't exit after node is synced",
},
},
Action: func(cctx *cli.Context) error {
napi, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@@ -92,7 +98,7 @@ var syncWaitCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
return SyncWait(ctx, napi)
return SyncWait(ctx, napi, cctx.Bool("watch"))
},
}
@@ -122,8 +128,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 +145,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")
}
@@ -224,7 +240,7 @@ var syncCheckpointCmd = &cli.Command{
},
}
func SyncWait(ctx context.Context, napi api.FullNode) error {
func SyncWait(ctx context.Context, napi api.FullNode, watch bool) error {
tick := time.Second / 4
lastLines := 0
@@ -301,7 +317,7 @@ func SyncWait(ctx context.Context, napi api.FullNode) error {
_ = target // todo: maybe print? (creates a bunch of line wrapping issues with most tipsets)
if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
if !watch && time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
fmt.Println("\nDone!")
return nil
}
+124
View File
@@ -0,0 +1,124 @@
package test
import (
"bytes"
"flag"
"strings"
"testing"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
lcli "github.com/urfave/cli/v2"
)
type mockCLI struct {
t *testing.T
cmds []*lcli.Command
cctx *lcli.Context
out *bytes.Buffer
}
func newMockCLI(t *testing.T, cmds []*lcli.Command) *mockCLI {
// Create a CLI App with an --api-url flag so that we can specify which node
// the command should be executed against
app := &lcli.App{
Flags: []lcli.Flag{
&lcli.StringFlag{
Name: "api-url",
Hidden: true,
},
},
Commands: cmds,
}
var out bytes.Buffer
app.Writer = &out
app.Setup()
cctx := lcli.NewContext(app, &flag.FlagSet{}, nil)
return &mockCLI{t: t, cmds: cmds, cctx: cctx, out: &out}
}
func (c *mockCLI) client(addr multiaddr.Multiaddr) *mockCLIClient {
return &mockCLIClient{t: c.t, cmds: c.cmds, addr: addr, cctx: c.cctx, out: c.out}
}
// mockCLIClient runs commands against a particular node
type mockCLIClient struct {
t *testing.T
cmds []*lcli.Command
addr multiaddr.Multiaddr
cctx *lcli.Context
out *bytes.Buffer
}
func (c *mockCLIClient) run(cmd []string, params []string, args []string) string {
// Add parameter --api-url=<node api listener address>
apiFlag := "--api-url=" + c.addr.String()
params = append([]string{apiFlag}, params...)
err := c.cctx.App.Run(append(append(cmd, params...), args...))
require.NoError(c.t, err)
// Get the output
str := strings.TrimSpace(c.out.String())
c.out.Reset()
return str
}
func (c *mockCLIClient) runCmd(input []string) string {
cmd := c.cmdByNameSub(input[0], input[1])
out, err := c.runCmdRaw(cmd, input[2:])
require.NoError(c.t, err)
return out
}
func (c *mockCLIClient) cmdByNameSub(name string, sub string) *lcli.Command {
for _, c := range c.cmds {
if c.Name == name {
for _, s := range c.Subcommands {
if s.Name == sub {
return s
}
}
}
}
return nil
}
func (c *mockCLIClient) runCmdRaw(cmd *lcli.Command, input []string) (string, error) {
// prepend --api-url=<node api listener address>
apiFlag := "--api-url=" + c.addr.String()
input = append([]string{apiFlag}, input...)
fs := c.flagSet(cmd)
err := fs.Parse(input)
require.NoError(c.t, err)
err = cmd.Action(lcli.NewContext(c.cctx.App, fs, c.cctx))
// Get the output
str := strings.TrimSpace(c.out.String())
c.out.Reset()
return str, err
}
func (c *mockCLIClient) flagSet(cmd *lcli.Command) *flag.FlagSet {
// 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)
if err != nil {
c.t.Fatal(err)
}
}
// Apply command level flags
for _, f := range cmd.Flags {
err := f.Apply(fs)
if err != nil {
c.t.Fatal(err)
}
}
return fs
}
+110
View File
@@ -0,0 +1,110 @@
package test
import (
"context"
"fmt"
"regexp"
"strings"
"testing"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api/test"
"github.com/filecoin-project/lotus/chain/types"
logging "github.com/ipfs/go-log/v2"
"github.com/stretchr/testify/require"
lcli "github.com/urfave/cli/v2"
)
func QuietMiningLogs() {
logging.SetLogLevel("miner", "ERROR")
logging.SetLogLevel("chainstore", "ERROR")
logging.SetLogLevel("chain", "ERROR")
logging.SetLogLevel("sub", "ERROR")
logging.SetLogLevel("storageminer", "ERROR")
}
func RunMultisigTest(t *testing.T, cmds []*lcli.Command, clientNode test.TestNode) {
ctx := context.Background()
// Create mock CLI
mockCLI := newMockCLI(t, cmds)
clientCLI := mockCLI.client(clientNode.ListenAddr)
// Create some wallets on the node to use for testing multisig
var walletAddrs []address.Address
for i := 0; i < 4; i++ {
addr, err := clientNode.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
walletAddrs = append(walletAddrs, addr)
test.SendFunds(ctx, t, clientNode, addr, types.NewInt(1e15))
}
// Create an msig with three of the addresses and threshold of two sigs
// msig create --required=2 --duration=50 --value=1000attofil <addr1> <addr2> <addr3>
amtAtto := types.NewInt(1000)
threshold := 2
paramDuration := "--duration=50"
paramRequired := fmt.Sprintf("--required=%d", threshold)
paramValue := fmt.Sprintf("--value=%dattofil", amtAtto)
cmd := []string{
"msig", "create",
paramRequired,
paramDuration,
paramValue,
walletAddrs[0].String(),
walletAddrs[1].String(),
walletAddrs[2].String(),
}
out := clientCLI.runCmd(cmd)
fmt.Println(out)
// Extract msig robust address from output
expCreateOutPrefix := "Created new multisig:"
require.Regexp(t, regexp.MustCompile(expCreateOutPrefix), out)
parts := strings.Split(strings.TrimSpace(strings.Replace(out, expCreateOutPrefix, "", -1)), " ")
require.Len(t, parts, 2)
msigRobustAddr := parts[1]
fmt.Println("msig robust address:", msigRobustAddr)
// Propose to add a new address to the msig
// msig add-propose --from=<addr> <msig> <addr>
paramFrom := fmt.Sprintf("--from=%s", walletAddrs[0])
cmd = []string{
"msig", "add-propose",
paramFrom,
msigRobustAddr,
walletAddrs[3].String(),
}
out = clientCLI.runCmd(cmd)
fmt.Println(out)
// msig inspect <msig>
cmd = []string{"msig", "inspect", "--vesting", "--decode-params", msigRobustAddr}
out = clientCLI.runCmd(cmd)
fmt.Println(out)
// Expect correct balance
require.Regexp(t, regexp.MustCompile("Balance: 0.000000000000001 FIL"), out)
// Expect 1 transaction
require.Regexp(t, regexp.MustCompile(`Transactions:\s*1`), out)
// Expect transaction to be "AddSigner"
require.Regexp(t, regexp.MustCompile(`AddSigner`), out)
// Approve adding the new address
// msig add-approve --from=<addr> <msig> <addr> 0 <addr> false
txnID := "0"
paramFrom = fmt.Sprintf("--from=%s", walletAddrs[1])
cmd = []string{
"msig", "add-approve",
paramFrom,
msigRobustAddr,
walletAddrs[0].String(),
txnID,
walletAddrs[3].String(),
"false",
}
out = clientCLI.runCmd(cmd)
fmt.Println(out)
}
+3 -4
View File
@@ -17,7 +17,6 @@ import (
"github.com/filecoin-project/go-state-types/crypto"
types "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/lib/tablewriter"
)
@@ -55,7 +54,7 @@ var walletNew = &cli.Command{
t = "secp256k1"
}
nk, err := api.WalletNew(ctx, wallet.ActSigType(t))
nk, err := api.WalletNew(ctx, types.KeyType(t))
if err != nil {
return err
}
@@ -329,9 +328,9 @@ var walletImport = &cli.Command{
ki.PrivateKey = gk.PrivateKey
switch gk.SigType {
case 1:
ki.Type = wallet.KTSecp256k1
ki.Type = types.KTSecp256k1
case 2:
ki.Type = wallet.KTBLS
ki.Type = types.KTBLS
default:
return fmt.Errorf("unrecognized key type: %d", gk.SigType)
}
+1 -3
View File
@@ -7,8 +7,6 @@ import (
"os"
"time"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@@ -61,7 +59,7 @@ var runCmd = &cli.Command{
func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Address, rate int) error {
var sendSet []address.Address
for i := 0; i < 20; i++ {
naddr, err := api.WalletNew(ctx, crypto.SigTypeSecp256k1)
naddr, err := api.WalletNew(ctx, types.KTSecp256k1)
if err != nil {
return err
}
+1 -1
View File
@@ -316,7 +316,7 @@ limit 1
}
func (s *Syncer) storeCirculatingSupply(ctx context.Context, tipset *types.TipSet) error {
supply, err := s.node.StateCirculatingSupply(ctx, tipset.Key())
supply, err := s.node.StateVMCirculatingSupplyInternal(ctx, tipset.Key())
if err != nil {
return err
}
+133 -6
View File
@@ -6,16 +6,23 @@ import (
"time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/dline"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/filecoin-project/lotus/node/impl/full"
"github.com/ipfs/go-cid"
)
const (
LookbackCap = time.Hour
LookbackCap = time.Hour * 12
stateWaitLookbackLimit = abi.ChainEpoch(20)
)
@@ -26,9 +33,12 @@ var (
// gatewayDepsAPI defines the API methods that the GatewayAPI depends on
// (to make it easy to mock for tests)
type gatewayDepsAPI interface {
ChainHasObj(context.Context, cid.Cid) (bool, error)
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)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainGetNode(ctx context.Context, p string) (*api.IpldObject, 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)
@@ -37,10 +47,31 @@ type gatewayDepsAPI interface {
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)
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error)
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error)
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error)
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error)
}
type GatewayAPI struct {
api gatewayDepsAPI
api gatewayDepsAPI
lookbackCap time.Duration
}
// NewGatewayAPI creates a new GatewayAPI with the default lookback cap
func NewGatewayAPI(api gatewayDepsAPI) *GatewayAPI {
return newGatewayAPI(api, LookbackCap)
}
// used by the tests
func newGatewayAPI(api gatewayDepsAPI, lookbackCap time.Duration) *GatewayAPI {
return &GatewayAPI{api: api, lookbackCap: lookbackCap}
}
func (a *GatewayAPI) checkTipsetKey(ctx context.Context, tsk types.TipSetKey) error {
@@ -76,13 +107,17 @@ func (a *GatewayAPI) checkTipsetHeight(ts *types.TipSet, h abi.ChainEpoch) error
}
func (a *GatewayAPI) checkTimestamp(at time.Time) error {
if time.Since(at) > LookbackCap {
if time.Since(at) > a.lookbackCap {
return ErrLookbackTooLong
}
return nil
}
func (a *GatewayAPI) ChainHasObj(ctx context.Context, c cid.Cid) (bool, error) {
return a.api.ChainHasObj(ctx, c)
}
func (a *GatewayAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
// TODO: cache and invalidate cache when timestamp is up (or have internal ChainNotify)
@@ -94,9 +129,19 @@ func (a *GatewayAPI) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*
}
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
var ts *types.TipSet
if tsk.IsEmpty() {
head, err := a.api.ChainHead(ctx)
if err != nil {
return nil, err
}
ts = head
} else {
gts, err := a.api.ChainGetTipSet(ctx, tsk)
if err != nil {
return nil, err
}
ts = gts
}
// Check if the tipset key refers to a tipset that's too far in the past
@@ -112,6 +157,14 @@ func (a *GatewayAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoc
return a.api.ChainGetTipSetByHeight(ctx, h, tsk)
}
func (a *GatewayAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
return a.api.ChainReadObj(ctx, c)
}
func (a *GatewayAPI) ChainGetNode(ctx context.Context, p string) (*api.IpldObject, error) {
return a.api.ChainGetNode(ctx, p)
}
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
@@ -172,6 +225,80 @@ func (a *GatewayAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence u
return a.api.StateWaitMsgLimited(ctx, msg, confidence, stateWaitLookbackLimit)
}
func (a *GatewayAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.StateReadState(ctx, actor, tsk)
}
func (a *GatewayAPI) StateMinerPower(ctx context.Context, m address.Address, tsk types.TipSetKey) (*api.MinerPower, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.StateMinerPower(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerFaults(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return bitfield.BitField{}, err
}
return a.api.StateMinerFaults(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerRecoveries(ctx context.Context, m address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return bitfield.BitField{}, err
}
return a.api.StateMinerRecoveries(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerInfo(ctx context.Context, m address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return miner.MinerInfo{}, err
}
return a.api.StateMinerInfo(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]api.Deadline, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.StateMinerDeadlines(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerAvailableBalance(ctx context.Context, m address.Address, tsk types.TipSetKey) (types.BigInt, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return types.BigInt{}, err
}
return a.api.StateMinerAvailableBalance(ctx, m, tsk)
}
func (a *GatewayAPI) StateMinerProvingDeadline(ctx context.Context, m address.Address, tsk types.TipSetKey) (*dline.Info, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return nil, err
}
return a.api.StateMinerProvingDeadline(ctx, m, tsk)
}
func (a *GatewayAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return types.BigInt{}, err
}
return a.api.StateCirculatingSupply(ctx, tsk)
}
func (a *GatewayAPI) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
if err := a.checkTipsetKey(ctx, tsk); err != nil {
return api.CirculatingSupply{}, err
}
return a.api.StateVMCirculatingSupplyInternal(ctx, tsk)
}
func (a *GatewayAPI) WalletVerify(ctx context.Context, k address.Address, msg []byte, sig *crypto.Signature) (bool, error) {
return sigs.Verify(sig, k, msg) == nil, nil
}
var _ api.GatewayAPI = (*GatewayAPI)(nil)
var _ full.ChainModuleAPI = (*GatewayAPI)(nil)
var _ full.GasModuleAPI = (*GatewayAPI)(nil)
+16 -1
View File
@@ -88,7 +88,7 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
mock := &mockGatewayDepsAPI{}
a := &GatewayAPI{api: mock}
a := NewGatewayAPI(mock)
// Create tipsets from genesis up to tskh and return the highest
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
@@ -107,6 +107,13 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
type mockGatewayDepsAPI struct {
lk sync.RWMutex
tipsets []*types.TipSet
gatewayDepsAPI // satisfies all interface requirements but will panic if
// methods are called. easier than filling out with panic stubs IMO
}
func (m *mockGatewayDepsAPI) ChainHasObj(context.Context, cid.Cid) (bool, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) ChainHead(ctx context.Context) (*types.TipSet, error) {
@@ -158,6 +165,10 @@ func (m *mockGatewayDepsAPI) ChainGetTipSetByHeight(ctx context.Context, h abi.C
return m.tipsets[h], nil
}
func (m *mockGatewayDepsAPI) ChainReadObj(ctx context.Context, c cid.Cid) ([]byte, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
panic("implement me")
}
@@ -189,3 +200,7 @@ func (m *mockGatewayDepsAPI) StateLookupID(ctx context.Context, addr address.Add
func (m *mockGatewayDepsAPI) StateWaitMsgLimited(ctx context.Context, msg cid.Cid, confidence uint64, h abi.ChainEpoch) (*api.MsgLookup, error) {
panic("implement me")
}
func (m *mockGatewayDepsAPI) StateReadState(ctx context.Context, act address.Address, ts types.TipSetKey) (*api.ActorState, error) {
panic("implement me")
}
+44 -13
View File
@@ -4,10 +4,14 @@ import (
"bytes"
"context"
"fmt"
"math"
"os"
"testing"
"time"
"github.com/filecoin-project/lotus/cli"
clitest "github.com/filecoin-project/lotus/cli/test"
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
@@ -22,25 +26,26 @@ import (
"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"
)
const maxLookbackCap = time.Duration(math.MaxInt64)
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) {
// TestEndToEndWalletMsig tests that wallet and msig API calls can be made
// on a lite node that is connected through a gateway to a full API node
func TestEndToEndWalletMsig(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
blocktime := 5 * time.Millisecond
ctx := context.Background()
full, lite, closer := startNodes(ctx, t, blocktime)
full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap)
defer closer()
// The full node starts with a wallet
@@ -53,15 +58,15 @@ func TestEndToEnd(t *testing.T) {
fmt.Println(balance)
// Create a wallet on the lite node
liteWalletAddr, err := lite.WalletNew(ctx, wallet.ActSigType("secp256k1"))
liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1)
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))
err = sendFunds(ctx, 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))
err = sendFunds(ctx, lite, liteWalletAddr, fullWalletAddr, types.NewInt(100))
require.NoError(t, err)
// Sign some data with the lite node wallet address
@@ -77,12 +82,12 @@ func TestEndToEnd(t *testing.T) {
// 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"))
addr, err := lite.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
walletAddrs = append(walletAddrs, addr)
err = sendFunds(ctx, t, lite, liteWalletAddr, addr, types.NewInt(1e15))
err = sendFunds(ctx, lite, liteWalletAddr, addr, types.NewInt(1e15))
require.NoError(t, err)
}
@@ -136,7 +141,33 @@ func TestEndToEnd(t *testing.T) {
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 {
// TestEndToEndMsigCLI tests that msig CLI calls can be made
// on a lite node that is connected through a gateway to a full API node
func TestEndToEndMsigCLI(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
clitest.QuietMiningLogs()
blocktime := 5 * time.Millisecond
ctx := context.Background()
full, lite, closer := startNodes(ctx, t, blocktime, maxLookbackCap)
defer closer()
// The full node starts with a wallet
fullWalletAddr, err := full.WalletDefaultAddress(ctx)
require.NoError(t, err)
// Create a wallet on the lite node
liteWalletAddr, err := lite.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)
// Send some funds from the full node to the lite node
err = sendFunds(ctx, full, fullWalletAddr, liteWalletAddr, types.NewInt(1e18))
require.NoError(t, err)
clitest.RunMultisigTest(t, cli.Commands, lite)
}
func sendFunds(ctx context.Context, fromNode test.TestNode, fromAddr address.Address, toAddr address.Address, amt types.BigInt) error {
msg := &types.Message{
From: fromAddr,
To: toAddr,
@@ -159,7 +190,7 @@ func sendFunds(ctx context.Context, t *testing.T, fromNode test.TestNode, fromAd
return nil
}
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration, lookbackCap time.Duration) (test.TestNode, test.TestNode, jsonrpc.ClientCloser) {
var closer jsonrpc.ClientCloser
// Create one miner and two full nodes.
@@ -176,7 +207,7 @@ func startNodes(ctx context.Context, t *testing.T, blocktime time.Duration) (tes
fullNode := nodes[0]
// Create a gateway server in front of the full node
_, addr, err := builder.CreateRPCServer(&GatewayAPI{api: fullNode})
_, addr, err := builder.CreateRPCServer(newGatewayAPI(fullNode, lookbackCap))
require.NoError(t, err)
// Create a gateway client API that connects to the gateway server
+1 -1
View File
@@ -76,7 +76,7 @@ var runCmd = &cli.Command{
log.Info("Setting up API endpoint at " + address)
rpcServer := jsonrpc.NewServer()
rpcServer.Register("Filecoin", &GatewayAPI{api: api})
rpcServer.Register("Filecoin", NewGatewayAPI(api))
mux.Handle("/rpc/v0", rpcServer)
mux.PathPrefix("/").Handler(http.DefaultServeMux)
+4 -4
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"os"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
@@ -30,12 +30,12 @@ func main() {
return err
}
var kt crypto.SigType
var kt types.KeyType
switch cctx.String("type") {
case "bls":
kt = crypto.SigTypeBLS
kt = types.KTBLS
case "secp256k1":
kt = crypto.SigTypeSecp256k1
kt = types.KTSecp256k1
default:
return fmt.Errorf("unrecognized key type: %q", cctx.String("type"))
}
+2
View File
@@ -884,6 +884,8 @@ func (r *refunder) processTipsetStorageMarketActor(ctx context.Context, tipset *
}
refundValue = types.BigMul(types.NewInt(uint64(recp.GasUsed)), tipset.Blocks()[0].ParentBaseFee)
default:
return false, messageMethod, types.NewInt(0), nil
}
return true, messageMethod, refundValue, nil
+1 -2
View File
@@ -21,7 +21,6 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/extern/sector-storage/zerocomm"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
@@ -93,7 +92,7 @@ func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.Sect
return nil, nil, err
}
} else {
minerAddr, err = wallet.GenerateKey(crypto.SigTypeBLS)
minerAddr, err = wallet.GenerateKey(types.KTBLS)
if err != nil {
return nil, nil, err
}
+52 -1
View File
@@ -5,6 +5,10 @@ import (
"fmt"
"strconv"
"github.com/filecoin-project/lotus/chain/gen/genesis"
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/docker/go-units"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
@@ -136,6 +140,9 @@ var chainBalanceStateCmd = &cli.Command{
&cli.BoolFlag{
Name: "miner-info",
},
&cli.BoolFlag{
Name: "robust-addresses",
},
},
Action: func(cctx *cli.Context) error {
ctx := context.TODO()
@@ -187,6 +194,33 @@ var chainBalanceStateCmd = &cli.Command{
minerInfo := cctx.Bool("miner-info")
robustMap := make(map[address.Address]address.Address)
if cctx.Bool("robust-addresses") {
iact, err := tree.GetActor(_init.Address)
if err != nil {
return xerrors.Errorf("failed to load init actor: %w", err)
}
ist, err := _init.Load(store, iact)
if err != nil {
return xerrors.Errorf("failed to load init actor state: %w", err)
}
err = ist.ForEachActor(func(id abi.ActorID, addr address.Address) error {
idAddr, err := address.NewIDAddress(uint64(id))
if err != nil {
return xerrors.Errorf("failed to write to addr map: %w", err)
}
robustMap[idAddr] = addr
return nil
})
if err != nil {
return xerrors.Errorf("failed to invert init address map: %w", err)
}
}
var infos []accountInfo
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
@@ -201,6 +235,23 @@ var chainBalanceStateCmd = &cli.Command{
VestingAmount: types.FIL(big.NewInt(0)),
}
if cctx.Bool("robust-addresses") {
robust, found := robustMap[addr]
if found {
ai.Address = robust
} else {
id, err := address.IDFromAddress(addr)
if err != nil {
return xerrors.Errorf("failed to get ID address: %w", err)
}
// TODO: This is not the correctest way to determine whether a robust address should exist
if id >= genesis.MinerStart {
return xerrors.Errorf("address doesn't have a robust address: %s", addr)
}
}
}
if minerInfo && builtin.IsStorageMinerActor(act.Code) {
pow, _, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr)
if err != nil {
@@ -372,7 +423,7 @@ var chainPledgeCmd = &cli.Command{
pledgeCollateral = c
}
circ, err := sm.GetCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
circ, err := sm.GetVMCirculatingSupplyDetailed(ctx, abi.ChainEpoch(epoch), state)
if err != nil {
return err
}
+10 -10
View File
@@ -32,10 +32,10 @@ import (
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
)
var validTypes = []string{wallet.KTBLS, wallet.KTSecp256k1, lp2p.KTLibp2pHost}
var validTypes = []types.KeyType{types.KTBLS, types.KTSecp256k1, lp2p.KTLibp2pHost}
type keyInfoOutput struct {
Type string
Type types.KeyType
Address string
PublicKey string
}
@@ -86,7 +86,7 @@ var keyinfoVerifyCmd = &cli.Command{
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
}
if string(name) != keyInfo.Type {
if types.KeyType(name) != keyInfo.Type {
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
}
case modules.KTJwtHmacSecret:
@@ -98,7 +98,7 @@ var keyinfoVerifyCmd = &cli.Command{
if string(name) != modules.JWTSecretName {
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
}
case wallet.KTSecp256k1, wallet.KTBLS:
case types.KTSecp256k1, types.KTBLS:
keystore := wallet.NewMemKeyStore()
w, err := wallet.NewWallet(keystore)
if err != nil {
@@ -214,7 +214,7 @@ var keyinfoImportCmd = &cli.Command{
fmt.Printf("%s\n", peerid.String())
break
case wallet.KTSecp256k1, wallet.KTBLS:
case types.KTSecp256k1, types.KTBLS:
w, err := wallet.NewWallet(keystore)
if err != nil {
return err
@@ -317,7 +317,7 @@ var keyinfoInfoCmd = &cli.Command{
kio.PublicKey = base64.StdEncoding.EncodeToString(pkBytes)
break
case wallet.KTSecp256k1, wallet.KTBLS:
case types.KTSecp256k1, types.KTBLS:
kio.Type = keyInfo.Type
key, err := wallet.NewKey(keyInfo)
@@ -366,7 +366,7 @@ var keyinfoNewCmd = &cli.Command{
return fmt.Errorf("please specify a type to generate")
}
keyType := cctx.Args().First()
keyType := types.KeyType(cctx.Args().First())
flagOutput := cctx.String("output")
if i := SliceIndex(len(validTypes), func(i int) bool {
@@ -404,8 +404,8 @@ var keyinfoNewCmd = &cli.Command{
keyInfo = ki
break
case wallet.KTSecp256k1, wallet.KTBLS:
key, err := wallet.GenerateKey(wallet.ActSigType(keyType))
case types.KTSecp256k1, types.KTBLS:
key, err := wallet.GenerateKey(keyType)
if err != nil {
return err
}
@@ -418,7 +418,7 @@ var keyinfoNewCmd = &cli.Command{
filename := flagOutput
filename = strings.ReplaceAll(filename, "<addr>", keyAddr)
filename = strings.ReplaceAll(filename, "<type>", keyType)
filename = strings.ReplaceAll(filename, "<type>", string(keyType))
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
+248
View File
@@ -0,0 +1,248 @@
package main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/filecoin-project/go-address"
"github.com/urfave/cli/v2"
ledgerfil "github.com/whyrusleeping/ledger-filecoin-go"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
lcli "github.com/filecoin-project/lotus/cli"
)
var ledgerCmd = &cli.Command{
Name: "ledger",
Usage: "Ledger interactions",
Flags: []cli.Flag{},
Subcommands: []*cli.Command{
ledgerListAddressesCmd,
ledgerKeyInfoCmd,
ledgerSignTestCmd,
},
}
const hdHard = 0x80000000
var ledgerListAddressesCmd = &cli.Command{
Name: "list",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "print-balances",
Usage: "print balances",
Aliases: []string{"b"},
},
},
Action: func(cctx *cli.Context) error {
var api api.FullNode
if cctx.Bool("print-balances") {
a, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
api = a
defer closer()
}
ctx := lcli.ReqContext(cctx)
fl, err := ledgerfil.FindLedgerFilecoinApp()
if err != nil {
return err
}
end := 20
for i := 0; i < end; i++ {
if err := ctx.Err(); err != nil {
return err
}
p := []uint32{hdHard | 44, hdHard | 461, hdHard, 0, uint32(i)}
pubk, err := fl.GetPublicKeySECP256K1(p)
if err != nil {
return err
}
addr, err := address.NewSecp256k1Address(pubk)
if err != nil {
return err
}
if cctx.Bool("print-balances") && api != nil { // api check makes linter happier
b, err := api.WalletBalance(ctx, addr)
if err != nil {
return xerrors.Errorf("getting balance: %w", err)
}
if !b.IsZero() {
end = i + 21 // BIP32 spec, stop after 20 empty addresses
}
fmt.Printf("%s %s %s\n", addr, printHDPath(p), types.FIL(b))
} else {
fmt.Printf("%s %s\n", addr, printHDPath(p))
}
}
return nil
},
}
func parseHDPath(s string) ([]uint32, error) {
parts := strings.Split(s, "/")
if parts[0] != "m" {
return nil, fmt.Errorf("expected HD path to start with 'm'")
}
var out []uint32
for _, p := range parts[1:] {
var hard bool
if strings.HasSuffix(p, "'") {
p = p[:len(p)-1]
hard = true
}
v, err := strconv.ParseUint(p, 10, 32)
if err != nil {
return nil, err
}
if v >= hdHard {
return nil, fmt.Errorf("path element %s too large", p)
}
if hard {
v += hdHard
}
out = append(out, uint32(v))
}
return out, nil
}
func printHDPath(pth []uint32) string {
s := "m"
for _, p := range pth {
s += "/"
hard := p&hdHard != 0
p &^= hdHard // remove hdHard bit
s += fmt.Sprint(p)
if hard {
s += "'"
}
}
return s
}
var ledgerKeyInfoCmd = &cli.Command{
Name: "key-info",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
},
},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
}
fl, err := ledgerfil.FindLedgerFilecoinApp()
if err != nil {
return err
}
p, err := parseHDPath(cctx.Args().First())
if err != nil {
return err
}
pubk, _, addr, err := fl.GetAddressPubKeySECP256K1(p)
if err != nil {
return err
}
if cctx.Bool("verbose") {
fmt.Println(addr)
fmt.Println(pubk)
}
a, err := address.NewFromString(addr)
if err != nil {
return err
}
var pd ledgerwallet.LedgerKeyInfo
pd.Address = a
pd.Path = p
b, err := json.Marshal(pd)
if err != nil {
return err
}
var ki types.KeyInfo
ki.Type = types.KTSecp256k1Ledger
ki.PrivateKey = b
out, err := json.Marshal(ki)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
}
var ledgerSignTestCmd = &cli.Command{
Name: "sign",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
}
fl, err := ledgerfil.FindLedgerFilecoinApp()
if err != nil {
return err
}
p, err := parseHDPath(cctx.Args().First())
if err != nil {
return err
}
addr, err := address.NewFromString("f1xc3hws5n6y5m3m44gzb3gyjzhups6wzmhe663ji")
if err != nil {
return err
}
m := &types.Message{
To: addr,
From: addr,
}
b, err := m.ToStorageBlock()
if err != nil {
return err
}
sig, err := fl.SignSECP256K1(p, b.RawData())
if err != nil {
return err
}
fmt.Println(sig.SignatureBytes())
return nil
},
}
+1
View File
@@ -41,6 +41,7 @@ func main() {
syncCmd,
stateTreePruneCmd,
datastoreCmd,
ledgerCmd,
}
app := &cli.App{
+105
View File
@@ -5,6 +5,11 @@ import (
"os"
"strings"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/lotus/build"
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
@@ -34,6 +39,7 @@ var actorCmd = &cli.Command{
Subcommands: []*cli.Command{
actorSetAddrsCmd,
actorWithdrawCmd,
actorRepayDebtCmd,
actorSetPeeridCmd,
actorSetOwnerCmd,
actorControl,
@@ -254,6 +260,105 @@ var actorWithdrawCmd = &cli.Command{
},
}
var actorRepayDebtCmd = &cli.Command{
Name: "repay-debt",
Usage: "pay down a miner's debt",
ArgsUsage: "[amount (FIL)]",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "from",
Usage: "optionally specify the account to send funds from",
},
},
Action: func(cctx *cli.Context) error {
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
api, acloser, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(cctx)
maddr, err := nodeApi.ActorAddress(ctx)
if err != nil {
return err
}
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
var amount abi.TokenAmount
if cctx.Args().Present() {
f, err := types.ParseFIL(cctx.Args().First())
if err != nil {
return xerrors.Errorf("parsing 'amount' argument: %w", err)
}
amount = abi.TokenAmount(f)
} else {
mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
store := adt.WrapStore(ctx, cbor.NewCborStore(apibstore.NewAPIBlockstore(api)))
mst, err := miner.Load(store, mact)
if err != nil {
return err
}
amount, err = mst.FeeDebt()
if err != nil {
return err
}
}
fromAddr := mi.Worker
if from := cctx.String("from"); from != "" {
addr, err := address.NewFromString(from)
if err != nil {
return err
}
fromAddr = addr
}
fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK)
if err != nil {
return err
}
if !mi.IsController(fromId) {
return xerrors.Errorf("sender isn't a controller of miner: %s", fromId)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
To: maddr,
From: fromId,
Value: amount,
Method: builtin2.MethodsMiner.RepayDebt,
Params: nil,
}, nil)
if err != nil {
return err
}
fmt.Printf("Sent repay debt message %s\n", smsg.Cid())
return nil
},
}
var actorControl = &cli.Command{
Name: "control",
Usage: "Manage control addresses",
+2 -3
View File
@@ -27,7 +27,6 @@ import (
cborutil "github.com/filecoin-project/go-cbor-util"
paramfetch "github.com/filecoin-project/go-paramfetch"
"github.com/filecoin-project/go-state-types/abi"
crypto2 "github.com/filecoin-project/go-state-types/crypto"
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
@@ -156,7 +155,7 @@ var initCmd = &cli.Command{
log.Info("Checking full node sync status")
if !cctx.Bool("genesis-miner") && !cctx.Bool("nosync") {
if err := lcli.SyncWait(ctx, api); err != nil {
if err := lcli.SyncWait(ctx, api, false); err != nil {
return xerrors.Errorf("sync wait: %w", err)
}
}
@@ -624,7 +623,7 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID,
if cctx.String("worker") != "" {
worker, err = address.NewFromString(cctx.String("worker"))
} else if cctx.Bool("create-worker-key") { // TODO: Do we need to force this if owner is Secpk?
worker, err = api.WalletNew(ctx, crypto2.SigTypeBLS)
worker, err = api.WalletNew(ctx, types.KTBLS)
}
// TODO: Transfer some initial funds to worker
if err != nil {
+1 -1
View File
@@ -72,7 +72,7 @@ var initRestoreCmd = &cli.Command{
}
if !cctx.Bool("nosync") {
if err := lcli.SyncWait(ctx, api); err != nil {
if err := lcli.SyncWait(ctx, api, false); err != nil {
return xerrors.Errorf("sync wait: %w", err)
}
}
+1 -1
View File
@@ -84,7 +84,7 @@ var runCmd = &cli.Command{
log.Info("Checking full node sync status")
if !cctx.Bool("nosync") {
if err := lcli.SyncWait(ctx, nodeApi); err != nil {
if err := lcli.SyncWait(ctx, nodeApi, false); err != nil {
return xerrors.Errorf("sync wait: %w", err)
}
}
+2 -1
View File
@@ -80,7 +80,8 @@ var sealingWorkersCmd = &cli.Command{
cpuBars := int(stat.CpuUse * barCols / stat.Info.Resources.CPUs)
cpuBar := strings.Repeat("|", cpuBars) + strings.Repeat(" ", int(barCols)-cpuBars)
fmt.Printf("\tCPU: [%s] %d core(s) in use\n", color.GreenString(cpuBar), stat.CpuUse)
fmt.Printf("\tCPU: [%s] %d/%d core(s) in use\n",
color.GreenString(cpuBar), stat.CpuUse, stat.Info.Resources.CPUs)
ramBarsRes := int(stat.Info.Resources.MemReserved * barCols / stat.Info.Resources.MemPhysical)
ramBarsUsed := int(stat.MemUsedMin * barCols / stat.Info.Resources.MemPhysical)
+2 -7
View File
@@ -19,13 +19,8 @@ type LoggedWallet struct {
under api.WalletAPI
}
func (c *LoggedWallet) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
n, err := typ.Name()
if err != nil {
return address.Address{}, err
}
log.Infow("WalletNew", "type", n)
func (c *LoggedWallet) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
log.Infow("WalletNew", "type", typ)
return c.under.WalletNew(ctx, typ)
}
+21 -1
View File
@@ -11,8 +11,11 @@ import (
"github.com/urfave/cli/v2"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/wallet"
ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/lib/lotuslog"
"github.com/filecoin-project/lotus/node/repo"
@@ -60,6 +63,10 @@ var runCmd = &cli.Command{
Usage: "host address and port the wallet api will listen on",
Value: "0.0.0.0:1777",
},
&cli.BoolFlag{
Name: "ledger",
Usage: "use a ledger device instead of an on-disk wallet",
},
},
Action: func(cctx *cli.Context) error {
log.Info("Starting lotus wallet")
@@ -94,11 +101,24 @@ var runCmd = &cli.Command{
return err
}
w, err := wallet.NewWallet(ks)
lw, err := wallet.NewWallet(ks)
if err != nil {
return err
}
var w api.WalletAPI = lw
if cctx.Bool("ledger") {
ds, err := lr.Datastore("/metadata")
if err != nil {
return err
}
w = wallet.MultiWallet{
Local: lw,
Ledger: ledgerwallet.NewWallet(ds),
}
}
address := cctx.String("listen")
mux := mux.NewRouter()
+5 -1
View File
@@ -436,6 +436,10 @@ func ImportChain(r repo.Repo, fname string, snapshot bool) (err error) {
return xerrors.Errorf("importing chain failed: %w", err)
}
if err := cst.FlushValidationCache(); err != nil {
return xerrors.Errorf("flushing validation cache failed: %w", err)
}
gb, err := cst.GetTipsetByHeight(context.TODO(), 0, ts, true)
if err != nil {
return err
@@ -455,7 +459,7 @@ func ImportChain(r repo.Repo, fname string, snapshot bool) (err error) {
}
}
log.Info("accepting %s as new head", ts.Cids())
log.Infof("accepting %s as new head", ts.Cids())
if err := cst.SetHead(ts); err != nil {
return err
}
+37
View File
@@ -0,0 +1,37 @@
package main
import (
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/build"
)
// ProtocolCodenames is a table that summarises the protocol codenames that
// will be set on extracted vectors, depending on the original execution height.
//
// Implementers rely on these names to filter the vectors they can run through
// their implementations, based on their support level
var ProtocolCodenames = []struct {
firstEpoch abi.ChainEpoch
name string
}{
{0, "genesis"},
{build.UpgradeBreezeHeight + 1, "breeze"},
{build.UpgradeSmokeHeight + 1, "smoke"},
{build.UpgradeIgnitionHeight + 1, "ignition"},
{build.UpgradeRefuelHeight + 1, "refuel"},
{build.UpgradeActorsV2Height + 1, "actorsv2"},
{build.UpgradeTapeHeight + 1, "tape"},
{build.UpgradeLiftoffHeight + 1, "liftoff"},
}
// GetProtocolCodename gets the protocol codename associated with a height.
func GetProtocolCodename(height abi.ChainEpoch) string {
for i, v := range ProtocolCodenames {
if height < v.firstEpoch {
// found the cutoff, return previous.
return ProtocolCodenames[i-1].name
}
}
return ProtocolCodenames[len(ProtocolCodenames)-1].name
}
+28
View File
@@ -0,0 +1,28 @@
package main
import (
"math"
"testing"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/build"
)
func TestProtocolCodenames(t *testing.T) {
if height := abi.ChainEpoch(100); GetProtocolCodename(height) != "genesis" {
t.Fatal("expected genesis codename")
}
if height := abi.ChainEpoch(build.UpgradeBreezeHeight + 1); GetProtocolCodename(height) != "breeze" {
t.Fatal("expected breeze codename")
}
if height := build.UpgradeActorsV2Height + 1; GetProtocolCodename(height) != "actorsv2" {
t.Fatal("expected actorsv2 codename")
}
if height := abi.ChainEpoch(math.MaxInt64); GetProtocolCodename(height) != ProtocolCodenames[len(ProtocolCodenames)-1].name {
t.Fatal("expected last codename")
}
}
+17 -13
View File
@@ -72,20 +72,24 @@ func runExecLotus(_ *cli.Context) error {
func executeTestVector(tv schema.TestVector) error {
log.Println("executing test vector:", tv.Meta.ID)
r := new(conformance.LogReporter)
switch class := tv.Class; class {
case "message":
conformance.ExecuteMessageVector(r, &tv)
case "tipset":
conformance.ExecuteTipsetVector(r, &tv)
default:
return fmt.Errorf("test vector class %s not supported", class)
}
if r.Failed() {
log.Println(color.HiRedString("❌ test vector failed"))
} else {
log.Println(color.GreenString("✅ test vector succeeded"))
for _, v := range tv.Pre.Variants {
r := new(conformance.LogReporter)
switch class, v := tv.Class, v; class {
case "message":
conformance.ExecuteMessageVector(r, &tv, &v)
case "tipset":
conformance.ExecuteTipsetVector(r, &tv, &v)
default:
return fmt.Errorf("test vector class %s not supported", class)
}
if r.Failed() {
log.Println(color.HiRedString("❌ test vector failed for variant %s", v.ID))
} else {
log.Println(color.GreenString("✅ test vector succeeded for variant %s", v.ID))
}
}
return nil
+14 -2
View File
@@ -135,7 +135,7 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
}
// get the circulating supply before the message was executed.
circSupplyDetail, err := fapi.StateCirculatingSupply(ctx, incTs.Key())
circSupplyDetail, err := fapi.StateVMCirculatingSupplyInternal(ctx, incTs.Key())
if err != nil {
return fmt.Errorf("failed while fetching circulating supply: %w", err)
}
@@ -347,6 +347,13 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
return err
}
nv, err := fapi.StateNetworkVersion(ctx, execTs.Key())
if err != nil {
return err
}
codename := GetProtocolCodename(execTs.Height())
// Write out the test vector.
vector := schema.TestVector{
Class: schema.ClassMessage,
@@ -363,10 +370,15 @@ func doExtract(ctx context.Context, fapi api.FullNode, opts extractOpts) error {
{Source: fmt.Sprintf("execution_tipset:%s", execTs.Key().String())},
{Source: "github.com/filecoin-project/lotus", Version: version.String()}},
},
Selector: schema.Selector{
schema.SelectorMinProtocolVersion: codename,
},
Randomness: recordingRand.Recorded(),
CAR: out.Bytes(),
Pre: &schema.Preconditions{
Epoch: int64(execTs.Height()),
Variants: []schema.Variant{
{ID: codename, Epoch: int64(execTs.Height()), NetworkVersion: uint(nv)},
},
CircSupply: circSupply.Int,
BaseFee: basefee.Int,
StateTree: &schema.StateTree{
+12 -3
View File
@@ -87,7 +87,7 @@ type proxyingBlockstore struct {
ctx context.Context
api api.FullNode
lk sync.RWMutex
lk sync.Mutex
tracing bool
traced map[cid.Cid]struct{}
@@ -113,11 +113,11 @@ func (pb *proxyingBlockstore) FinishTracing() map[cid.Cid]struct{} {
}
func (pb *proxyingBlockstore) Get(cid cid.Cid) (blocks.Block, error) {
pb.lk.RLock()
pb.lk.Lock()
if pb.tracing {
pb.traced[cid] = struct{}{}
}
pb.lk.RUnlock()
pb.lk.Unlock()
if block, err := pb.Blockstore.Get(cid); err == nil {
return block, err
@@ -140,3 +140,12 @@ func (pb *proxyingBlockstore) Get(cid cid.Cid) (blocks.Block, error) {
return block, nil
}
func (pb *proxyingBlockstore) Put(block blocks.Block) error {
pb.lk.Lock()
if pb.tracing {
pb.traced[block.Cid()] = struct{}{}
}
pb.lk.Unlock()
return pb.Blockstore.Put(block)
}
+15 -7
View File
@@ -11,6 +11,11 @@ import (
"github.com/filecoin-project/test-vectors/schema"
)
var invokees = map[schema.Class]func(Reporter, *schema.TestVector, *schema.Variant){
schema.ClassMessage: ExecuteMessageVector,
schema.ClassTipset: ExecuteTipsetVector,
}
const (
// EnvSkipConformance, if 1, skips the conformance test suite.
EnvSkipConformance = "SKIP_CONFORMANCE"
@@ -120,13 +125,16 @@ func TestConformance(t *testing.T) {
}
// dispatch the execution depending on the vector class.
switch vector.Class {
case "message":
ExecuteMessageVector(t, &vector)
case "tipset":
ExecuteTipsetVector(t, &vector)
default:
t.Fatalf("test vector class not supported: %s", vector.Class)
invokee, ok := invokees[vector.Class]
if !ok {
t.Fatalf("unsupported test vector class: %s", vector.Class)
}
for _, variant := range vector.Pre.Variants {
variant := variant
t.Run(variant.ID, func(t *testing.T) {
invokee(t, &vector, &variant)
})
}
})
}
+2 -3
View File
@@ -82,7 +82,7 @@ type ExecuteTipsetResult struct {
// This method returns the the receipts root, the poststate root, and the VM
// message results. The latter _include_ implicit messages, such as cron ticks
// and reward withdrawal per miner.
func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot cid.Cid, parentEpoch abi.ChainEpoch, tipset *schema.Tipset) (*ExecuteTipsetResult, error) {
func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot cid.Cid, parentEpoch abi.ChainEpoch, tipset *schema.Tipset, execEpoch abi.ChainEpoch) (*ExecuteTipsetResult, error) {
var (
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
vmRand = NewFixedRand()
@@ -121,11 +121,10 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot
messages []*types.Message
results []*vm.ApplyRet
epoch = abi.ChainEpoch(tipset.Epoch)
basefee = abi.NewTokenAmount(tipset.BaseFee.Int64())
)
postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, epoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, execEpoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
messages = append(messages, msg)
results = append(results, ret)
return nil

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