Compare commits

...
Author SHA1 Message Date
whyrusleeping e6f454ac33 fix setup of burnt funds actor state 2020-08-24 18:45:09 +00:00
whyrusleeping ee20eec451 randomize ticket in genesis creation 2020-08-24 18:40:51 +00:00
Aayush Rajasekaran 9e2f56b0b7 Merge pull request #3226 from filecoin-project/fix/mpool-state-inconsistencies
Address potential mpool state inconsistencies
2020-08-21 17:17:57 -04:00
Whyrusleeping 5c315b4503 Merge pull request #3212 from filecoin-project/feat/space-race-params
space race parameters
2020-08-21 14:16:50 -07:00
vyzo 817358f1bb better semantics for mpool clear local argument
local messages should be kept unless the parameter is true
2020-08-21 23:48:35 +03:00
vyzo 3debf005a8 add --really-do-it flag to mpool clear command 2020-08-21 23:32:41 +03:00
vyzo 087955e927 add localonly option to MpoolClear 2020-08-21 23:32:41 +03:00
vyzo e33d398c33 remove pending local messages from the datastore when clearing the mpool 2020-08-21 23:32:41 +03:00
vyzo 9fc674feb4 update mpool documentation 2020-08-21 23:32:41 +03:00
vyzo 0c875774ce add mpool clear cli command 2020-08-21 23:32:41 +03:00
vyzo 3027283756 add MpoolClear api 2020-08-21 23:32:41 +03:00
vyzo 161cb32078 recover from errors in head change 2020-08-21 23:32:41 +03:00
Whyrusleeping 84bbf7f420 Merge pull request #3227 from filecoin-project/feat/drand-incentinet
Feat/drand incentinet
2020-08-21 13:06:03 -07:00
Aayush Rajasekaran d022dba14a Merge pull request #3210 from filecoin-project/asr/docs
Update changelog for 0.5.0
2020-08-21 15:44:46 -04:00
Aayush Rajasekaran bf98ebe33e Merge pull request #3223 from filecoin-project/fix/nil-commd-commr
If sectorInfo doesnt have CommD or CommR set during commit, don't crash
2020-08-21 15:18:11 -04:00
Aayush Rajasekaran 7d704bf86b Merge pull request #3230 from filecoin-project/feat/update-markets-0.5.7
Update to markets v0.5.7
2020-08-21 15:10:40 -04:00
Aayush Rajasekaran aabb90293d Merge pull request #3214 from filecoin-project/fix/genesis-remainder
Actually set genesis remainder account balance
2020-08-21 15:07:14 -04:00
Aayush Rajasekaran 6b8beabad0 Merge pull request #3211 from filecoin-project/testnet-peers
Testnet peers
2020-08-21 15:04:46 -04:00
hannahhoward 438fa637df feat(markets): update to markets v0.5.7 2020-08-21 11:49:16 -07:00
Travis Person 30b28b7f7b Update drand to incentinet 2020-08-21 17:46:43 +00:00
Hector Sanjuan 4b80bc93b0 build/drand.go: add settings for incentinet. 2020-08-21 17:45:55 +00:00
whyrusleeping 2e78f2c267 If sectorInfo doesnt have CommD or CommR set during commit, don't crash 2020-08-21 09:31:28 -07:00
vyzo 8df9c483f3 Merge pull request #3218 from filecoin-project/fix/update-pubsub
update go-libp2p-pubsub@master
2020-08-21 18:15:22 +03:00
vyzo 7c1e0d2132 update go-libp2p-pubsub@master 2020-08-21 10:53:30 +03:00
whyrusleeping 4bf7619d32 Actually set genesis remainder account balance 2020-08-20 18:59:16 -07:00
Whyrusleeping 659babc6b3 Merge pull request #3215 from filecoin-project/fix/fd-limit-test
fix fd limit test
2020-08-20 18:58:54 -07:00
whyrusleeping 38a2f82f78 fix fd limit test 2020-08-20 18:43:43 -07:00
whyrusleeping 7456cdeb42 space race parameters 2020-08-20 17:21:33 -07:00
Travis Person 0eac90b596 Testnet peers 2020-08-21 00:11:30 +00:00
Aayush Rajasekaran 393ac5a7c7 Update changelog 2020-08-20 19:52:47 -04:00
vyzo d1718369a1 Merge pull request #3205 from filecoin-project/fix/update-pubsub
update pubsub and bump behaviour penalty threshold to 6
2020-08-20 23:37:17 +03:00
Łukasz Magiera 57af7e8d1e Merge pull request #3206 from filecoin-project/docs/env-var
add a doc on environment variables that can be used to tweak lotus
2020-08-20 22:29:19 +02:00
Whyrusleeping af3fe206d6 Merge pull request #3122 from filecoin-project/feat/cmd-improvements
sorted deal listings
2020-08-20 13:29:01 -07:00
vyzo 29f6d50c49 Merge pull request #3207 from filecoin-project/fix/more-pubsub-metrics
pubsub metrics for RPCs
2020-08-20 23:28:17 +03:00
vyzo 896edfe072 pubsub metrics for RPCs 2020-08-20 23:14:32 +03:00
whyrusleeping 2010bf55b7 add a doc on environment variables that can be used to tweak lotus 2020-08-20 12:52:50 -07:00
vyzo ccd000cc16 update go-libp2p-pubsub@master 2020-08-20 22:52:40 +03:00
vyzo de05120e69 increase behaviour penalty threshold to 6 2020-08-20 22:32:41 +03:00
Aayush Rajasekaran d8a669c85a Merge pull request #3200 from filecoin-project/asr/docs
Update links
2020-08-20 15:00:38 -04:00
vyzo 87f1b7564c Merge pull request #3196 from filecoin-project/fix/pubsub-behavioural-penalty-threshold
Address issues with pubsub behavioural penalties
2020-08-20 20:19:54 +03:00
Aayush Rajasekaran 807504fa16 Update faucet link 2020-08-20 13:13:20 -04:00
Aayush Rajasekaran 93e566d7e0 Change docs.lotu.sh links to lotu.sh 2020-08-20 12:45:41 -04:00
vyzo 6193f4e062 pubsub: increase gossip history length to 10 heartbeats 2020-08-20 18:09:17 +03:00
Łukasz Magiera 364e3229b9 Merge pull request #3178 from filecoin-project/feat/miner-init-from-flag
add a from flag for miner init
2020-08-20 17:09:03 +02:00
vyzo 98d6d25c74 pubsub: set behaviour penalty threshold, increase IWANT follow up time to 5s 2020-08-20 18:08:02 +03:00
vyzo 67bf952c5a gomod: update go-libp2p-pubsub@master 2020-08-20 18:06:06 +03:00
Łukasz Magiera 0acc461cb1 Merge pull request #3185 from filecoin-project/fix/chainwatch/fix-nil-smoothing-estimate
fix(chainwatch): Handle RewardState.EpochSmoothingEstimate == nil
2020-08-20 11:20:58 +02:00
Łukasz Magiera cd82f79d35 Merge pull request #3191 from filecoin-project/feat/miner-data-transfers
Add data transfer list command to miner
2020-08-20 11:18:56 +02:00
Łukasz Magiera e035e29595 Merge pull request #3189 from filecoin-project/fix/pcr-impursement
lotus-pcr: fix refund math
2020-08-20 11:00:29 +02:00
Łukasz Magiera b89e94ee86 Merge pull request #3190 from filecoin-project/feat/noise-first
NOISE first
2020-08-20 10:57:53 +02:00
Łukasz Magiera fc41b72bb6 Merge pull request #3181 from filecoin-project/asr/cc-upgrade-fix
Do not try to replace CC sectors with a deal-less sector
2020-08-20 10:56:57 +02:00
hannahhoward 0086f76a90 feat(lotus-miner): add data transfer list cmd
add equivalent command to list data transfers on miner side, extract common functionality for reuse
2020-08-20 01:35:48 -07:00
vyzo 92faf5c5f9 don't prefer TLS over NOISE 2020-08-20 11:33:19 +03:00
Travis Person 3eeec8d438 lotus-pcr: fix refund math 2020-08-20 08:28:53 +00:00
Mike Greenberg bf10de82df fix(chainwatch): Handle RewardState.EpochSmoothingEstimate == nil 2020-08-20 01:55:17 -04:00
Aayush Rajasekaran e9c526b218 Do not try to replace CC sectors with a deal-less sector 2020-08-19 22:41:23 -04:00
whyrusleeping 2675ffb128 add a from flag for miner init 2020-08-19 17:34:58 -07:00
Łukasz Magiera 885f357c59 Merge pull request #3175 from filecoin-project/feat/control-addersses-control
Wire up miner control addresses, use for PoSt
2020-08-20 02:24:33 +02:00
Łukasz Magiera de41f63fa4 miner info: Also print locked pledge 2020-08-20 02:03:42 +02:00
Łukasz Magiera a4807b18bc gofmt, api docstring 2020-08-20 01:26:13 +02:00
Łukasz Magiera b42625d824 docs: Explain setting miner control addresses 2020-08-20 01:18:03 +02:00
Łukasz Magiera 71cf358ee3 Fix windowpost test 2020-08-20 01:18:01 +02:00
Łukasz Magiera 5ea61abfe1 Wire up miner control addresses, use for post 2020-08-20 01:17:03 +02:00
Łukasz Magiera 0292c979ab Merge pull request #3043 from filecoin-project/feat/paych-cli-tests
Payment Channel CLI tests
2020-08-20 00:23:00 +02:00
Łukasz Magiera a78258efdf Merge pull request #3157 from filecoin-project/docs/paych
Payment channel lotu.sh docs
2020-08-20 00:13:49 +02:00
Łukasz Magiera bee6c0e26e Merge remote-tracking branch 'origin/master' into feat/paych-cli-tests 2020-08-20 00:12:47 +02:00
Łukasz Magiera 6e492e41d1 Merge pull request #3165 from filecoin-project/fix/validator-ignore-nonce-errors
ignore, don't reject messages with nonce that is too low
2020-08-20 00:00:20 +02:00
Łukasz Magiera f943ea7d5d Merge pull request #3170 from filecoin-project/frrist/chainwatch-SectorOnChainInfo-ext
refactor(cw): add new values to sector_info table and smoothing estimate
2020-08-19 23:58:22 +02:00
Łukasz Magiera ed098390cb Merge pull request #3172 from filecoin-project/feat/lotus-shed-jwt
lotus-shed: add simple jwt creation support
2020-08-19 23:32:01 +02:00
Łukasz Magiera 3ed3e4f5d7 Merge pull request #3162 from filecoin-project/feat/data-transfer-status
Find out what's up with data transfers!
2020-08-19 23:30:44 +02:00
Whyrusleeping 6117afe0be Merge pull request #3174 from filecoin-project/keyko-io-fix/genesis-multisig
Keyko io fix/genesis multisig
2020-08-19 13:56:36 -07:00
whyrusleeping f5dcd4a25f set missing miner ID field 2020-08-19 13:42:34 -07:00
frrist 05f1a23c94 feat(chainwatch): power actor smoothing estimate 2020-08-19 13:34:58 -07:00
whyrusleeping 621d675938 fixup tests 2020-08-19 13:32:53 -07:00
whyrusleeping 4f25c1c60e minor improvements to multisig cli commands 2020-08-19 13:10:07 -07:00
frrist fecaeda382 feat(chainwatch): reward actor smoothing estimate 2020-08-19 13:05:07 -07:00
frrist 3df85ca784 refactor(chainwatch): add new values to sector_info table 2020-08-19 13:05:07 -07:00
whyrusleeping 2ab202a03d fixup ID allocation and a few other things 2020-08-19 12:54:33 -07:00
Travis Person f1632376e7 lotus-shed: add simple jwt creation support 2020-08-19 19:21:36 +00:00
whyrusleeping 073efeeacb Merge branch 'fix/genesis-multisig' of git://github.com/keyko-io/lotus into keyko-io-fix/genesis-multisig 2020-08-19 10:51:15 -07:00
vyzo 19253dbbb1 Merge pull request #3169 from filecoin-project/fix/drand-delivery-cap
fix drand topic first message delivery cap
2020-08-19 20:02:08 +03:00
vyzo 6c5a91735a fix drand topic first message delivery cap 2020-08-19 18:45:31 +03:00
Dirk McCormick 20cb9425cc docs: paych edits 2020-08-19 08:43:06 -04:00
Sami Mäkelä 74f35c88ad checking verifreg handling 2020-08-19 15:27:50 +03:00
vyzo c7a6e32c96 ignore, don't reject messages with nonce that is too low
we seem to have a problem with this leading to many rejected messages and negative scores for
potentially innocent peers.
2020-08-19 13:20:16 +03:00
Sami Mäkelä 99e71badbf check that accounts aren't overwritten 2020-08-19 13:03:59 +03:00
Sami Mäkelä e894f360a5 merge 2020-08-19 12:26:19 +03:00
Sami Mäkelä 63ad6bc325 need to merge 2020-08-19 12:25:38 +03:00
hannahhoward 4fc5f9fe9f feat(cli): data transfer watch option
make watching data transfer CLI updates only an option
2020-08-18 18:23:51 -07:00
hannahhoward 66ac7c195c feat(cli): add updates to data transfer
Add an API to get data transfer updates and add modify the CLI to be an
ongoing monitoring plan
2020-08-18 17:36:29 -07:00
Łukasz Magiera 80e6e56a82 Merge pull request #2145 from filecoin-project/next
Next Testnet Staging
2020-08-19 02:14:30 +02:00
Łukasz Magiera 0471b10de5 Merge remote-tracking branch 'origin/master' into next 2020-08-19 02:03:14 +02:00
Łukasz Magiera 2dfc15c67d docs: Expand sealing issue template 2020-08-19 01:57:57 +02:00
David Dias d0f6804283 docs: add badgers 2020-08-19 01:57:25 +02:00
hannahhoward ef7f7375e7 fix(cli): cleanup data-transfers
cleanup output for data transfers.
2020-08-18 16:45:20 -07:00
Łukasz Magiera 7f6c86daae Merge pull request #3024 from filecoin-project/docs/expand-sealing-template
docs: Expand sealing issue template
2020-08-19 01:45:01 +02:00
Łukasz Magiera d2d72c76e0 docs: Expand sealing issue template 2020-08-19 01:40:28 +02:00
Łukasz Magiera ec4603e55d Merge pull request #3160 from filecoin-project/asr/cc-upgrade-fixes
cc upgrade fixes
2020-08-19 01:29:05 +02:00
hannahhoward f511cc188a feat(cli): data transfer command
add command to monitor data transfers
2020-08-18 16:26:21 -07:00
Aayush Rajasekaran 7de7e65dbc Calculate depositMinimum for upgrading as replaced sector's Initialpledge 2020-08-18 19:22:43 -04:00
Aayush Rajasekaran 98f00b510f re-mark replaced sectors as for upgrade if precommit fails 2020-08-18 18:53:56 -04:00
Łukasz Magiera e47e51275a Merge pull request #3138 from filecoin-project/feat/remainder
place the remainder of unallocated funds in a 'remainder' account
2020-08-18 23:52:19 +02:00
whyrusleeping 916bebadef setup proper template defaults 2020-08-18 14:34:35 -07:00
whyrusleeping abca69b476 configurable remainder account 2020-08-18 14:30:49 -07:00
Łukasz Magiera 71aa3a59d9 Merge pull request #3047 from filecoin-project/asr/burn-genesis
Do not include the burnt funds actor as a genesis account actor
2020-08-18 23:10:32 +02:00
Łukasz Magiera 19be380b53 Merge pull request #3152 from filecoin-project/fix/chainwatch/rpc-peer-id-bug
fix(api): Filter malformed peer ID before RPC marshaling
2020-08-18 23:07:55 +02:00
Łukasz Magiera 574a22de6c genesis: Set remainder account balance correctly 2020-08-18 22:52:25 +02:00
Mike Greenberg 8675ca561d fix(api): Filter malformed peer ID before RPC marshaling 2020-08-18 16:29:21 -04:00
Dirk McCormick 2b15831672 docs: payment channels 2020-08-18 16:07:04 -04:00
Łukasz Magiera 1dd554ad71 Merge pull request #3155 from filecoin-project/misc/selection-misc
Use conditional probability for miners
2020-08-18 21:56:41 +02:00
Łukasz Magiera 3fd4921ea3 Merge pull request #3147 from filecoin-project/feat/fsm-seal-limits
fsm: Config for limiting max sealing sectors
2020-08-18 21:54:41 +02:00
Łukasz Magiera a03192a39b Separate concurrent sealing sector limit for deals 2020-08-18 21:48:18 +02:00
vyzo 6d9707c784 fix OptimalSelection3 test 2020-08-18 22:24:07 +03:00
Łukasz Magiera d23cd2e507 Merge pull request #3136 from filecoin-project/asr/genesis-hardcode
Create a testnet version of setupGenesisActors
2020-08-18 21:21:04 +02:00
Łukasz Magiera 25448798b0 Merge pull request #3154 from filecoin-project/chore/add_missing_error_arg
Missing error argument
2020-08-18 21:19:20 +02:00
Łukasz Magiera d1cb60bdee Merge pull request #3118 from filecoin-project/feat/improve-pcr
lotus-pcr: refund provecommit sectors
2020-08-18 21:18:45 +02:00
Jakub Sztandera e0b72ba049 Reduce number of runs to 1
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 4d01cbfb62 Increase precision of output
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 8d4427a8bc add best ticket reward to tests
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 8bca545cab Add test for winnerProba
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 9c98cf8bc1 Fix blockProbabilities
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 8acd926636 Use conditional probability for noWinners, fix tests
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 21:10:04 +02:00
Jakub Sztandera 12f7ead55e Merge pull request #3144 from filecoin-project/feat/dedup-for-basefee
Basefee change depends on unique messages not all messages
2020-08-18 21:08:29 +02:00
Peter Rabbitson 02d21c2833 Missing error argument 2020-08-18 21:08:20 +02:00
Łukasz Magiera b23cac19ab Merge pull request #3151 from filecoin-project/asr/specs-update
Update to specs-actors v0.9.3
2020-08-18 20:56:51 +02:00
Aayush Rajasekaran 446a4f6272 Update to specs-actors v0.9.3 2020-08-18 14:24:46 -04:00
whyrusleeping 42730bcf1c handle potential overallocation 2020-08-18 10:56:54 -07:00
Aayush Rajasekaran 214eeccb18 Create a testnet version of setupGenesisActors 2020-08-18 13:56:47 -04:00
Łukasz Magiera 2570712a29 Merge pull request #3135 from filecoin-project/feat/genesis-block-linkage
proper genesis block history
2020-08-18 19:28:55 +02:00
Łukasz Magiera 6a7d72c030 fsm: fail early on too-many-sealing-sectors in pledge 2020-08-18 19:26:17 +02:00
Łukasz Magiera e7d65be90a gofmt 2020-08-18 18:27:28 +02:00
Łukasz Magiera baf91f08a1 Unbreak tests 2020-08-18 18:27:18 +02:00
Łukasz Magiera 255bd6881a Merge pull request #3142 from filecoin-project/asr/client-retrieve
Create eventless version of ClientRetrieve
2020-08-18 18:15:16 +02:00
Łukasz Magiera 886d9cd5eb fsm: handle already-precommitted CommitFailed sectors correctly 2020-08-18 18:02:25 +02:00
Jakub Sztandera c9fdd4bee2 Fix testgrounds build
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 17:40:53 +02:00
Dirk McCormick 043b63d8d8 feat: payment channel CLI tests 2020-08-18 11:26:08 -04:00
Łukasz Magiera 6a49bd6d8e fsm: Config for limiting max sealing sectors 2020-08-18 16:54:05 +02:00
Łukasz Magiera 65ffde9e4b fsm: Config for max WaitDeals sectors 2020-08-18 16:20:31 +02:00
Jakub Sztandera c841f26256 Basefee change depends on unique messages not all messages
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-18 15:28:50 +02:00
Łukasz Magiera 4cd56b3b99 impl: wait in ClientRetrieve 2020-08-18 15:27:56 +02:00
Łukasz Magiera 2d73b04f7d Merge pull request #3137 from filecoin-project/fix/chainwatch/calibration-improvements-2
More Chainwatch Improvements
2020-08-18 15:10:42 +02:00
Łukasz Magiera 36d87eb8e9 more checks around genesis CID 2020-08-18 15:04:31 +02:00
Łukasz Magiera 1ba5dd4c72 Merge pull request #3139 from filecoin-project/fix/mpool-push-deadlock
fix deadlock in mpool.Push
2020-08-18 14:09:00 +02:00
Łukasz Magiera b4d9b6efaf Merge pull request #3140 from filecoin-project/asr/restart-timer
restart WaitDeals timers if miner restarts
2020-08-18 13:54:55 +02:00
Sami Mäkelä 4ae02ef1b9 looks like it's working 2020-08-18 13:58:32 +03:00
Sami Mäkelä 88fbc044b3 adding actors for genesis msig addresses 2020-08-18 13:58:29 +03:00
Aayush Rajasekaran 8942c02f28 Add a reminder comment 2020-08-18 06:01:48 -04:00
Aayush Rajasekaran add56c8b81 Create eventless version of ClientRetrieve 2020-08-18 05:49:56 -04:00
Aayush Rajasekaran 37ff876bc6 restart WaitDeals timers if miner restarts 2020-08-18 05:07:14 -04:00
vyzo 4287f76ed4 fix deadlock in mpool.Push 2020-08-18 10:19:46 +03:00
whyrusleeping 64e18131c1 place the remainder of unallocated funds in a 'remainder' account 2020-08-17 23:38:58 -07:00
Mike Greenberg fabf26cc21 fix(chainwatch): Actually capture human actor names 2020-08-18 00:22:01 -04:00
Mike Greenberg 94e4f8d116 fix(chainwatch): Ignore blocks missing from local blockstore during processing 2020-08-18 00:22:01 -04:00
Mike Greenberg 6734287789 fix(chainwatch): Change tmp table names to not collide 2020-08-18 00:22:01 -04:00
whyrusleeping 13e5b72cdb proper genesis block history
Commit hash originally stamped into the ethereum blockchain:
https://etherscan.io/tx/0xe8f51c9eefb682cd866f059462577b6dd3d2685ff4b6437f6c940ff4f4aaf067
2020-08-17 21:13:43 -07:00
Aayush Rajasekaran 8cae101c04 Merge pull request #3134 from filecoin-project/fix/active-detection-timeout
Remove timeouts on deal committed checks
2020-08-17 22:53:17 -04:00
hannahhoward d1743555d4 fix(markets): remove timeouts on deal committed checks 2020-08-17 19:07:13 -07:00
Łukasz Magiera b463749594 Merge pull request #3131 from filecoin-project/asr/no-peerid
strip peerid when setting on-chain addrs
2020-08-18 03:21:42 +02:00
Aayush Rajasekaran 4ef5a58b36 strip peerid when setting on-chain addrs 2020-08-17 21:18:26 -04:00
Łukasz Magiera 1bd90d0701 Merge pull request #3130 from filecoin-project/fix/reachability-cli
cli: Fix net reachability
2020-08-18 03:14:11 +02:00
Łukasz Magiera 127d6d0576 cli: Fix net reachability 2020-08-18 03:12:50 +02:00
Łukasz Magiera 9db478fd2e Bump version 2020-08-18 02:58:54 +02:00
Łukasz Magiera 1cf2d1aad5 Merge pull request #3127 from filecoin-project/asr/set-peerid
Add a CLI method to set peerid
2020-08-18 02:58:17 +02:00
Aayush Rajasekaran 01b5118a08 Add a CLI method to set peerid 2020-08-17 20:53:02 -04:00
Łukasz Magiera 5c71d25872 Merge pull request #3126 from filecoin-project/feat/lotus-keygen
add lotus keygen utility
2020-08-18 02:46:12 +02:00
whyrusleeping ef8b9eae93 add lotus keygen utility 2020-08-17 17:29:26 -07:00
Łukasz Magiera dfa2ac6807 Merge pull request #3123 from filecoin-project/fix/retrieval-nil-serializing
Fix/retrieval nil serializing
2020-08-18 02:20:12 +02:00
whyrusleeping f05cff478f sorted deal listings 2020-08-17 14:48:49 -07:00
Ingar Shu cb71386ed9 Don't send finishing event if there is no error 2020-08-17 14:39:08 -07:00
Ingar Shu 7fbbf23e5a Initialize FundsSpent to zero in RetrievalEvent 2020-08-17 14:39:08 -07:00
Ingar Shu 5ace7479ad Don't try to output nil channel values 2020-08-17 14:39:08 -07:00
Travis Person 5040623a12 lotus-pcr: refund provecommit sectors 2020-08-17 21:29:59 +00:00
vyzo ff7f0a9dcd Merge pull request #3090 from filecoin-project/fix/pubsub-validation-clown-shoes
Fix clown shoes in pubsub validation
2020-08-17 23:31:45 +03:00
vyzo ca552cf83b deduplicate some block validation logic 2020-08-17 21:03:08 +03:00
Łukasz Magiera 2e78ed685f Merge pull request #3113 from filecoin-project/fix/chainwatch/calibration-improvements
Chainwatch Improvements
2020-08-17 19:06:05 +02:00
Łukasz Magiera 01df17f1e7 Merge pull request #3103 from filecoin-project/fix/fsm-recover-bork-snark
fsm: Recover from errors from VerifySeal in checkCommit
2020-08-17 19:00:16 +02:00
Łukasz Magiera f87ede501c Merge pull request #3101 from filecoin-project/fix/fsm-no-pci-panic
fsm: Fix panic on missing precommit info
2020-08-17 18:53:28 +02:00
Łukasz Magiera bb79af7721 fsm: Recover from errors from VerifySeal in checkCommit 2020-08-17 18:53:09 +02:00
Łukasz Magiera a66e202f02 fsm: Fix panic on missing precommit info 2020-08-17 18:45:38 +02:00
Łukasz Magiera 29db7047a3 Merge pull request #3112 from filecoin-project/fix/sched-hang
Fix sealing sched hands on unclean worker disconnect
2020-08-17 18:43:25 +02:00
Łukasz Magiera 6ef7a30b19 Merge pull request #3089 from filecoin-project/integrate/storage-fsm
integrate extern/{storage-fsm,sector-storage} into lotus source tree
2020-08-17 18:37:54 +02:00
Raúl Kripalani 1f016262cd readd int64 cast + nolint directive. 2020-08-17 17:26:07 +01:00
Mike Greenberg 80fef50b90 feat(chainwatch): Include detailed economic data per epoch 2020-08-17 12:22:34 -04:00
Łukasz Magiera 704578c9c2 Merge pull request #3108 from austinabell/msload
Remove unnecessary miner state load for checking slashed
2020-08-17 18:11:09 +02:00
Łukasz Magiera cfc1a54ee5 Merge pull request #3110 from filecoin-project/badgers
docs: add badgers
2020-08-17 17:57:28 +02:00
Łukasz Magiera f31473c4cf Update jsonrpc to fix sealing sched hangs 2020-08-17 17:36:21 +02:00
Łukasz Magiera 09dbd12638 Merge pull request #3107 from yaohcn/feat/addpiece-configurable
make addpiece configurable
2020-08-17 17:35:09 +02:00
Mike Greenberg b37a39588e feat(chainwatch): Add full version to help/startup log via build param 2020-08-17 11:31:59 -04:00
Mike Greenberg 0b498d25f6 fix(chainwatch): Actor code are human readable 2020-08-17 11:18:35 -04:00
David Dias f5b0c30633 docs: add badgers 2020-08-17 15:21:27 +01:00
Raúl Kripalani 862bafc63a fix lint errors. 2020-08-17 14:39:33 +01:00
austinabell c3c6fda9d5 Remove unnecessary miner state load for checking slashed 2020-08-17 09:32:47 -04:00
Raúl Kripalani efdc428d5d keep storage-fsm (renamed to storage-sealing) and sector-storage in extern. 2020-08-17 14:26:18 +01:00
Łukasz Magiera 7595b1d8d4 cli: pprof goroutines command 2020-08-17 11:49:11 +02:00
yaohcn 39bcfab37c make addpiece configurable 2020-08-17 17:39:50 +08:00
Łukasz Magiera ae40555558 Merge pull request #3104 from filecoin-project/feat/pubsub-metrics
collect pubsub metrics through the tracer
2020-08-17 10:39:46 +02:00
Łukasz Magiera 9c30b17b5a Merge pull request #3105 from yaohcn/fix/restart-flag
add missing restart flag
2020-08-17 10:37:24 +02:00
yaohcn aded4b4199 add missing restart flag 2020-08-17 16:04:50 +08:00
Łukasz Magiera eb616bff7f Merge pull request #3100 from filecoin-project/feat/mpool-improve-repub
trigger early republish from head changes
2020-08-17 09:46:46 +02:00
vyzo 8cf9595d35 collect pubsub metrics through the tracer 2020-08-17 10:46:20 +03:00
Łukasz Magiera 5c23ec73cb Merge pull request #3102 from filecoin-project/fix/mpool-docs
Some small improvements in mpool docs
2020-08-17 09:44:00 +02:00
vyzo 8d7994cd82 fix confusing wording 2020-08-17 10:12:54 +03:00
vyzo fb77a758ff note defaults in mpool configuration docs 2020-08-17 10:10:25 +03:00
vyzo 3b6e2bdb7b trigger early republish from head changes 2020-08-17 10:03:39 +03:00
Łukasz Magiera 1898b82dc4 Merge pull request #3086 from filecoin-project/feat/mpool-doc-config-cmd
Mpool documentation and config cli command
2020-08-17 08:47:40 +02:00
Łukasz Magiera 290011166f Merge pull request #3083 from filecoin-project/asr/docs
Show how to set env vars
2020-08-17 08:40:14 +02:00
Łukasz Magiera c5c819afca Merge pull request #3098 from filecoin-project/feat/config-cmd
Add config command that prints the default config file for a storage …
2020-08-17 08:36:51 +02:00
Łukasz Magiera c2687f9064 Merge pull request #3084 from shaodan/next
Fix typo
2020-08-17 08:34:28 +02:00
Łukasz Magiera 548e94d3fc Merge pull request #3079 from filecoin-project/fix/chainwatch-slow-read
fix a small issue in chain watch
2020-08-17 08:23:38 +02:00
vyzo ae88a99c84 add some lightweight validation of local messages 2020-08-17 09:04:22 +03:00
lanzafame 0d3aaabd2c Add config command that prints the default config file for a storage miner 2020-08-17 13:51:04 +10:00
vyzo 884d4ad9df fix clown shoes pubsub validation: we always accept our own self-published messages 2020-08-16 20:46:19 +03:00
Raúl Kripalani 4f6d01d2ea fix path in failing test. 2020-08-16 12:28:39 +01:00
Raúl Kripalani 2b511d2f57 fix lint errors. 2020-08-16 11:44:22 +01:00
Raúl Kripalani 1eed341951 fix test compilation error. 2020-08-16 11:14:24 +01:00
Raúl Kripalani 3c17cd655e integrate extern/sector-storage into lotus proper. 2020-08-16 11:09:58 +01:00
Raúl Kripalani fb0ccc9260 integrate extern/storage-fsm into lotus proper. 2020-08-16 10:42:13 +01:00
vyzo aa679a7359 add message pool documentation 2020-08-16 10:57:17 +03:00
vyzo 054fc4a614 add client command for mpool config 2020-08-16 09:57:53 +03:00
Dan Shao 10b5e3e576 fix typo 2020-08-16 10:20:32 +08:00
Aayush Rajasekaran e3c241e613 Show how to set env vars 2020-08-15 21:48:42 -04:00
vyzo 7f27c80a6a move sleep into the select
as it is it simply slows down the writer if there are many messages
2020-08-15 21:20:02 +03:00
Łukasz Magiera 9a23ede4fd Merge pull request #3075 from filecoin-project/fix/inter-filffi
Update filecoin-ffi to fix Intel build
2020-08-15 13:57:27 +02:00
Łukasz Magiera 9328dc27f3 Update filecoin-ffi to fix Intel build 2020-08-15 13:19:10 +02:00
Whyrusleeping 98643b90f8 Merge pull request #3068 from filecoin-project/feat/fundmgr-fix
Temporary fix for fund manager add issues
2020-08-14 21:10:08 -07:00
hannahhoward aa419155f6 feat(fundmgr): temp fix for funding issues 2020-08-14 19:37:20 -07:00
Łukasz Magiera b75ba5ea46 Merge pull request #3066 from filecoin-project/feat/cmd-improvements
add a market balance command, and a verbose mode for storage-deals list
2020-08-15 01:51:18 +02:00
whyrusleeping 8dfcf2b7d3 make things print nicerly 2020-08-14 16:46:11 -07:00
whyrusleeping 8774a7b2dd add a market balance command, and a verbose mode for storage-deals list 2020-08-14 16:45:40 -07:00
Łukasz Magiera 9012fea2f6 Merge pull request #3067 from filecoin-project/fix/addpiece-with-data
Fix AddPiece with data and multiple workers
2020-08-15 01:42:33 +02:00
Łukasz Magiera a52e406c0d Fix AddPiece with data and multiple workers 2020-08-15 01:36:29 +02:00
Łukasz Magiera 45476a208e Merge pull request #3053 from filecoin-project/feat/worker-addpiece2
Support AddPiece on workers
2020-08-14 23:50:17 +02:00
Łukasz Magiera 4ca5fef0de rpcenc: fix bug 2020-08-14 23:49:08 +02:00
Łukasz Magiera 42bb91c2e6 gofmt 2020-08-14 23:40:41 +02:00
Łukasz Magiera 1ecec49885 build: Bump versions 2020-08-14 23:40:11 +02:00
Łukasz Magiera 7fa2f20e8c Merge pull request #3064 from filecoin-project/asr/circ-supply-api
Include more info in StateCirculatingSupply
2020-08-14 23:31:28 +02:00
Łukasz Magiera d9ad6fb8c8 worker: Make disconnects less bad 2020-08-14 23:24:41 +02:00
Łukasz Magiera aa611e49fd rpcenc: Add timeout for readers 2020-08-14 23:12:55 +02:00
Aayush Rajasekaran 0359a458e4 Include more info in StateCirculatingSupply 2020-08-14 16:53:30 -04:00
Łukasz Magiera 0377d6952b Merge remote-tracking branch 'origin/next' into feat/worker-addpiece2 2020-08-14 21:17:30 +02:00
Łukasz Magiera ec242c1ba7 Update jsonrpc with stacktraces on panic 2020-08-14 21:16:42 +02:00
Łukasz Magiera 4a0171d26a Merge pull request #3058 from filecoin-project/feat/update-markets-0.5.6
Update markets 0.5.6
2020-08-14 21:13:00 +02:00
Łukasz Magiera 8955690d76 Merge pull request #3062 from filecoin-project/fix/post-conf-wait
wdpost: Wait for the correct confidence
2020-08-14 21:10:24 +02:00
Łukasz Magiera 25cb3a15e7 wdpost: Wait for the correct confidence 2020-08-14 21:03:20 +02:00
hannahhoward 6b5525b8d2 feat(markets): update markets 0.5.6
update markets to 0.5.6, removing use of validators that moved inside markets
2020-08-14 11:14:03 -07:00
Łukasz Magiera 0c75dd3865 Support AddPiece on workers 2020-08-14 16:06:53 +02:00
Łukasz Magiera 4d204d2c25 Merge pull request #3022 from filecoin-project/feat/fix-rename-miner-withdraw
miner: fix/rename miner actor withdraw
2020-08-14 13:51:58 +02:00
Łukasz Magiera 75eaa1bf5b Merge remote-tracking branch 'origin/next' into feat/fix-rename-miner-withdraw 2020-08-14 13:40:12 +02:00
vyzo b44d188912 Merge pull request #3040 from filecoin-project/misc/use-zipf-selection-test
Add competitve selection test with Zipf premium distribution
2020-08-14 10:25:29 +03:00
vyzo a5d2ec0df8 appease linter 2020-08-14 10:12:55 +03:00
vyzo b844f70a3c make competitve selection test parameteric on distribution function, add test for Zipf distribution 2020-08-14 10:09:25 +03:00
Aayush Rajasekaran 5fe85c07b1 Merge pull request #3046 from filecoin-project/asr/collateral
Move estimation correction into markets adapters
2020-08-13 22:27:43 -04:00
Aayush Rajasekaran 5ca410ae99 extract overestimation factor into a constant 2020-08-13 22:21:20 -04:00
Aayush Rajasekaran 2d90bcff3c jeromy is a bad software engineer 2020-08-13 22:14:45 -04:00
Aayush Rajasekaran c2a24b7b4c Update markets 2020-08-13 22:13:31 -04:00
Aayush Rajasekaran b49276ef47 Double provider collateral estimates in the client atadpter 2020-08-13 21:54:39 -04:00
whyrusleeping eb2879ca22 allow client to specify provider collateral 2020-08-13 21:47:36 -04:00
Aayush Rajasekaran 5702ea236c Do not include the burnt funds actor as a genesis account actor 2020-08-13 20:19:47 -04:00
Łukasz Magiera b3f27c0075 Merge pull request #3044 from filecoin-project/frrist/fix-error-actor-not-found
fix: chainwatch actor not found handling
2020-08-13 23:23:52 +02:00
frrist 50d4c2e0ac fix: error checking for actor not found 2020-08-13 14:10:05 -07:00
Łukasz Magiera 6c1ecb4d16 Merge pull request #3039 from filecoin-project/frrist/fix-id-map-table-v2
fix: chainwatch id_address_map
2020-08-13 20:49:22 +02:00
Jakub Sztandera f27a122787 Use Zipf distribution for messages
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-13 20:22:56 +02:00
frrist 55f88b46cf fix: best attempt at fixing the id_address_map 2020-08-13 11:14:58 -07:00
Jakub Sztandera 15a81707b4 Merge pull request #3036 from filecoin-project/feat/noise-gas-premium
Add noise to GasPremium calculation to help out message selection
2020-08-13 19:33:41 +02:00
Jakub Sztandera a6d79b26e4 Add comments
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-13 19:27:31 +02:00
Whyrusleeping 2db1001a07 Merge pull request #3033 from filecoin-project/fix/paych-alloc-lane
Fix bug with paych allocate lane
2020-08-13 10:24:12 -07:00
Jakub Sztandera d94119dada Merge pull request #3037 from filecoin-project/feat/mpool-selection-fixes
Some optimal selection fixes
2020-08-13 19:15:35 +02:00
vyzo 9aa8791920 make selection2 test less touchy 2020-08-13 20:02:08 +03:00
Jakub Sztandera ff7e441c82 Add noise to GasPremium calculation to help out message selection
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-13 18:57:06 +02:00
vyzo 2eff03fa1f small fixes in optimal selection
1. Remove noop updates from the previous dependencies
2. Update subsequent dependencies, which was the intention
2020-08-13 19:49:07 +03:00
Łukasz Magiera 5c0d86373e Merge pull request #3034 from filecoin-project/feat/stat-gas-limit-total
Add total gas used and limit to stats
2020-08-13 17:42:04 +02:00
Jakub Sztandera 8a8017c536 Merge pull request #3020 from filecoin-project/feat/lower-default-comm-maxfee
config: Set lower default max commit maxfee
2020-08-13 17:32:06 +02:00
Jakub Sztandera 3198d2d1e5 Add total gas used
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-13 16:55:12 +02:00
Jakub Sztandera dd619e85ff Add total gas limit to stats
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
2020-08-13 16:48:29 +02:00
Dirk McCormick 536b2ad9d7 fix: paych - bug with allocating lane 2020-08-13 10:14:11 -04:00
Łukasz Magiera 02650c7f25 miner: drop rewardsCmd from miner cmd list 2020-08-13 10:25:21 +02:00
Łukasz Magiera 936d861df5 gofmt 2020-08-13 10:20:41 +02:00
Łukasz Magiera f0d32f2c01 miner: fix/rename miner actor withdraw 2020-08-13 10:20:09 +02:00
Łukasz Magiera 97489f8bf9 config: Set lower default max commit maxfee 2020-08-13 09:40:19 +02:00
238 changed files with 5836 additions and 3229 deletions
+15 -6
View File
@@ -17,18 +17,27 @@ A brief description of the problem you encountered while proving (sealing) a sec
Including what commands you ran, and a description of your setup, is very helpful.
**Sectors list**
The output of `./lotus-miner sectors list`.
**Sectors status**
The output of `./lotus-miner sectors status --log <sectorId>` for the failed sector(s).
The output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
**Lotus miner logs**
Please go through the logs of your miner, and include screenshots of any error-like messages you find.
Alternatively please upload full log files and share a link here
**Lotus miner diagnostic info**
Please collect the following diagnostic information, and share a link here
* lotus-miner diagnostic info `lotus-miner info all > allinfo`
** Code modifications **
If you have modified parts of lotus, please describe which areas were modified,
and the scope of those modifications
**Version**
The output of `./lotus --version`.
The output of `lotus --version`.
+143 -2
View File
@@ -1,7 +1,148 @@
# lotus changelog
# Lotus changelog
## 0.5.0 / 2020-08-2020
This version of Lotus will be used for the incentivized testnet Space Race competition,
and can be considered mainnet-ready code. It includes some protocol
changes, upgrades of core dependencies, and various bugfixes and UX/performance improvements.
# Highlights
Among the highlights included in this release are:
- Gas changes: We implemented EIP-1559 and introduced real gas values.
- Deal-making: We now support "Committed Capacity" sectors, "fast-retrieval" deals,
and the packing of multiple deals into a single sector.
- Renamed features: We renamed some of the binaries, environment variables, and default
paths associated with a Lotus node.
## Gas changes
We made some significant changes to the mechanics of gas in this release.
#### Network fee
We implemented something similar to
[Ethereum's EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md).
The `Message` structure had three changes:
- The `GasPrice` field has been removed
- A new `GasFeeCap` field has been added, which controls the maximum cost
the sender incurs for the message
- A new `GasPremium` field has been added, which controls the reward a miner
earns for including the message
A sender will never be charged more than `GasFeeCap * GasLimit`.
A miner will typically earn `GasPremium * GasLimit` as a reward.
The `Blockheader` structure has one new field, called `ParentBaseFee`.
Informally speaking,the `ParentBaseFee`
is increased when blocks are densely packed with messages, and decreased otherwise.
The `ParentBaseFee` is used when calculating how much a sender burns when executing a message. _Burning_ simply refers to sending attoFIL to a dedicated, unreachable account.
A message causes `ParentBaseFee * GasUsed` attoFIL to be burnt.
#### Real gas values
This release also includes our first "real" gas costs for primitive operations.
The costs were designed to account for both the _time_ that message execution takes,
as well as the _space_ a message adds to the state tree.
## Deal-making changes
There are three key changes to the deal-making process.
#### Committed Capacity sectors
Miners can now pledge "Committed Capacity" (CC) sectors, which are explicitly
stated as containing junk data, and must not include any deals. Miners can do this
to increase their storage power, and win block rewards from this pledged storage.
They can mark these sectors as "upgradable" with `lotus-miner sectors mark-for-upgrade`.
If the miner receives and accepts one or more storage deals, the sector that includes
those deals will _replace_ the CC sector. This is intended to maximize the amount of useful
storage on the Filecoin network.
#### Fast-retrieval deals
Clients can now include a `fast-retrieval` flag when proposing deals with storage miners.
If set to true, the miner will include an extra copy of the deal data. This
data can be quickly served in a retrieval deal, since it will not need to be unsealed.
#### Multiple deals per sector
Miners can now pack multiple deals into a single sector, so long as all the deals
fit into the sector capacity. This should increase the packing efficiency of miners.
## Renamed features
To improve the user experience, we updated several names to mainatin
standard prefixing, and to better reflect the meaning of the features being referenced.
In particular, the Lotus miner binary is now called `lotus-miner`, the default
path for miner data is now `~/.lotusminer`, and the environment variable
that sets the path for miner data is now `$LOTUS_MINER_PATH`. A full list of renamed
features can be found [here](https://github.com/filecoin-project/lotus/issues/2304).
# Changelog
#### Downstream upgrades
- Upgrades markets to v0.5.6 (https://github.com/filecoin-project/lotus/pull/3058)
- Upgrades specs-actors to v0.9.3 (https://github.com/filecoin-project/lotus/pull/3151)
#### Core protocol
- Introduces gas values, replacing placeholders (https://github.com/filecoin-project/lotus/pull/2343)
- Implements EIP-1559, introducing a network base fee, message gas fee cap, and message gas fee premium (https://github.com/filecoin-project/lotus/pull/2874)
- Implements Poisson Sortition for elections (https://github.com/filecoin-project/lotus/pull/2084)
#### Deal-making lifecycle
- Introduces "Committed Capacity" sectors (https://github.com/filecoin-project/lotus/pull/2220)
- Introduces "fast-retrieval" flag for deals (https://github.com/filecoin-project/lotus/pull/2323
- Supports packing multiple deals into one sector (https://github.com/filecoin-project/storage-fsm/pull/38)
#### Enhancements
- Optimized message pool selection logic (https://github.com/filecoin-project/lotus/pull/2838)
- Window-based scheduling of sealing tasks (https://github.com/filecoin-project/sector-storage/pull/67)
- Faster window PoSt (https://github.com/filecoin-project/lotus/pull/2209/files)
- Refactors the payment channel manager (https://github.com/filecoin-project/lotus/pull/2640)
- Refactors blocksync (https://github.com/filecoin-project/lotus/pull/2715/files)
#### UX
- Provide status updates for data-transfer (https://github.com/filecoin-project/lotus/pull/3162, https://github.com/filecoin-project/lotus/pull/3191)
- Miners can customise asks (https://github.com/filecoin-project/lotus/pull/2046)
- Miners can toggle auto-acceptance of deals (https://github.com/filecoin-project/lotus/pull/1994)
- Miners can maintain a blocklist of piece CIDs (https://github.com/filecoin-project/lotus/pull/2069)
# Contributors
The following contributors had 10 or more commits go into this release.
We are grateful for every contribution!
| Contributor | Commits | Lines ± |
|--------------------|---------|---------------|
| magik6k | 361 | +13197/-6136 |
| Kubuxu | 227 | +5670/-2587 |
| arajasek | 120 | +2916/-1264 |
| whyrusleeping | 112 | +3979/-1089 |
| vyzo | 99 | +3343/-1305 |
| dirkmc | 68 | +8732/-3621 |
| laser | 45 | +1489/-501 |
| hannahhoward | 43 | +2654/-990 |
| frrist | 37 | +6630/-4338 |
| schomatis | 28 | +3016/-1368 |
| placer14 | 27 | +824/-350 |
| raulk | 25 | +28718/-29849 |
| mrsmkl | 22 | +560/-368 |
| travisperson | 18 | +1354/-314 |
| nonsense | 16 | +2956/-2842 |
| ingar | 13 | +331/-123 |
| daviddias | 11 | +311/-11 |
| Stebalien | 11 | +1204/-980 |
| RobQuistNL | 10 | +69/-74 |
## 0.1.0 / 2019-12-11
We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [docs.lotu.sh](docs.lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues).
We are very excited to release **lotus** 0.1.0. This is our testnet release. To install lotus and join the testnet, please visit [lotu.sh](lotu.sh). Please file bug reports as [issues](https://github.com/filecoin-project/lotus/issues).
A huge thank you to all contributors for this testnet release!
+2 -1
View File
@@ -148,7 +148,7 @@ BINS+=lotus-fountain
lotus-chainwatch:
rm -f lotus-chainwatch
go build -o lotus-chainwatch ./cmd/lotus-chainwatch
go build $(GOFLAGS) -o lotus-chainwatch ./cmd/lotus-chainwatch
.PHONY: lotus-chainwatch
BINS+=lotus-chainwatch
@@ -272,6 +272,7 @@ dist-clean:
type-gen:
go run ./gen/main.go
go generate ./...
method-gen:
(cd ./lotuspond/front/src/chain && go run ./methodgen.go)
+10 -2
View File
@@ -1,16 +1,24 @@
<p align="center">
<a href="https://docs.lotu.sh/" title="Lotus Docs">
<a href="https://lotu.sh/" title="Lotus Docs">
<img src="documentation/images/lotus_logo_h.png" alt="Project Lotus Logo" width="244" />
</a>
</p>
<h1 align="center">Project Lotus - 莲</h1>
<p align="center">
<a href="https://circleci.com/gh/filecoin-project/lotus"><img src="https://circleci.com/gh/filecoin-project/lotus.svg?style=svg"></a>
<a href="https://codecov.io/gh/filecoin-project/lotus"><img src="https://codecov.io/gh/filecoin-project/lotus/branch/master/graph/badge.svg"></a>
<a href="https://goreportcard.com/report/github.com/filecoin-project/lotus"><img src="https://goreportcard.com/badge/github.com/filecoin-project/lotus" /></a>
<a href=""><img src="https://img.shields.io/badge/golang-%3E%3D1.14.7-blue.svg" /></a>
<br>
</p>
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://spec.filecoin.io).
## Building & Documentation
For instructions on how to build lotus from source, please visit [https://docs.lotu.sh](https://docs.lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
For instructions on how to build lotus from source, please visit [https://lotu.sh](https://lotu.sh) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
## Reporting a Vulnerability
+2 -4
View File
@@ -4,11 +4,9 @@ import (
"context"
"fmt"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/lotus/build"
)
@@ -70,5 +68,5 @@ func (v Version) String() string {
type NatInfo struct {
Reachability network.Reachability
PublicAddr ma.Multiaddr
PublicAddr string
}
+33 -10
View File
@@ -132,6 +132,9 @@ type FullNode interface {
GasEstimateGasPremium(_ context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
// GasEstimateMessageGas estimates gas values for unset message gas fields
GasEstimateMessageGas(context.Context, *types.Message, *MessageSendSpec, types.TipSetKey) (*types.Message, error)
// MethodGroup: Sync
// The Sync method group contains methods for interacting with and
// observing the lotus sync service.
@@ -181,6 +184,9 @@ type FullNode interface {
MpoolGetNonce(context.Context, address.Address) (uint64, error)
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
// MpoolClear clears pending messages from the mpool
MpoolClear(context.Context, bool) error
// MpoolGetConfig returns (a copy of) the current mpool config
MpoolGetConfig(context.Context) (*types.MpoolConfig, error)
// MpoolSetConfig sets the mpool config to (a copy of) the supplied config
@@ -244,7 +250,10 @@ type FullNode interface {
// ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.
ClientMinerQueryOffer(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (QueryOffer, error)
// ClientRetrieve initiates the retrieval of a file, as specified in the order.
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) (<-chan marketevents.RetrievalEvent, error)
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
// ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel
// of status updates.
ClientRetrieveWithEvents(ctx context.Context, order RetrievalOrder, ref *FileRef) (<-chan marketevents.RetrievalEvent, error)
// ClientQueryAsk returns a signed StorageAsk from the specified miner.
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
// ClientCalcCommP calculates the CommP for a specified file
@@ -253,6 +262,9 @@ type FullNode interface {
ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
// ClientDealSize calculates real deal data size
ClientDealSize(ctx context.Context, root cid.Cid) (DataSize, error)
// ClientListTransfers returns the status of all ongoing transfers of data
ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
// ClientUnimport removes references to the specified file from filestore
//ClientUnimport(path string)
@@ -359,7 +371,7 @@ type FullNode interface {
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) (abi.TokenAmount, error)
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
// MethodGroup: Msig
// The Msig methods are used to interact with multisig wallets on the
@@ -469,6 +481,8 @@ type DealInfo struct {
Duration uint64
DealID abi.DealID
CreationTime time.Time
}
type MsgLookup struct {
@@ -609,14 +623,15 @@ type MethodCall struct {
}
type StartDealParams struct {
Data *storagemarket.DataRef
Wallet address.Address
Miner address.Address
EpochPrice types.BigInt
MinBlocksDuration uint64
DealStartEpoch abi.ChainEpoch
FastRetrieval bool
VerifiedDeal bool
Data *storagemarket.DataRef
Wallet address.Address
Miner address.Address
EpochPrice types.BigInt
MinBlocksDuration uint64
ProviderCollateral big.Int
DealStartEpoch abi.ChainEpoch
FastRetrieval bool
VerifiedDeal bool
}
type IpldObject struct {
@@ -673,6 +688,14 @@ type DealCollateralBounds struct {
Max abi.TokenAmount
}
type CirculatingSupply struct {
FilVested abi.TokenAmount
FilMined abi.TokenAmount
FilBurnt abi.TokenAmount
FilLocked abi.TokenAmount
FilCirculating abi.TokenAmount
}
type MiningBaseInfo struct {
MinerPower types.BigInt
NetworkPower types.BigInt
+5 -3
View File
@@ -12,9 +12,9 @@ import (
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/sector-storage/fsutil"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/sector-storage/storiface"
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
"github.com/filecoin-project/specs-actors/actors/abi"
)
@@ -79,6 +79,8 @@ type StorageMiner interface {
MarketGetAsk(ctx context.Context) (*storagemarket.SignedStorageAsk, error)
MarketSetRetrievalAsk(ctx context.Context, rask *retrievalmarket.Ask) error
MarketGetRetrievalAsk(ctx context.Context) (*retrievalmarket.Ask, error)
MarketListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
MarketDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error
DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error)
+5 -3
View File
@@ -6,9 +6,9 @@ import (
"github.com/ipfs/go-cid"
"github.com/filecoin-project/sector-storage/sealtasks"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/sector-storage/storiface"
"github.com/filecoin-project/lotus/extern/sector-storage/sealtasks"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-storage/storage"
@@ -23,6 +23,8 @@ type WorkerAPI interface {
Paths(context.Context) ([]stores.StoragePath, error)
Info(context.Context) (storiface.WorkerInfo, error)
AddPiece(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error)
storage.Sealer
MoveStorage(ctx context.Context, sector abi.SectorID) error
+70 -31
View File
@@ -15,11 +15,11 @@ import (
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/go-jsonrpc/auth"
"github.com/filecoin-project/go-multistore"
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
"github.com/filecoin-project/lotus/extern/sector-storage/sealtasks"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
marketevents "github.com/filecoin-project/lotus/markets/loggers"
"github.com/filecoin-project/sector-storage/fsutil"
"github.com/filecoin-project/sector-storage/sealtasks"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/sector-storage/storiface"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
@@ -90,9 +90,10 @@ type FullNodeStruct struct {
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
GasEstimateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
GasEstimateFeeCap func(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
GasEstimateFeeCap func(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateMessageGas func(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error) `perm:"read"`
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
@@ -105,7 +106,9 @@ type FullNodeStruct struct {
MpoolSelect func(context.Context, types.TipSetKey, float64) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
MpoolClear func(context.Context, bool) error `perm:"write"`
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
MpoolPushMessage func(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"`
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
@@ -127,20 +130,23 @@ type FullNodeStruct struct {
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
WalletDelete func(context.Context, address.Address) error `perm:"write"`
ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"`
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"`
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"`
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"`
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"`
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"`
ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"`
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"`
ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"`
ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"`
ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"`
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"`
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"`
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
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"`
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
@@ -181,7 +187,7 @@ type FullNodeStruct struct {
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*verifreg.DataCap, error) `perm:"read"`
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
StateCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
MsigGetAvailableBalance func(context.Context, address.Address, 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"`
@@ -234,6 +240,8 @@ type StorageMinerStruct struct {
MarketGetAsk func(ctx context.Context) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
MarketSetRetrievalAsk func(ctx context.Context, rask *retrievalmarket.Ask) error `perm:"admin"`
MarketGetRetrievalAsk func(ctx context.Context) (*retrievalmarket.Ask, error) `perm:"read"`
MarketListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"`
MarketDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"`
PledgeSector func(context.Context) error `perm:"write"`
@@ -300,6 +308,7 @@ type WorkerStruct struct {
Paths func(context.Context) ([]stores.StoragePath, error) `perm:"admin"`
Info func(context.Context) (storiface.WorkerInfo, error) `perm:"admin"`
AddPiece func(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error) `perm:"admin"`
SealPreCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) `perm:"admin"`
SealPreCommit2 func(context.Context, abi.SectorID, storage.PreCommit1Out) (cids storage.SectorCids, err error) `perm:"admin"`
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
@@ -424,10 +433,14 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e
return c.Internal.ClientListDeals(ctx)
}
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) {
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error {
return c.Internal.ClientRetrieve(ctx, order, ref)
}
func (c *FullNodeStruct) ClientRetrieveWithEvents(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) {
return c.Internal.ClientRetrieveWithEvents(ctx, order, ref)
}
func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) {
return c.Internal.ClientQueryAsk(ctx, p, miner)
}
@@ -443,17 +456,27 @@ func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api.
return c.Internal.ClientDealSize(ctx, root)
}
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
func (c *FullNodeStruct) ClientListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) {
return c.Internal.ClientListDataTransfers(ctx)
}
func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) {
return c.Internal.ClientDataTransferUpdates(ctx)
}
func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk)
}
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, msg *types.Message,
maxqueueblks int64, tsk types.TipSetKey) (types.BigInt, error) {
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxqueueblks int64, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.GasEstimateFeeCap(ctx, msg, maxqueueblks, tsk)
}
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
tsk types.TipSetKey) (int64, error) {
func (c *FullNodeStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
return c.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
}
func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (int64, error) {
return c.Internal.GasEstimateGasLimit(ctx, msg, tsk)
}
@@ -473,6 +496,10 @@ func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey)
return c.Internal.MpoolPending(ctx, tsk)
}
func (c *FullNodeStruct) MpoolClear(ctx context.Context, local bool) error {
return c.Internal.MpoolClear(ctx, local)
}
func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
return c.Internal.MpoolPush(ctx, smsg)
}
@@ -801,7 +828,7 @@ 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) (abi.TokenAmount, error) {
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
return c.Internal.StateCirculatingSupply(ctx, tsk)
}
@@ -1061,6 +1088,14 @@ func (c *StorageMinerStruct) MarketGetRetrievalAsk(ctx context.Context) (*retrie
return c.Internal.MarketGetRetrievalAsk(ctx)
}
func (c *StorageMinerStruct) MarketListDataTransfers(ctx context.Context) ([]api.DataTransferChannel, error) {
return c.Internal.MarketListDataTransfers(ctx)
}
func (c *StorageMinerStruct) MarketDataTransferUpdates(ctx context.Context) (<-chan api.DataTransferChannel, error) {
return c.Internal.MarketDataTransferUpdates(ctx)
}
func (c *StorageMinerStruct) DealsImportData(ctx context.Context, dealPropCid cid.Cid, file string) error {
return c.Internal.DealsImportData(ctx, dealPropCid, file)
}
@@ -1147,6 +1182,10 @@ func (w *WorkerStruct) Info(ctx context.Context) (storiface.WorkerInfo, error) {
return w.Internal.Info(ctx)
}
func (w *WorkerStruct) AddPiece(ctx context.Context, sector abi.SectorID, pieceSizes []abi.UnpaddedPieceSize, newPieceSize abi.UnpaddedPieceSize, pieceData storage.Data) (abi.PieceInfo, error) {
return w.Internal.AddPiece(ctx, sector, pieceSizes, newPieceSize, pieceData)
}
func (w *WorkerStruct) SealPreCommit1(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (storage.PreCommit1Out, error) {
return w.Internal.SealPreCommit1(ctx, sector, ticket, pieces)
}
+23 -1
View File
@@ -2,11 +2,15 @@ package client
import (
"net/http"
"net/url"
"path"
"time"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/lib/rpcenc"
)
// NewCommonRPC creates a new http jsonrpc client.
@@ -35,7 +39,7 @@ func NewFullNodeRPC(addr string, requestHeader http.Header) (api.FullNode, jsonr
}
// NewStorageMinerRPC creates a new http jsonrpc client for miner
func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMiner, jsonrpc.ClientCloser, error) {
func NewStorageMinerRPC(addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.StorageMiner, jsonrpc.ClientCloser, error) {
var res apistruct.StorageMinerStruct
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
[]interface{}{
@@ -43,18 +47,36 @@ func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMine
&res.Internal,
},
requestHeader,
opts...,
)
return &res, closer, err
}
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerAPI, jsonrpc.ClientCloser, error) {
u, err := url.Parse(addr)
if err != nil {
return nil, nil, err
}
switch u.Scheme {
case "ws":
u.Scheme = "http"
case "wss":
u.Scheme = "https"
}
///rpc/v0 -> /rpc/streams/v0/push
u.Path = path.Join(u.Path, "../streams/v0/push")
var res apistruct.WorkerStruct
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
[]interface{}{
&res.Internal,
},
requestHeader,
rpcenc.ReaderParamEncoder(u.String()),
jsonrpc.WithNoReconnect(),
jsonrpc.WithTimeout(30*time.Second),
)
return &res, closer, err
+56
View File
@@ -0,0 +1,56 @@
package test
import (
"context"
"fmt"
"sync/atomic"
"testing"
"time"
"github.com/filecoin-project/lotus/miner"
"github.com/filecoin-project/specs-actors/actors/abi"
)
type BlockMiner struct {
ctx context.Context
t *testing.T
miner TestStorageNode
blocktime time.Duration
mine int64
nulls int64
done chan struct{}
}
func NewBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *BlockMiner {
return &BlockMiner{
ctx: ctx,
t: t,
miner: miner,
blocktime: blocktime,
mine: int64(1),
done: make(chan struct{}),
}
}
func (bm *BlockMiner) MineBlocks() {
time.Sleep(time.Second)
go func() {
defer close(bm.done)
for atomic.LoadInt64(&bm.mine) == 1 {
time.Sleep(bm.blocktime)
nulls := atomic.SwapInt64(&bm.nulls, 0)
if err := bm.miner.MineOne(bm.ctx, miner.MineReq{
InjectNulls: abi.ChainEpoch(nulls),
Done: func(bool, error) {},
}); err != nil {
bm.t.Error(err)
}
}
}()
}
func (bm *BlockMiner) Stop() {
atomic.AddInt64(&bm.mine, -1)
fmt.Println("shutting down mining")
<-bm.done
}
+1 -1
View File
@@ -20,7 +20,7 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
+6 -6
View File
@@ -22,8 +22,8 @@ import (
"github.com/filecoin-project/go-fil-markets/storagemarket"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/lotus/miner"
sealing "github.com/filecoin-project/storage-fsm"
dag "github.com/ipfs/go-merkledag"
dstest "github.com/ipfs/go-merkledag/test"
unixfile "github.com/ipfs/go-unixfs/file"
@@ -47,7 +47,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -84,7 +84,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -148,7 +148,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -203,7 +203,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -398,7 +398,7 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu
Path: filepath.Join(rpath, "ret"),
IsCAR: carExport,
}
updates, err := client.ClientRetrieve(ctx, offers[0].Order(caddr), ref)
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
for update := range updates {
if update.Err != "" {
t.Fatalf("%v", err)
+2 -2
View File
@@ -24,7 +24,7 @@ var log = logging.Logger("apitest")
func (ts *testSuite) testMining(t *testing.T) {
ctx := context.Background()
apis, sn := ts.makeNodes(t, 1, oneMiner)
apis, sn := ts.makeNodes(t, 1, OneMiner)
api := apis[0]
newHeads, err := api.ChainNotify(ctx)
@@ -55,7 +55,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
}()
ctx := context.Background()
apis, sn := ts.makeNodes(t, 1, oneMiner)
apis, sn := ts.makeNodes(t, 1, OneMiner)
api := apis[0]
newHeads, err := api.ChainNotify(ctx)
+6 -77
View File
@@ -23,14 +23,13 @@ import (
"github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/miner"
)
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 2, oneMiner)
n, sn := b(t, 2, OneMiner)
paymentCreator := n[0]
paymentReceiver := n[1]
@@ -51,8 +50,8 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
}
// start mining blocks
bm := newBlockMiner(ctx, t, miner, blocktime)
bm.mineBlocks()
bm := NewBlockMiner(ctx, t, miner, blocktime)
bm.MineBlocks()
// send some funds to register the receiver
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
@@ -60,7 +59,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
t.Fatal(err)
}
sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
// setup the payment channel
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
@@ -201,10 +200,10 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
}
// shut down mining
bm.stop()
bm.Stop()
}
func waitForBlocks(ctx context.Context, t *testing.T, bm *blockMiner, paymentReceiver TestNode, receiverAddr address.Address, count int) {
func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentReceiver TestNode, receiverAddr address.Address, count int) {
// We need to add null blocks in batches, if we add too many the chain can't sync
batchSize := 60
for i := 0; i < count; i += batchSize {
@@ -249,73 +248,3 @@ func waitForMessage(ctx context.Context, t *testing.T, paymentCreator TestNode,
fmt.Println("Confirmed", desc)
return res
}
type blockMiner struct {
ctx context.Context
t *testing.T
miner TestStorageNode
blocktime time.Duration
mine int64
nulls int64
done chan struct{}
}
func newBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *blockMiner {
return &blockMiner{
ctx: ctx,
t: t,
miner: miner,
blocktime: blocktime,
mine: int64(1),
done: make(chan struct{}),
}
}
func (bm *blockMiner) mineBlocks() {
time.Sleep(time.Second)
go func() {
defer close(bm.done)
for atomic.LoadInt64(&bm.mine) == 1 {
time.Sleep(bm.blocktime)
nulls := atomic.SwapInt64(&bm.nulls, 0)
if err := bm.miner.MineOne(bm.ctx, miner.MineReq{
InjectNulls: abi.ChainEpoch(nulls),
Done: func(bool, error) {},
}); err != nil {
bm.t.Error(err)
}
}
}()
}
func (bm *blockMiner) stop() {
atomic.AddInt64(&bm.mine, -1)
fmt.Println("shutting down mining")
<-bm.done
}
func sendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) {
senderAddr, err := sender.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
msg := &types.Message{
From: senderAddr,
To: addr,
Value: amount,
}
sm, err := sender.MpoolPushMessage(ctx, msg, nil)
if err != nil {
t.Fatal(err)
}
res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1)
if err != nil {
t.Fatal(err)
}
if res.Receipt.ExitCode != 0 {
t.Fatal("did not successfully send money")
}
}
+12 -4
View File
@@ -4,6 +4,8 @@ import (
"context"
"testing"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -14,10 +16,16 @@ import (
type TestNode struct {
api.FullNode
// ListenAddr is the address on which an API server is listening, if an
// API server is created for this Node
ListenAddr multiaddr.Multiaddr
}
type TestStorageNode struct {
api.StorageMiner
// ListenAddr is the address on which an API server is listening, if an
// API server is created for this Node
ListenAddr multiaddr.Multiaddr
MineOne func(context.Context, miner.MineReq) error
}
@@ -54,11 +62,11 @@ func TestApis(t *testing.T, b APIBuilder) {
t.Run("testMiningReal", ts.testMiningReal)
}
var oneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
func (ts *testSuite) testVersion(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, 1, oneMiner)
apis, _ := ts.makeNodes(t, 1, OneMiner)
api := apis[0]
v, err := api.Version(ctx)
@@ -70,7 +78,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
func (ts *testSuite) testID(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, 1, oneMiner)
apis, _ := ts.makeNodes(t, 1, OneMiner)
api := apis[0]
id, err := api.ID(ctx)
@@ -82,7 +90,7 @@ func (ts *testSuite) testID(t *testing.T) {
func (ts *testSuite) testConnectTwo(t *testing.T) {
ctx := context.Background()
apis, _ := ts.makeNodes(t, 2, oneMiner)
apis, _ := ts.makeNodes(t, 2, OneMiner)
p, err := apis[0].NetPeers(ctx)
if err != nil {
+36
View File
@@ -0,0 +1,36 @@
package test
import (
"context"
"testing"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
)
func SendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) {
senderAddr, err := sender.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
msg := &types.Message{
From: senderAddr,
To: addr,
Value: amount,
}
sm, err := sender.MpoolPushMessage(ctx, msg, nil)
if err != nil {
t.Fatal(err)
}
res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1)
if err != nil {
t.Fatal(err)
}
if res.Receipt.ExitCode != 0 {
t.Fatal("did not successfully send money")
}
}
+4 -4
View File
@@ -12,10 +12,10 @@ import (
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/mock"
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/specs-actors/actors/abi"
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
sealing "github.com/filecoin-project/storage-fsm"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@@ -28,7 +28,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
@@ -113,7 +113,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
os.Setenv("BELLMAN_NO_GPU", "1")
ctx := context.Background()
n, sn := b(t, 1, oneMiner)
n, sn := b(t, 1, OneMiner)
client := n[0].FullNode.(*impl.FullNodeAPI)
miner := sn[0]
+66 -9
View File
@@ -2,10 +2,14 @@ package api
import (
"encoding/json"
"fmt"
"github.com/filecoin-project/go-address"
datatransfer "github.com/filecoin-project/go-data-transfer"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
@@ -46,11 +50,12 @@ type PubsubScore struct {
}
type MinerInfo struct {
Owner address.Address // Must be an ID-address.
Worker address.Address // Must be an ID-address.
NewWorker address.Address // Must be an ID-address.
Owner address.Address // Must be an ID-address.
Worker address.Address // Must be an ID-address.
NewWorker address.Address // Must be an ID-address.
ControlAddresses []address.Address // Must be an ID-addresses.
WorkerChangeEpoch abi.ChainEpoch
PeerId peer.ID
PeerId *peer.ID
Multiaddrs []abi.Multiaddrs
SealProofType abi.RegisteredSealProof
SectorSize abi.SectorSize
@@ -58,12 +63,20 @@ type MinerInfo struct {
}
func NewApiMinerInfo(info *miner.MinerInfo) MinerInfo {
var pid *peer.ID
if peerID, err := peer.IDFromBytes(info.PeerId); err == nil {
pid = &peerID
}
mi := MinerInfo{
Owner: info.Owner,
Worker: info.Worker,
NewWorker: address.Undef,
WorkerChangeEpoch: -1,
PeerId: peer.ID(info.PeerId),
Owner: info.Owner,
Worker: info.Worker,
ControlAddresses: info.ControlAddresses,
NewWorker: address.Undef,
WorkerChangeEpoch: -1,
PeerId: pid,
Multiaddrs: info.Multiaddrs,
SealProofType: info.SealProofType,
SectorSize: info.SectorSize,
@@ -93,3 +106,47 @@ func (ms *MessageSendSpec) Get() MessageSendSpec {
return *ms
}
type DataTransferChannel struct {
TransferID datatransfer.TransferID
Status datatransfer.Status
BaseCID cid.Cid
IsInitiator bool
IsSender bool
Voucher string
Message string
OtherPeer peer.ID
Transferred uint64
}
// NewDataTransferChannel constructs an API DataTransferChannel type from full channel state snapshot and a host id
func NewDataTransferChannel(hostID peer.ID, channelState datatransfer.ChannelState) DataTransferChannel {
channel := DataTransferChannel{
TransferID: channelState.TransferID(),
Status: channelState.Status(),
BaseCID: channelState.BaseCID(),
IsSender: channelState.Sender() == hostID,
Message: channelState.Message(),
}
stringer, ok := channelState.Voucher().(fmt.Stringer)
if ok {
channel.Voucher = stringer.String()
} else {
voucherJSON, err := json.Marshal(channelState.Voucher())
if err != nil {
channel.Voucher = fmt.Errorf("Voucher Serialization: %w", err).Error()
} else {
channel.Voucher = string(voucherJSON)
}
}
if channel.IsSender {
channel.IsInitiator = !channelState.IsPull()
channel.Transferred = channelState.Sent()
channel.OtherPeer = channelState.Recipient()
} else {
channel.IsInitiator = channelState.IsPull()
channel.Transferred = channelState.Received()
channel.OtherPeer = channelState.Sender()
}
return channel
}
+6 -12
View File
@@ -1,12 +1,6 @@
/dns4/bootstrap-0-sin.fil-test.net/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
/ip4/86.109.15.57/tcp/1347/p2p/12D3KooWPdUquftaQvoQEtEdsRBAhwD6jopbF2oweVTzR59VbHEd
/dns4/bootstrap-0-dfw.fil-test.net/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
/ip4/139.178.84.45/tcp/1347/p2p/12D3KooWQSCkHCzosEyrh8FgYfLejKgEPM5VB6qWzZE3yDAuXn8d
/dns4/bootstrap-0-fra.fil-test.net/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
/ip4/136.144.49.17/tcp/1347/p2p/12D3KooWEXN2eQmoyqnNjde9PBAQfQLHN67jcEdWU6JougWrgXJK
/dns4/bootstrap-1-sin.fil-test.net/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
/ip4/86.109.15.123/tcp/1347/p2p/12D3KooWLmJkZd33mJhjg5RrpJ6NFep9SNLXWc4uVngV4TXKwzYw
/dns4/bootstrap-1-dfw.fil-test.net/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
/ip4/139.178.86.3/tcp/1347/p2p/12D3KooWGXLHjiz6pTRu7x2pkgTVCoxcCiVxcNLpMnWcJ3JiNEy5
/dns4/bootstrap-1-fra.fil-test.net/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
/ip4/136.144.49.131/tcp/1347/p2p/12D3KooW9szZmKttS9A1FafH3Zc2pxKwwmvCWCGKkRP4KmbhhC4R
/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
+15 -1
View File
@@ -2,7 +2,7 @@ package build
import "github.com/filecoin-project/lotus/node/modules/dtypes"
var DrandNetwork = DrandMainnet
var DrandNetwork = DrandIncentinet
func DrandConfig() dtypes.DrandConfig {
return DrandConfigs[DrandNetwork]
@@ -15,6 +15,7 @@ const (
DrandTestnet
DrandDevnet
DrandLocalnet
DrandIncentinet
)
var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{
@@ -55,4 +56,17 @@ 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"}`,
},
}
Binary file not shown.
+3
View File
@@ -89,11 +89,14 @@ const VerifSigCacheSize = 32000
// TODO: If this is gonna stay, it should move to specs-actors
const BlockMessageLimit = 10000
const BlockGasLimit = 10_000_000_000
const BlockGasTarget = BlockGasLimit / 2
const BaseFeeMaxChangeDenom = 8 // 12.5%
const InitialBaseFee = 100e6
const MinimumBaseFee = 100
const PackingEfficiencyNum = 4
const PackingEfficiencyDenom = 5
// Actor consts
// TODO: Pull from actors when its made not private
+3
View File
@@ -66,4 +66,7 @@ var (
// Actor consts
// TODO: Pull from actors when its made not private
MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
PackingEfficiencyNum int64 = 4
PackingEfficiencyDenom int64 = 5
)
+1 -1
View File
@@ -13,7 +13,7 @@ import (
)
func init() {
power.ConsensusMinerMinPower = big.NewInt(1024 << 30)
power.ConsensusMinerMinPower = big.NewInt(10 << 40)
miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
+2 -2
View File
@@ -25,7 +25,7 @@ func buildType() string {
}
// BuildVersion is the local build version, set by build system
const BuildVersion = "0.4.4"
const BuildVersion = "0.4.6"
func UserVersion() string {
return BuildVersion + buildType() + CurrentCommit
@@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
}
// APIVersion is a semver version of the rpc api exposed
var APIVersion Version = newVer(0, 10, 0)
var APIVersion Version = newVer(0, 11, 0)
//nolint:varcheck,deadcode
const (
+20 -8
View File
@@ -34,11 +34,11 @@ import (
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/sector-storage/ffiwrapper"
)
var log = logging.Logger("gen")
@@ -92,10 +92,8 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
return b, nil
}
var rootkey, _ = address.NewIDAddress(80)
var rootkeyMultisig = genesis.MultisigMeta{
Signers: []address.Address{rootkey},
Signers: []address.Address{remAccTestKey},
Threshold: 1,
VestingDuration: 0,
VestingStart: 0,
@@ -107,6 +105,18 @@ var DefaultVerifregRootkeyActor = genesis.Actor{
Meta: rootkeyMultisig.ActorMeta(),
}
var remAccTestKey, _ = address.NewFromString("t1ceb34gnsc6qk5dt6n7xg6ycwzasjhbxm3iylkiy")
var remAccMeta = genesis.MultisigMeta{
Signers: []address.Address{remAccTestKey},
Threshold: 1,
}
var DefaultRemainderAccountActor = genesis.Actor{
Type: genesis.TMultisig,
Balance: big.NewInt(0),
Meta: remAccMeta.ActorMeta(),
}
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
@@ -210,9 +220,10 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
*genm1,
*genm2,
},
VerifregRootKey: DefaultVerifregRootkeyActor,
NetworkName: "",
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
VerifregRootKey: DefaultVerifregRootkeyActor,
RemainderAccount: DefaultRemainderAccountActor,
NetworkName: "",
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
}
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
@@ -304,7 +315,8 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
for _, link := range nd.Links() {
if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed {
pref := link.Cid.Prefix()
if pref.Codec == cid.FilCommitmentSealed || pref.Codec == cid.FilCommitmentUnsealed {
continue
}
out = append(out, link)
+41
View File
@@ -0,0 +1,41 @@
package genesis
import (
"encoding/hex"
blocks "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
)
const genesisMultihashString = "1220107d821c25dc0735200249df94a8bebc9c8e489744f86a4ca8919e81f19dcd72"
const genesisBlockHex = "a5684461746574696d6573323031372d30352d30352030313a32373a3531674e6574776f726b6846696c65636f696e65546f6b656e6846696c65636f696e6c546f6b656e416d6f756e7473a36b546f74616c537570706c796d322c3030302c3030302c303030664d696e6572736d312c3430302c3030302c3030306c50726f746f636f6c4c616273a36b446576656c6f706d656e746b3330302c3030302c3030306b46756e6472616973696e676b3230302c3030302c3030306a466f756e646174696f6e6b3130302c3030302c303030674d657373616765784854686973206973207468652047656e6573697320426c6f636b206f66207468652046696c65636f696e20446563656e7472616c697a65642053746f72616765204e6574776f726b2e"
var cidBuilder = cid.V1Builder{Codec: cid.DagCBOR, MhType: multihash.SHA2_256}
func expectedCid() cid.Cid {
mh, err := multihash.FromHexString(genesisMultihashString)
if err != nil {
panic(err)
}
return cid.NewCidV1(cidBuilder.Codec, mh)
}
func getGenesisBlock() (blocks.Block, error) {
genesisBlockData, err := hex.DecodeString(genesisBlockHex)
if err != nil {
return nil, err
}
genesisCid, err := cidBuilder.Sum(genesisBlockData)
if err != nil {
return nil, err
}
block, err := blocks.NewBlockWithCid(genesisBlockData, genesisCid)
if err != nil {
return nil, err
}
return block, nil
}
+181 -74
View File
@@ -2,7 +2,9 @@ package genesis
import (
"context"
"crypto/rand"
"encoding/json"
"fmt"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
@@ -117,11 +119,6 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
}
emptyobject, err := cst.Put(context.TODO(), []struct{}{})
if err != nil {
return nil, nil, xerrors.Errorf("failed putting empty object: %w", err)
}
// Create system actor
sysact, err := SetupSystemActor(bs)
@@ -134,7 +131,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
// Create init actor
initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey)
idStart, initact, keyIDs, err := SetupInitActor(bs, template.NetworkName, template.Accounts, template.VerifregRootKey)
if err != nil {
return nil, nil, xerrors.Errorf("setup init actor: %w", err)
}
@@ -190,31 +187,47 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, xerrors.Errorf("set market actor: %w", err)
}
burntRoot, err := cst.Put(ctx, &account.State{
Address: builtin.BurntFundsActorAddr,
})
if err != nil {
return nil, nil, xerrors.Errorf("failed to setup burnt funds actor state: %w", err)
}
// Setup burnt-funds
err = state.SetActor(builtin.BurntFundsActorAddr, &types.Actor{
Code: builtin.AccountActorCodeID,
Balance: types.NewInt(0),
Head: emptyobject,
Head: burntRoot,
})
if err != nil {
return nil, nil, xerrors.Errorf("set burnt funds account actor: %w", err)
}
// Create accounts
for id, info := range template.Accounts {
if info.Type != genesis.TAccount && info.Type != genesis.TMultisig {
for _, info := range template.Accounts {
switch info.Type {
case genesis.TAccount:
if err := createAccountActor(ctx, cst, state, info, keyIDs); err != nil {
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
}
case genesis.TMultisig:
ida, err := address.NewIDAddress(uint64(idStart))
if err != nil {
return nil, nil, err
}
idStart++
if err := createMultisigAccount(ctx, bs, cst, state, ida, info, keyIDs); err != nil {
return nil, nil, err
}
default:
return nil, nil, xerrors.New("unsupported account type")
}
ida, err := address.NewIDAddress(uint64(AccountStart + id))
if err != nil {
return nil, nil, err
}
if err = createAccount(ctx, bs, cst, state, ida, info); err != nil {
return nil, nil, err
}
}
vregroot, err := address.NewIDAddress(80)
@@ -222,8 +235,8 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
return nil, nil, err
}
if err = createAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey); err != nil {
return nil, nil, err
if err = createMultisigAccount(ctx, bs, cst, state, vregroot, template.VerifregRootKey, keyIDs); err != nil {
return nil, nil, xerrors.Errorf("failed to set up verified registry signer: %w", err)
}
// Setup the first verifier as ID-address 81
@@ -258,63 +271,132 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
Balance: types.NewInt(0),
Head: verifierState,
})
if err != nil {
return nil, nil, xerrors.Errorf("setting account from actmap: %w", err)
}
totalFilAllocated := big.Zero()
// flush as ForEach works on the HAMT
if _, err := state.Flush(ctx); err != nil {
return nil, nil, err
}
err = state.ForEach(func(addr address.Address, act *types.Actor) error {
totalFilAllocated = big.Add(totalFilAllocated, act.Balance)
return nil
})
if err != nil {
return nil, nil, xerrors.Errorf("summing account balances in state tree: %w", err)
}
totalFil := big.Mul(big.NewInt(int64(build.FilBase)), big.NewInt(int64(build.FilecoinPrecision)))
remainingFil := big.Sub(totalFil, totalFilAllocated)
if remainingFil.Sign() < 0 {
return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated))
}
remAccKey, err := address.NewIDAddress(90)
if err != nil {
return nil, nil, err
}
template.RemainderAccount.Balance = remainingFil
if err := createMultisigAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil {
return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err)
}
return state, keyIDs, nil
}
func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor) error {
if info.Type == genesis.TAccount {
var ainfo genesis.AccountMeta
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
return xerrors.Errorf("unmarshaling account meta: %w", err)
}
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
if err != nil {
return err
}
err = state.SetActor(ida, &types.Actor{
Code: builtin.AccountActorCodeID,
Balance: info.Balance,
Head: st,
})
if err != nil {
return xerrors.Errorf("setting account from actmap: %w", err)
}
} else if info.Type == genesis.TMultisig {
var ainfo genesis.MultisigMeta
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
return xerrors.Errorf("unmarshaling account meta: %w", err)
}
pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root()
if err != nil {
return xerrors.Errorf("failed to create empty map: %v", err)
}
st, err := cst.Put(ctx, &multisig.State{
Signers: ainfo.Signers,
NumApprovalsThreshold: uint64(ainfo.Threshold),
StartEpoch: abi.ChainEpoch(ainfo.VestingStart),
UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration),
PendingTxns: pending,
InitialBalance: info.Balance,
})
if err != nil {
return err
}
err = state.SetActor(ida, &types.Actor{
Code: builtin.MultisigActorCodeID,
Balance: info.Balance,
Head: st,
})
if err != nil {
return xerrors.Errorf("setting account from actmap: %w", err)
}
func createAccountActor(ctx context.Context, cst cbor.IpldStore, state *state.StateTree, info genesis.Actor, keyIDs map[address.Address]address.Address) error {
var ainfo genesis.AccountMeta
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
return xerrors.Errorf("unmarshaling account meta: %w", err)
}
st, err := cst.Put(ctx, &account.State{Address: ainfo.Owner})
if err != nil {
return err
}
ida, ok := keyIDs[ainfo.Owner]
if !ok {
return fmt.Errorf("no registered ID for account actor: %s", ainfo.Owner)
}
err = state.SetActor(ida, &types.Actor{
Code: builtin.AccountActorCodeID,
Balance: info.Balance,
Head: st,
})
if err != nil {
return xerrors.Errorf("setting account from actmap: %w", err)
}
return nil
}
func createMultisigAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore, state *state.StateTree, ida address.Address, info genesis.Actor, keyIDs map[address.Address]address.Address) error {
if info.Type != genesis.TMultisig {
return fmt.Errorf("can only call createMultisigAccount with multisig Actor info")
}
var ainfo genesis.MultisigMeta
if err := json.Unmarshal(info.Meta, &ainfo); err != nil {
return xerrors.Errorf("unmarshaling account meta: %w", err)
}
pending, err := adt.MakeEmptyMap(adt.WrapStore(ctx, cst)).Root()
if err != nil {
return xerrors.Errorf("failed to create empty map: %v", err)
}
var signers []address.Address
for _, e := range ainfo.Signers {
idAddress, ok := keyIDs[e]
if !ok {
return fmt.Errorf("no registered key ID for signer: %s", e)
}
// Check if actor already exists
_, err := state.GetActor(e)
if err == nil {
signers = append(signers, idAddress)
continue
}
st, err := cst.Put(ctx, &account.State{Address: e})
if err != nil {
return err
}
err = state.SetActor(idAddress, &types.Actor{
Code: builtin.AccountActorCodeID,
Balance: types.NewInt(0),
Head: st,
})
if err != nil {
return xerrors.Errorf("setting account from actmap: %w", err)
}
signers = append(signers, idAddress)
}
st, err := cst.Put(ctx, &multisig.State{
Signers: signers,
NumApprovalsThreshold: uint64(ainfo.Threshold),
StartEpoch: abi.ChainEpoch(ainfo.VestingStart),
UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration),
PendingTxns: pending,
InitialBalance: info.Balance,
})
if err != nil {
return err
}
err = state.SetActor(ida, &types.Actor{
Code: builtin.MultisigActorCodeID,
Balance: info.Balance,
Head: st,
})
if err != nil {
return xerrors.Errorf("setting account from actmap: %w", err)
}
return nil
}
@@ -336,11 +418,12 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
}
for _, m := range template.Miners {
for mi, m := range template.Miners {
for si, s := range m.Sectors {
if s.Deal.Provider != m.ID {
return cid.Undef, xerrors.Errorf("Sector %d in miner %d in template had mismatch in provider and miner ID: %s != %s", si, mi, s.Deal.Provider, m.ID)
}
// Add the miner to the market actor's balance table
_, err = doExec(ctx, vm, builtin.StorageMarketActorAddr, m.Owner, builtin.MethodsMarket.AddBalance, mustEnc(adt.Empty))
for _, s := range m.Sectors {
amt := s.Deal.PieceSize
verifNeeds[keyIDs[s.Deal.Client]] += amt
sum += amt
@@ -430,14 +513,38 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
log.Infof("Empty Genesis root: %s", emptyroot)
tickBuf := make([]byte, 32)
_, _ = rand.Read(tickBuf)
genesisticket := &types.Ticket{
VRFProof: []byte("vrf proof0000000vrf proof0000000"),
VRFProof: tickBuf,
}
filecoinGenesisCid, err := cid.Decode("bafyreiaqpwbbyjo4a42saasj36kkrpv4tsherf2e7bvezkert2a7dhonoi")
if err != nil {
return nil, xerrors.Errorf("failed to decode filecoin genesis block CID: %w", err)
}
if !expectedCid().Equals(filecoinGenesisCid) {
return nil, xerrors.Errorf("expectedCid != filecoinGenesisCid")
}
gblk, err := getGenesisBlock()
if err != nil {
return nil, xerrors.Errorf("failed to construct filecoin genesis block: %w", err)
}
if !filecoinGenesisCid.Equals(gblk.Cid()) {
return nil, xerrors.Errorf("filecoinGenesisCid != gblk.Cid")
}
if err := bs.Put(gblk); err != nil {
return nil, xerrors.Errorf("failed writing filecoin genesis block to blockstore: %w", err)
}
b := &types.BlockHeader{
Miner: builtin.SystemActorAddr,
Ticket: genesisticket,
Parents: []cid.Cid{},
Parents: []cid.Cid{filecoinGenesisCid},
Height: 0,
ParentWeight: types.NewInt(0),
ParentStateRoot: stateroot,
+7 -3
View File
@@ -14,7 +14,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -137,7 +137,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
params := mustEnc(&minerInfos[i].maddr)
_, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err)
}
}
@@ -149,7 +149,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params))
if err != nil {
return xerrors.Errorf("failed to create genesis miner: %w", err)
return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err)
}
var ids market.PublishStorageDealsReturn
if err := ids.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
@@ -262,6 +262,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
return cid.Undef, xerrors.Errorf("getting current total power: %w", err)
}
pcd := miner.PreCommitDepositForPower(epochReward.ThisEpochRewardSmoothed, tpow.QualityAdjPowerSmoothed, sectorWeight)
pledge := miner.InitialPledgeForPower(
sectorWeight,
epochReward.ThisEpochBaselinePower,
@@ -271,6 +273,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
circSupply(ctx, vm, minerInfos[i].maddr),
)
pledge = big.Add(pcd, pledge)
fmt.Println(types.FIL(pledge))
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, m.Worker, pledge, builtin.MethodsMiner.PreCommitSector, mustEnc(params))
if err != nil {
+65 -14
View File
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/builtin"
@@ -19,9 +20,9 @@ import (
bstore "github.com/filecoin-project/lotus/lib/blockstore"
)
func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (*types.Actor, map[address.Address]address.Address, error) {
func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesis.Actor, rootVerifier genesis.Actor) (int64, *types.Actor, map[address.Address]address.Address, error) {
if len(initialActors) > MaxAccounts {
return nil, nil, xerrors.New("too many initial actors")
return 0, nil, nil, xerrors.New("too many initial actors")
}
var ias init_.State
@@ -32,55 +33,105 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
amap := adt.MakeEmptyMap(store)
keyToId := map[address.Address]address.Address{}
counter := int64(AccountStart)
for i, a := range initialActors {
for _, a := range initialActors {
if a.Type == genesis.TMultisig {
var ainfo genesis.MultisigMeta
if err := json.Unmarshal(a.Meta, &ainfo); err != nil {
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
}
for _, e := range ainfo.Signers {
if _, ok := keyToId[e]; ok {
continue
}
fmt.Printf("init set %s t0%d\n", e, counter)
value := cbg.CborInt(counter)
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
return 0, nil, nil, err
}
counter = counter + 1
var err error
keyToId[e], err = address.NewIDAddress(uint64(value))
if err != nil {
return 0, nil, nil, err
}
}
// Need to add actors for all multisigs too
continue
}
if a.Type != genesis.TAccount {
return nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type) // TODO: Support msig (skip here)
return 0, nil, nil, xerrors.Errorf("unsupported account type: %s", a.Type)
}
var ainfo genesis.AccountMeta
if err := json.Unmarshal(a.Meta, &ainfo); err != nil {
return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
}
fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+int64(i))
fmt.Printf("init set %s t0%d\n", ainfo.Owner, counter)
value := cbg.CborInt(AccountStart + int64(i))
value := cbg.CborInt(counter)
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
return nil, nil, err
return 0, nil, nil, err
}
counter = counter + 1
var err error
keyToId[ainfo.Owner], err = address.NewIDAddress(uint64(value))
if err != nil {
return nil, nil, err
return 0, nil, nil, err
}
}
if rootVerifier.Type == genesis.TAccount {
var ainfo genesis.AccountMeta
if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil {
return nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
}
value := cbg.CborInt(80)
if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil {
return nil, nil, err
return 0, nil, nil, err
}
} else if rootVerifier.Type == genesis.TMultisig {
var ainfo genesis.MultisigMeta
if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil {
return 0, nil, nil, xerrors.Errorf("unmarshaling account meta: %w", err)
}
for _, e := range ainfo.Signers {
if _, ok := keyToId[e]; ok {
continue
}
fmt.Printf("init set %s t0%d\n", e, counter)
value := cbg.CborInt(counter)
if err := amap.Put(adt.AddrKey(e), &value); err != nil {
return 0, nil, nil, err
}
counter = counter + 1
var err error
keyToId[e], err = address.NewIDAddress(uint64(value))
if err != nil {
return 0, nil, nil, err
}
}
}
amapaddr, err := amap.Root()
if err != nil {
return nil, nil, err
return 0, nil, nil, err
}
ias.AddressMap = amapaddr
statecid, err := store.Put(store.Context(), &ias)
if err != nil {
return nil, nil, err
return 0, nil, nil, err
}
act := &types.Actor{
@@ -88,5 +139,5 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
Head: statecid,
}
return act, keyToId, nil
return counter, act, keyToId, nil
}
+1 -1
View File
@@ -28,7 +28,7 @@ func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method abi
func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) {
act, err := vm.StateTree().GetActor(from)
if err != nil {
return nil, xerrors.Errorf("doExec failed to get from actor: %w", err)
return nil, xerrors.Errorf("doExec failed to get from actor (%s): %w", from, err)
}
ret, err := vm.ApplyImplicitMessage(ctx, &types.Message{
+16 -9
View File
@@ -14,7 +14,6 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/events/state"
@@ -52,7 +51,7 @@ func StartFundManager(lc fx.Lifecycle, api API) *FundMgr {
match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
return dealDiffFn(ctx, oldTs.Key(), newTs.Key())
}
return ev.StateChanged(fm.checkFunc, fm.stateChanged, fm.revert, int(build.MessageConfidence), events.NoTimeout, match)
return ev.StateChanged(fm.checkFunc, fm.stateChanged, fm.revert, 0, events.NoTimeout, match)
},
})
return fm
@@ -92,6 +91,10 @@ func (fm *FundMgr) stateChanged(ts *types.TipSet, ts2 *types.TipSet, states even
// overwrite our in memory cache with new values from chain (chain is canonical)
fm.lk.Lock()
for addr, balanceChange := range changedBalances {
if fm.available[addr].Int != nil {
log.Infof("State balance change recorded, prev: %s, new: %s", fm.available[addr].String(), balanceChange.To.String())
}
fm.available[addr] = balanceChange.To
}
fm.lk.Unlock()
@@ -116,15 +119,17 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
return cid.Undef, err
}
fm.lk.Lock()
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
if err != nil {
fm.lk.Unlock()
return cid.Undef, err
}
stateAvail := types.BigSub(bal.Escrow, bal.Locked)
avail, ok := fm.available[idAddr]
if !ok {
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
if err != nil {
fm.lk.Unlock()
return cid.Undef, err
}
avail = types.BigSub(bal.Escrow, bal.Locked)
avail = stateAvail
}
toAdd := types.BigSub(amt, avail)
@@ -134,6 +139,8 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
fm.available[idAddr] = big.Add(avail, toAdd)
fm.lk.Unlock()
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
if toAdd.LessThanEqual(big.Zero()) {
return cid.Undef, nil
}
+24 -2
View File
@@ -26,6 +26,28 @@ func noWinnersProb() []float64 {
return noWinnersProbCache
}
var noWinnersProbAssumingCache []float64
var noWinnersProbAssumingOnce sync.Once
func noWinnersProbAssumingMoreThanOne() []float64 {
noWinnersProbAssumingOnce.Do(func() {
cond := math.Log(-1 + math.Exp(5))
poissPdf := func(x float64) float64 {
const Mu = 5
lg, _ := math.Lgamma(x + 1)
result := math.Exp((math.Log(Mu) * x) - lg - cond)
return result
}
out := make([]float64, 0, MaxBlocks)
for i := 0; i < MaxBlocks; i++ {
out = append(out, poissPdf(float64(i+1)))
}
noWinnersProbAssumingCache = out
})
return noWinnersProbAssumingCache
}
func binomialCoefficient(n, k float64) float64 {
if k > n {
return math.NaN()
@@ -40,7 +62,7 @@ func binomialCoefficient(n, k float64) float64 {
}
func (mp *MessagePool) blockProbabilities(tq float64) []float64 {
noWinners := noWinnersProb() // cache this
noWinners := noWinnersProbAssumingMoreThanOne()
p := 1 - tq
binoPdf := func(x, trials float64) float64 {
@@ -72,7 +94,7 @@ func (mp *MessagePool) blockProbabilities(tq float64) []float64 {
for place := 0; place < MaxBlocks; place++ {
var pPlace float64
for otherWinners, pCase := range noWinners {
pPlace += pCase * binoPdf(float64(place), float64(otherWinners+1))
pPlace += pCase * binoPdf(float64(place), float64(otherWinners))
}
out = append(out, pPlace)
}
+29 -1
View File
@@ -1,6 +1,11 @@
package messagepool
import "testing"
import (
"math"
"math/rand"
"testing"
"time"
)
func TestBlockProbability(t *testing.T) {
mp := &MessagePool{}
@@ -13,3 +18,26 @@ func TestBlockProbability(t *testing.T) {
}
}
}
func TestWinnerProba(t *testing.T) {
rand.Seed(time.Now().UnixNano())
const N = 1000000
winnerProba := noWinnersProb()
sum := 0
for i := 0; i < N; i++ {
minersRand := rand.Float64()
j := 0
for ; j < MaxBlocks; j++ {
minersRand -= winnerProba[j]
if minersRand < 0 {
break
}
}
sum += j
}
if avg := float64(sum) / N; math.Abs(avg-5) > 0.01 {
t.Fatalf("avg too far off: %f", avg)
}
}
+116 -15
View File
@@ -12,6 +12,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/hashicorp/go-multierror"
lru "github.com/hashicorp/golang-lru"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
@@ -59,7 +60,7 @@ var (
ErrBroadcastAnyway = errors.New("broadcasting message despite validation fail")
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
ErrTryAgain = errors.New("state inconsistency while signing message; please try again")
ErrTryAgain = errors.New("state inconsistency while pushing message; please try again")
)
const (
@@ -75,8 +76,12 @@ type MessagePool struct {
addSema chan struct{}
closer chan struct{}
repubTk *clock.Ticker
closer chan struct{}
repubTk *clock.Ticker
repubTrigger chan struct{}
republished map[cid.Cid]struct{}
localAddrs map[address.Address]struct{}
@@ -166,6 +171,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
addSema: make(chan struct{}, 1),
closer: make(chan struct{}),
repubTk: build.Clock.Ticker(RepublishInterval),
repubTrigger: make(chan struct{}, 1),
localAddrs: make(map[address.Address]struct{}),
pending: make(map[address.Address]*msgSet),
minGasPrice: types.NewInt(0),
@@ -224,6 +230,10 @@ func (mp *MessagePool) runLoop() {
if err := mp.republishPendingMessages(); err != nil {
log.Errorf("error while republishing messages: %s", err)
}
case <-mp.repubTrigger:
if err := mp.republishPendingMessages(); err != nil {
log.Errorf("error while republishing messages: %s", err)
}
case <-mp.pruneTrigger:
if err := mp.pruneExcessMessages(); err != nil {
log.Errorf("failed to prune excess messages from mempool: %s", err)
@@ -255,6 +265,11 @@ func (mp *MessagePool) verifyMsgBeforePush(m *types.SignedMessage, epoch abi.Cha
}
func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
err := mp.checkMessage(m)
if err != nil {
return cid.Undef, err
}
// serialize push access to reduce lock contention
mp.addSema <- struct{}{}
defer func() {
@@ -262,7 +277,8 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
}()
mp.curTsLk.Lock()
epoch := mp.curTs.Height()
curTs := mp.curTs
epoch := curTs.Height()
mp.curTsLk.Unlock()
if err := mp.verifyMsgBeforePush(m, epoch); err != nil {
return cid.Undef, err
@@ -273,9 +289,17 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
return cid.Undef, err
}
if err := mp.Add(m); err != nil {
mp.curTsLk.Lock()
if mp.curTs != curTs {
mp.curTsLk.Unlock()
return cid.Undef, ErrTryAgain
}
if err := mp.addTs(m, mp.curTs); err != nil {
mp.curTsLk.Unlock()
return cid.Undef, err
}
mp.curTsLk.Unlock()
mp.lk.Lock()
if err := mp.addLocal(m, msgb); err != nil {
@@ -287,7 +311,7 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
return m.Cid(), mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
}
func (mp *MessagePool) Add(m *types.SignedMessage) error {
func (mp *MessagePool) checkMessage(m *types.SignedMessage) error {
// big messages are bad, anti DOS
if m.Size() > 32*1024 {
return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig)
@@ -306,6 +330,15 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
return err
}
return nil
}
func (mp *MessagePool) Add(m *types.SignedMessage) error {
err := mp.checkMessage(m)
if err != nil {
return err
}
// serialize push access to reduce lock contention
mp.addSema <- struct{}{}
defer func() {
@@ -676,6 +709,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
mp.curTsLk.Lock()
defer mp.curTsLk.Unlock()
repubTrigger := false
rmsgs := make(map[address.Address]map[uint64]*types.SignedMessage)
add := func(m *types.SignedMessage) {
s, ok := rmsgs[m.Message.From]
@@ -700,40 +734,70 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
mp.Remove(from, nonce)
}
maybeRepub := func(cid cid.Cid) {
if !repubTrigger {
mp.lk.Lock()
_, republished := mp.republished[cid]
mp.lk.Unlock()
if republished {
repubTrigger = true
}
}
}
var merr error
for _, ts := range revert {
pts, err := mp.api.LoadTipSet(ts.Parents())
if err != nil {
return err
}
msgs, err := mp.MessagesForBlocks(ts.Blocks())
if err != nil {
return err
log.Errorf("error loading reverted tipset parent: %s", err)
merr = multierror.Append(merr, err)
continue
}
mp.curTs = pts
msgs, err := mp.MessagesForBlocks(ts.Blocks())
if err != nil {
log.Errorf("error retrieving messages for reverted block: %s", err)
merr = multierror.Append(merr, err)
continue
}
for _, msg := range msgs {
add(msg)
}
}
for _, ts := range apply {
mp.curTs = ts
for _, b := range ts.Blocks() {
bmsgs, smsgs, err := mp.api.MessagesForBlock(b)
if err != nil {
return xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err)
xerr := xerrors.Errorf("failed to get messages for apply block %s(height %d) (msgroot = %s): %w", b.Cid(), b.Height, b.Messages, err)
log.Errorf("error retrieving messages for block: %s", xerr)
merr = multierror.Append(merr, xerr)
continue
}
for _, msg := range smsgs {
rm(msg.Message.From, msg.Message.Nonce)
maybeRepub(msg.Cid())
}
for _, msg := range bmsgs {
rm(msg.From, msg.Nonce)
maybeRepub(msg.Cid())
}
}
}
mp.curTs = ts
if repubTrigger {
select {
case mp.repubTrigger <- struct{}{}:
default:
}
}
for _, s := range rmsgs {
@@ -809,7 +873,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
}
}
return nil
return merr
}
type statBucket struct {
@@ -909,3 +973,40 @@ func (mp *MessagePool) loadLocal() error {
return nil
}
func (mp *MessagePool) Clear(local bool) {
mp.lk.Lock()
defer mp.lk.Unlock()
// remove everything if local is true, including removing local messages from
// the datastore
if local {
for a := range mp.localAddrs {
mset, ok := mp.pending[a]
if !ok {
continue
}
for _, m := range mset.msgs {
err := mp.localMsgs.Delete(datastore.NewKey(string(m.Cid().Bytes())))
if err != nil {
log.Warnf("error deleting local message: %s", err)
}
}
}
mp.pending = make(map[address.Address]*msgSet)
mp.republished = nil
return
}
// remove everything except the local messages
for a := range mp.pending {
_, isLocal := mp.localAddrs[a]
if isLocal {
continue
}
delete(mp.pending, a)
}
}
+16
View File
@@ -10,6 +10,7 @@ import (
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
)
const repubMsgLimit = 30
@@ -26,6 +27,7 @@ func (mp *MessagePool) republishPendingMessages() error {
pending := make(map[address.Address]map[uint64]*types.SignedMessage)
mp.lk.Lock()
mp.republished = nil // clear this to avoid races triggering an early republish
for actor := range mp.localAddrs {
mset, ok := mp.pending[actor]
if !ok {
@@ -115,6 +117,7 @@ func (mp *MessagePool) republishPendingMessages() error {
}
}
count := 0
log.Infof("republishing %d messages", len(msgs))
for _, m := range msgs {
mb, err := m.Serialize()
@@ -126,7 +129,20 @@ func (mp *MessagePool) republishPendingMessages() error {
if err != nil {
return xerrors.Errorf("cannot publish: %w", err)
}
count++
}
// track most recently republished messages
republished := make(map[cid.Cid]struct{})
for _, m := range msgs[:count] {
republished[m.Cid()] = struct{}{}
}
mp.lk.Lock()
// update the republished set so that we can trigger early republish from head changes
mp.republished = republished
mp.lk.Unlock()
return nil
}
+4 -4
View File
@@ -177,16 +177,16 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
for i := len(chainDeps) - 1; i >= 0; i-- {
curChain := chainDeps[i]
curChain.merged = true
// adjust the next chain for the parent, which is being merged
if next := curChain.next; next != nil && next.effPerf > 0 {
next.effPerf += next.parentOffset
}
result = append(result, curChain.msgs...)
}
chain.merged = true
// adjust the effective pefromance for all subsequent chains
if next := chain.next; next != nil && next.effPerf > 0 {
next.effPerf += next.parentOffset
for next = next.next; next != nil && next.effPerf > 0; next = next.next {
next.setEffPerf()
}
}
result = append(result, chain.msgs...)
gasLimit -= chainGasLimit
+94 -27
View File
@@ -771,16 +771,26 @@ func TestOptimalMessageSelection2(t *testing.T) {
t.Fatalf("expected %d messages, but got %d", expectedMsgs, len(msgs))
}
nextNonce := uint64(0)
var nFrom1, nFrom2 int
var nextNonce1, nextNonce2 uint64
for _, m := range msgs {
if m.Message.From != a2 {
t.Fatal("expected message from a2")
if m.Message.From == a1 {
if m.Message.Nonce != nextNonce1 {
t.Fatalf("expected nonce %d but got %d", nextNonce1, m.Message.Nonce)
}
nextNonce1++
nFrom1++
} else {
if m.Message.Nonce != nextNonce2 {
t.Fatalf("expected nonce %d but got %d", nextNonce2, m.Message.Nonce)
}
nextNonce2++
nFrom2++
}
}
if m.Message.Nonce != nextNonce {
t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce)
}
nextNonce++
if nFrom1 > nFrom2 {
t.Fatalf("expected more messages from a2 than a1; nFrom1=%d nFrom2=%d", nFrom1, nFrom2)
}
}
@@ -824,7 +834,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
nMessages := int(build.BlockGasLimit/gasLimit) + 1
for i := 0; i < nMessages; i++ {
for j := 0; j < nActors; j++ {
premium := 500000 + 20000*(nActors-j) + (nMessages+2-i)/(3*nActors) + i%3
premium := 500000 + 10000*(nActors-j) + (nMessages+2-i)/(30*nActors) + i%3
m := makeTestMessage(wallets[j], actors[j], actors[j%nActors], uint64(i), gasLimit, uint64(premium))
mustAdd(t, mp, m)
}
@@ -864,9 +874,9 @@ func TestOptimalMessageSelection3(t *testing.T) {
}
}
func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, float64) {
// in this test we use 100 actors and send 10 blocks of messages.
// actors send with an exponentially decreasing premium.
func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium func() uint64) (float64, float64, float64) {
// in this test we use 300 actors and send 10 blocks of messages.
// actors send with an randomly distributed premium dictated by the getPremium function.
// a number of miners select with varying ticket quality and we compare the
// capacity and rewards of greedy selection -vs- optimal selection
@@ -909,10 +919,10 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
for i := 0; i < nMessages; i++ {
from := rng.Intn(nActors)
to := rng.Intn(nActors)
premium := 20000*math.Exp(-3.*rand.Float64()) + 5000
nonce := nonces[from]
nonces[from]++
m := makeTestMessage(wallets[from], actors[from], actors[to], uint64(nonce), gasLimit, uint64(premium))
premium := getPremium()
m := makeTestMessage(wallets[from], actors[from], actors[to], nonce, gasLimit, premium)
mustAdd(t, mp, m)
}
@@ -924,8 +934,11 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
t.Fatal(err)
}
capacityBoost := 0.0
rewardBoost := 0.0
totalGreedyCapacity := 0.0
totalGreedyReward := 0.0
totalOptimalCapacity := 0.0
totalOptimalReward := 0.0
totalBestTQReward := 0.0
const runs = 1
for i := 0; i < runs; i++ {
// 2. optimal selection
@@ -935,31 +948,38 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
for ; i < MaxBlocks && minersRand > 0; i++ {
minersRand -= winerProba[i]
}
nMiners := i
if nMiners == 0 {
nMiners := i - 1
if nMiners < 1 {
nMiners = 1
}
optMsgs := make(map[cid.Cid]*types.SignedMessage)
bestTq := 0.0
var bestMsgs []*types.SignedMessage
for j := 0; j < nMiners; j++ {
tq := rng.Float64()
msgs, err := mp.SelectMessages(ts, tq)
if err != nil {
t.Fatal(err)
}
if tq > bestTq {
bestMsgs = msgs
}
for _, m := range msgs {
optMsgs[m.Cid()] = m
}
}
totalGreedyCapacity += float64(len(greedyMsgs))
totalOptimalCapacity += float64(len(optMsgs))
boost := float64(len(optMsgs)) / float64(len(greedyMsgs))
capacityBoost += boost
t.Logf("nMiners: %d", nMiners)
t.Logf("greedy capacity %d, optimal capacity %d (x %.1f )", len(greedyMsgs),
len(optMsgs), boost)
if len(greedyMsgs) > len(optMsgs) {
t.Fatal("greedy capacity higher than optimal capacity; wtf")
t.Errorf("greedy capacity higher than optimal capacity; wtf")
}
greedyReward := big.NewInt(0)
@@ -972,39 +992,86 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) (float64, flo
optReward.Add(optReward, mp.getGasReward(m, baseFee, ts))
}
bestTqReward := big.NewInt(0)
for _, m := range bestMsgs {
bestTqReward.Add(bestTqReward, mp.getGasReward(m, baseFee, ts))
}
totalBestTQReward += float64(bestTqReward.Uint64())
nMinersBig := big.NewInt(int64(nMiners))
greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64()
totalGreedyReward += greedyAvgReward
optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64()
totalOptimalReward += optimalAvgReward
boost = optimalAvgReward / greedyAvgReward
rewardBoost += boost
t.Logf("greedy reward: %.0f, optimal reward: %.0f (x %.1f )", greedyAvgReward,
optimalAvgReward, boost)
}
capacityBoost /= runs
rewardBoost /= runs
capacityBoost := totalOptimalCapacity / totalGreedyCapacity
rewardBoost := totalOptimalReward / totalGreedyReward
t.Logf("Average capacity boost: %f", capacityBoost)
t.Logf("Average reward boost: %f", rewardBoost)
t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e12)
logging.SetLogLevel("messagepool", "info")
return capacityBoost, rewardBoost
return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e12
}
func TestCompetitiveMessageSelection(t *testing.T) {
var capacityBoost, rewardBoost float64
func makeExpPremiumDistribution(rng *rand.Rand) func() uint64 {
return func() uint64 {
premium := 20000*math.Exp(-3.*rng.Float64()) + 5000
return uint64(premium)
}
}
func makeZipfPremiumDistribution(rng *rand.Rand) func() uint64 {
zipf := rand.NewZipf(rng, 1.001, 1, 40000)
return func() uint64 {
return zipf.Uint64() + 10000
}
}
func TestCompetitiveMessageSelectionExp(t *testing.T) {
var capacityBoost, rewardBoost, tqReward float64
seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45}
for _, seed := range seeds {
t.Log("running competitve message selection with seed", seed)
cb, rb := testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed)))
t.Log("running competitive message selection with Exponential premium distribution and seed", seed)
rng := rand.New(rand.NewSource(seed))
cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeExpPremiumDistribution(rng))
capacityBoost += cb
rewardBoost += rb
tqReward += tqR
}
capacityBoost /= float64(len(seeds))
rewardBoost /= float64(len(seeds))
tqReward /= float64(len(seeds))
t.Logf("Average capacity boost across all seeds: %f", capacityBoost)
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
}
func TestCompetitiveMessageSelectionZipf(t *testing.T) {
var capacityBoost, rewardBoost, tqReward float64
seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45}
for _, seed := range seeds {
t.Log("running competitive message selection with Zipf premium distribution and seed", seed)
rng := rand.New(rand.NewSource(seed))
cb, rb, tqR := testCompetitiveMessageSelection(t, rng, makeZipfPremiumDistribution(rng))
capacityBoost += cb
rewardBoost += rb
tqReward += tqR
}
tqReward /= float64(len(seeds))
capacityBoost /= float64(len(seeds))
rewardBoost /= float64(len(seeds))
t.Logf("Average capacity boost across all seeds: %f", capacityBoost)
t.Logf("Average reward boost across all seeds: %f", rewardBoost)
t.Logf("Average reward of best ticket across all seeds: %f", tqReward)
}
+116 -20
View File
@@ -3,9 +3,10 @@ package stmgr
import (
"context"
"fmt"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"sync"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
"github.com/filecoin-project/go-address"
@@ -323,7 +324,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet
var parentEpoch abi.ChainEpoch
pstate := blks[0].ParentStateRoot
if len(blks[0].Parents) > 0 {
if blks[0].Height > 0 {
parent, err := sm.cs.GetBlock(blks[0].Parents[0])
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err)
@@ -787,7 +788,7 @@ type genesisActor struct {
initBal abi.TokenAmount
}
// sets up information about the non-multisig actors in the genesis state
// sets up information about the actors in the genesis state
func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
gi := genesisInfo{}
@@ -850,21 +851,24 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
}
} else if act.Code == builtin.AccountActorCodeID {
// should exclude burnt funds actor and "remainder account actor"
// should only ever be "faucet" accounts in testnets
kaddr, err := address.NewFromBytes([]byte(k))
if err != nil {
return xerrors.Errorf("decoding address: %w", err)
}
kid, err := sTree.LookupID(kaddr)
if err != nil {
return xerrors.Errorf("resolving address: %w", err)
}
if kaddr != builtin.BurntFundsActorAddr {
kid, err := sTree.LookupID(kaddr)
if err != nil {
return xerrors.Errorf("resolving address: %w", err)
}
gi.genesisActors = append(gi.genesisActors, genesisActor{
addr: kid,
initBal: act.Balance,
})
gi.genesisActors = append(gi.genesisActors, genesisActor{
addr: kid,
initBal: act.Balance,
})
}
}
return nil
})
@@ -888,6 +892,83 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
return nil
}
// sets up information about the actors in the genesis state
// For testnet we use a hardcoded set of multisig states, instead of what's actually in the genesis multisigs
// We also do not consider ANY account actors (including the faucet)
func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
gi := genesisInfo{}
gb, err := sm.cs.GetGenesis()
if err != nil {
return xerrors.Errorf("getting genesis block: %w", err)
}
gts, err := types.NewTipSet([]*types.BlockHeader{gb})
if err != nil {
return xerrors.Errorf("getting genesis tipset: %w", err)
}
st, _, err := sm.TipSetState(ctx, gts)
if err != nil {
return xerrors.Errorf("getting genesis tipset state: %w", err)
}
cst := cbor.NewCborStore(sm.cs.Blockstore())
sTree, err := state.LoadStateTree(cst, st)
if err != nil {
return xerrors.Errorf("loading state tree: %w", err)
}
gi.genesisMarketFunds, err = getFilMarketLocked(ctx, sTree)
if err != nil {
return xerrors.Errorf("setting up genesis market funds: %w", err)
}
gi.genesisPledge, err = getFilPowerLocked(ctx, sTree)
if err != nil {
return xerrors.Errorf("setting up genesis pledge: %w", err)
}
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
// 6 months
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
totalsByEpoch[sixMonths] = big.NewInt(49_929_341)
totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700))
// 1 year
oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay)
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
// 2 years
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
// 3 years
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
// 6 years
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
gi.genesisMsigs = make([]multisig.State, 0, len(totalsByEpoch))
for k, v := range totalsByEpoch {
ns := multisig.State{
InitialBalance: v,
UnlockDuration: k,
PendingTxns: cid.Undef,
}
gi.genesisMsigs = append(gi.genesisMsigs, ns)
}
sm.genInfo = &gi
return nil
}
// GetVestedFunds returns all funds that have "left" actors that are in the genesis state:
// - For Multisigs, it counts the actual amounts that have vested at the given epoch
// - For Accounts, it counts max(currentBalance - genesisBalance, 0).
@@ -898,7 +979,7 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch,
vf = big.Add(vf, au)
}
// these should only ever be "faucet" accounts in testnets
// there should not be any such accounts in testnet (and also none in mainnet?)
for _, v := range sm.genInfo.genesisActors {
act, err := st.GetActor(v.addr)
if err != nil {
@@ -984,34 +1065,34 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
return burnt.Balance, nil
}
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
sm.genesisMsigLk.Lock()
defer sm.genesisMsigLk.Unlock()
if sm.genInfo == nil {
err := sm.setupGenesisActors(ctx)
err := sm.setupGenesisActorsTestnet(ctx)
if err != nil {
return big.Zero(), xerrors.Errorf("failed to setup genesis information: %w", err)
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup genesis information: %w", err)
}
}
filVested, err := sm.GetFilVested(ctx, height, st)
if err != nil {
return big.Zero(), xerrors.Errorf("failed to calculate filVested: %w", err)
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
}
filMined, err := GetFilMined(ctx, st)
if err != nil {
return big.Zero(), xerrors.Errorf("failed to calculate filMined: %w", err)
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filMined: %w", err)
}
filBurnt, err := GetFilBurnt(ctx, st)
if err != nil {
return big.Zero(), xerrors.Errorf("failed to calculate filBurnt: %w", err)
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filBurnt: %w", err)
}
filLocked, err := sm.GetFilLocked(ctx, st)
if err != nil {
return big.Zero(), xerrors.Errorf("failed to calculate filLocked: %w", err)
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filLocked: %w", err)
}
ret := types.BigAdd(filVested, filMined)
@@ -1022,5 +1103,20 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
ret = big.Zero()
}
return ret, nil
return api.CirculatingSupply{
FilVested: filVested,
FilMined: filMined,
FilBurnt: filBurnt,
FilLocked: filLocked,
FilCirculating: ret,
}, nil
}
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
if err != nil {
return big.Zero(), err
}
return csi.FilCirculating, nil
}
+2 -8
View File
@@ -13,7 +13,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
@@ -293,14 +293,8 @@ func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
}
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return false, xerrors.Errorf("(get miner slashed) failed to load miner actor state")
}
var spas power.State
_, err = sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts)
_, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts)
if err != nil {
return false, xerrors.Errorf("(get miner slashed) failed to load power actor state")
}
+31 -3
View File
@@ -7,11 +7,26 @@ import (
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
)
func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt {
delta := gasLimitUsed/int64(noOfBlocks) - build.BlockGasTarget
// deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget
// change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom
// nextBaseFee = baseFee + change
// nextBaseFee = max(nextBaseFee, build.MinimumBaseFee)
delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum)
delta -= build.BlockGasTarget
// cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta
if delta > build.BlockGasTarget {
delta = build.BlockGasTarget
}
if delta < -build.BlockGasTarget {
delta = -build.BlockGasTarget
}
change := big.Mul(baseFee, big.NewInt(delta))
change = big.Div(change, big.NewInt(build.BlockGasTarget))
@@ -26,17 +41,30 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
zero := abi.NewTokenAmount(0)
// totalLimit is sum of GasLimits of unique messages in a tipset
totalLimit := int64(0)
seen := make(map[cid.Cid]struct{})
for _, b := range ts.Blocks() {
msg1, msg2, err := cs.MessagesForBlock(b)
if err != nil {
return zero, xerrors.Errorf("error getting messages for: %s: %w", b.Cid(), err)
}
for _, m := range msg1 {
totalLimit += m.GasLimit
c := m.Cid()
if _, ok := seen[c]; !ok {
totalLimit += m.GasLimit
seen[c] = struct{}{}
}
}
for _, m := range msg2 {
totalLimit += m.Message.GasLimit
c := m.Cid()
if _, ok := seen[c]; !ok {
totalLimit += m.Message.GasLimit
seen[c] = struct{}{}
}
}
}
parentBaseFee := ts.Blocks()[0].ParentBaseFee
+3 -3
View File
@@ -18,10 +18,10 @@ func TestBaseFee(t *testing.T) {
}{
{100e6, 0, 1, 87.5e6},
{100e6, 0, 5, 87.5e6},
{100e6, build.BlockGasTarget, 1, 100e6},
{100e6, build.BlockGasTarget * 2, 2, 100e6},
{100e6, build.BlockGasTarget, 1, 103.125e6},
{100e6, build.BlockGasTarget * 2, 2, 103.125e6},
{100e6, build.BlockGasLimit * 2, 2, 112.5e6},
{100e6, build.BlockGasLimit * 1.5, 2, 106.25e6},
{100e6, build.BlockGasLimit * 1.5, 2, 110937500},
}
for _, test := range tests {
+9 -4
View File
@@ -1177,15 +1177,20 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer)
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
}
for _, p := range b.Parents {
blocksToWalk = append(blocksToWalk, p)
}
cids, err := recurseLinks(cs.bs, b.Messages, []cid.Cid{b.Messages})
if err != nil {
return xerrors.Errorf("recursing messages failed: %w", err)
}
if b.Height > 0 {
for _, p := range b.Parents {
blocksToWalk = append(blocksToWalk, p)
}
} else {
// include the genesis block
cids = append(cids, b.Parents...)
}
out := cids
if b.Height == 0 {
+100 -21
View File
@@ -195,6 +195,8 @@ func fetchCids(
}
type BlockValidator struct {
self peer.ID
peers *lru.TwoQueueCache
killThresh int
@@ -211,9 +213,10 @@ type BlockValidator struct {
keycache map[string]address.Address
}
func NewBlockValidator(chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
func NewBlockValidator(self peer.ID, chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
p, _ := lru.New2Q(4096)
return &BlockValidator{
self: self,
peers: p,
killThresh: 10,
blacklist: blacklist,
@@ -243,6 +246,10 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
}
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
if pid == bv.self {
return bv.validateLocalBlock(ctx, msg)
}
// track validation time
begin := build.Clock.Now()
defer func() {
@@ -257,25 +264,10 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
bv.flagPeer(pid)
}
// make sure the block can be decoded
blk, err := types.DecodeBlockMsg(msg.GetData())
blk, what, err := bv.decodeAndCheckBlock(msg)
if err != nil {
log.Error("got invalid block over pubsub: ", err)
recordFailure("invalid")
return pubsub.ValidationReject
}
// check the message limit constraints
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
log.Warnf("received block with too many messages over pubsub")
recordFailure("too_many_messages")
return pubsub.ValidationReject
}
// make sure we have a signature
if blk.Header.BlockSig == nil {
log.Warnf("received block without a signature over pubsub")
recordFailure("missing_signature")
recordFailure(what)
return pubsub.ValidationReject
}
@@ -332,6 +324,45 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
return pubsub.ValidationAccept
}
func (bv *BlockValidator) validateLocalBlock(ctx context.Context, msg *pubsub.Message) pubsub.ValidationResult {
stats.Record(ctx, metrics.BlockPublished.M(1))
blk, what, err := bv.decodeAndCheckBlock(msg)
if err != nil {
log.Errorf("got invalid local block: %s", err)
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, what))
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
return pubsub.ValidationIgnore
}
if count := bv.recvBlocks.add(blk.Header.Cid()); count > 0 {
log.Warnf("local block has been seen %d times; ignoring", count)
return pubsub.ValidationIgnore
}
msg.ValidatorData = blk
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
return pubsub.ValidationAccept
}
func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
blk, err := types.DecodeBlockMsg(msg.GetData())
if err != nil {
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
}
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
}
// make sure we have a signature
if blk.Header.BlockSig == nil {
return nil, "missing_signature", fmt.Errorf("block without a signature")
}
return blk, "", nil
}
func (bv *BlockValidator) isChainNearSynced() bool {
ts := bv.chain.GetHeaviestTipSet()
timestamp := ts.MinTimestamp()
@@ -485,14 +516,19 @@ func (brc *blockReceiptCache) add(bcid cid.Cid) int {
}
type MessageValidator struct {
self peer.ID
mpool *messagepool.MessagePool
}
func NewMessageValidator(mp *messagepool.MessagePool) *MessageValidator {
return &MessageValidator{mp}
func NewMessageValidator(self peer.ID, mp *messagepool.MessagePool) *MessageValidator {
return &MessageValidator{self: self, mpool: mp}
}
func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
if pid == mv.self {
return mv.validateLocalMessage(ctx, msg)
}
stats.Record(ctx, metrics.MessageReceived.M(1))
m, err := types.DecodeSignedMessage(msg.Message.GetData())
if err != nil {
@@ -510,7 +546,11 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
)
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
switch {
case xerrors.Is(err, messagepool.ErrBroadcastAnyway) || xerrors.Is(err, messagepool.ErrRBFTooLowPremium):
case xerrors.Is(err, messagepool.ErrBroadcastAnyway):
fallthrough
case xerrors.Is(err, messagepool.ErrRBFTooLowPremium):
fallthrough
case xerrors.Is(err, messagepool.ErrNonceTooLow):
return pubsub.ValidationIgnore
default:
return pubsub.ValidationReject
@@ -520,6 +560,45 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
return pubsub.ValidationAccept
}
func (mv *MessageValidator) validateLocalMessage(ctx context.Context, msg *pubsub.Message) pubsub.ValidationResult {
// do some lightweight validation
stats.Record(ctx, metrics.MessagePublished.M(1))
m, err := types.DecodeSignedMessage(msg.Message.GetData())
if err != nil {
log.Warnf("failed to decode local message: %s", err)
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
return pubsub.ValidationIgnore
}
if m.Size() > 32*1024 {
log.Warnf("local message is too large! (%dB)", m.Size())
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
return pubsub.ValidationIgnore
}
if m.Message.To == address.Undef {
log.Warn("local message has invalid destination address")
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
return pubsub.ValidationIgnore
}
if !m.Message.Value.LessThan(types.TotalFilecoinInt) {
log.Warnf("local messages has too high value: %s", m.Message.Value)
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
return pubsub.ValidationIgnore
}
if err := mv.mpool.VerifyMsgSig(m); err != nil {
log.Warnf("signature verification failed for local message: %s", err)
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
return pubsub.ValidationIgnore
}
stats.Record(ctx, metrics.MessageValidationSuccess.M(1))
return pubsub.ValidationAccept
}
func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool, msub *pubsub.Subscription) {
for {
_, err := msub.Next(ctx)
+1 -1
View File
@@ -24,7 +24,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
+1 -1
View File
@@ -23,7 +23,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/runtime"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
)
func init() {
+214 -24
View File
@@ -3,6 +3,7 @@ package cli
import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"sort"
@@ -10,8 +11,10 @@ import (
"text/tabwriter"
"time"
tm "github.com/buger/goterm"
"github.com/docker/go-units"
"github.com/fatih/color"
datatransfer "github.com/filecoin-project/go-data-transfer"
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-cidutil/cidenc"
@@ -76,6 +79,7 @@ var clientCmd = &cli.Command{
WithCategory("util", clientCommPCmd),
WithCategory("util", clientCarGenCmd),
WithCategory("util", clientInfoCmd),
WithCategory("util", clientListTransfers),
},
}
@@ -311,6 +315,10 @@ var clientDealCmd = &cli.Command{
Usage: "indicate that the deal counts towards verified client total",
Value: false,
},
&cli.StringFlag{
Name: "provider-collateral",
Usage: "specify the requested provider collateral the miner should put up",
},
&CidBaseFlag,
},
Action: func(cctx *cli.Context) error {
@@ -351,6 +359,15 @@ var clientDealCmd = &cli.Command{
return err
}
var provCol big.Int
if pcs := cctx.String("provider-collateral"); pcs != "" {
pc, err := big.FromString(pcs)
if err != nil {
return fmt.Errorf("failed to parse provider-collateral: %w", err)
}
provCol = pc
}
if abi.ChainEpoch(dur) < build.MinDealDuration {
return xerrors.Errorf("minimum deal duration is %d blocks", build.MinDealDuration)
}
@@ -415,14 +432,15 @@ var clientDealCmd = &cli.Command{
}
proposal, err := api.ClientStartDeal(ctx, &lapi.StartDealParams{
Data: ref,
Wallet: a,
Miner: miner,
EpochPrice: types.BigInt(price),
MinBlocksDuration: uint64(dur),
DealStartEpoch: abi.ChainEpoch(cctx.Int64("start-epoch")),
FastRetrieval: cctx.Bool("fast-retrieval"),
VerifiedDeal: isVerified,
Data: ref,
Wallet: a,
Miner: miner,
EpochPrice: types.BigInt(price),
MinBlocksDuration: uint64(dur),
DealStartEpoch: abi.ChainEpoch(cctx.Int64("start-epoch")),
FastRetrieval: cctx.Bool("fast-retrieval"),
VerifiedDeal: isVerified,
ProviderCollateral: provCol,
})
if err != nil {
return err
@@ -536,7 +554,7 @@ func interactiveDeal(cctx *cli.Context) error {
continue
}
a, err := api.ClientQueryAsk(ctx, mi.PeerId, maddr)
a, err := api.ClientQueryAsk(ctx, *mi.PeerId, maddr)
if err != nil {
printErr(xerrors.Errorf("failed to query ask: %w", err))
state = "miner"
@@ -833,28 +851,28 @@ var clientRetrieveCmd = &cli.Command{
Path: cctx.Args().Get(1),
IsCAR: cctx.Bool("car"),
}
updates, err := fapi.ClientRetrieve(ctx, offer.Order(payer), ref)
updates, err := fapi.ClientRetrieveWithEvents(ctx, offer.Order(payer), ref)
if err != nil {
return xerrors.Errorf("error setting up retrieval: %w", err)
}
for {
select {
case evt, chOpen := <-updates:
fmt.Printf("> Recv: %s, Paid %s, %s (%s)\n",
types.SizeStr(types.NewInt(evt.BytesReceived)),
types.FIL(evt.FundsSpent),
retrievalmarket.ClientEvents[evt.Event],
retrievalmarket.DealStatuses[evt.Status],
)
if !chOpen {
case evt, ok := <-updates:
if ok {
fmt.Printf("> Recv: %s, Paid %s, %s (%s)\n",
types.SizeStr(types.NewInt(evt.BytesReceived)),
types.FIL(evt.FundsSpent),
retrievalmarket.ClientEvents[evt.Event],
retrievalmarket.DealStatuses[evt.Status],
)
} else {
fmt.Println("Success")
return nil
}
if evt.Err != "" {
return xerrors.Errorf("retrieval failed: %v", err)
return xerrors.Errorf("retrieval failed: %s", evt.Err)
}
case <-ctx.Done():
return xerrors.Errorf("retrieval timed out")
@@ -912,11 +930,11 @@ var clientQueryAskCmd = &cli.Command{
return xerrors.Errorf("failed to get peerID for miner: %w", err)
}
if peer.ID(mi.PeerId) == peer.ID("SETME") {
if peer.ID(*mi.PeerId) == peer.ID("SETME") {
return fmt.Errorf("the miner hasn't initialized yet")
}
pid = peer.ID(mi.PeerId)
pid = peer.ID(*mi.PeerId)
}
ask, err := api.ClientQueryAsk(ctx, pid, maddr)
@@ -979,6 +997,10 @@ var clientListDeals = &cli.Command{
return err
}
sort.Slice(localDeals, func(i, j int) bool {
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
})
var deals []deal
for _, v := range localDeals {
if v.DealID == 0 {
@@ -1007,7 +1029,7 @@ var clientListDeals = &cli.Command{
if cctx.Bool("verbose") {
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
fmt.Fprintf(w, "DealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
fmt.Fprintf(w, "Created\tDealCid\tDealId\tProvider\tState\tOn Chain?\tSlashed?\tPieceCID\tSize\tPrice\tDuration\tMessage\n")
for _, d := range deals {
onChain := "N"
if d.OnChainDealState.SectorStartEpoch != -1 {
@@ -1020,7 +1042,7 @@ var clientListDeals = &cli.Command{
}
price := types.FIL(types.BigMul(d.LocalDeal.PricePerEpoch, types.NewInt(d.LocalDeal.Duration)))
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%s\n", d.LocalDeal.CreationTime.Format(time.Stamp), d.LocalDeal.ProposalCid, d.LocalDeal.DealID, d.LocalDeal.Provider, dealStateString(color, d.LocalDeal.State), onChain, slashed, d.LocalDeal.PieceCID, types.SizeStr(types.NewInt(d.LocalDeal.Size)), price, d.LocalDeal.Duration, d.LocalDeal.Message)
}
return w.Flush()
} else {
@@ -1189,3 +1211,171 @@ var clientInfoCmd = &cli.Command{
return nil
},
}
var clientListTransfers = &cli.Command{
Name: "list-transfers",
Usage: "List ongoing data transfers for deals",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
Value: true,
},
&cli.BoolFlag{
Name: "completed",
Usage: "show completed data transfers",
},
&cli.BoolFlag{
Name: "watch",
Usage: "watch deal updates in real-time, rather than a one time list",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
channels, err := api.ClientListDataTransfers(ctx)
if err != nil {
return err
}
completed := cctx.Bool("completed")
color := cctx.Bool("color")
watch := cctx.Bool("watch")
if watch {
channelUpdates, err := api.ClientDataTransferUpdates(ctx)
if err != nil {
return err
}
for {
tm.Clear() // Clear current screen
tm.MoveCursor(1, 1)
OutputDataTransferChannels(tm.Screen, channels, completed, color)
tm.Flush()
select {
case <-ctx.Done():
return nil
case channelUpdate := <-channelUpdates:
var found bool
for i, existing := range channels {
if existing.TransferID == channelUpdate.TransferID &&
existing.OtherPeer == channelUpdate.OtherPeer &&
existing.IsSender == channelUpdate.IsSender &&
existing.IsInitiator == channelUpdate.IsInitiator {
channels[i] = channelUpdate
found = true
break
}
}
if !found {
channels = append(channels, channelUpdate)
}
}
}
}
OutputDataTransferChannels(os.Stdout, channels, completed, color)
return nil
},
}
// OutputDataTransferChannels generates table output for a list of channels
func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChannel, completed bool, color bool) {
sort.Slice(channels, func(i, j int) bool {
return channels[i].TransferID < channels[j].TransferID
})
var receivingChannels, sendingChannels []lapi.DataTransferChannel
for _, channel := range channels {
if !completed && channel.Status == datatransfer.Completed {
continue
}
if channel.IsSender {
sendingChannels = append(sendingChannels, channel)
} else {
receivingChannels = append(receivingChannels, channel)
}
}
fmt.Fprintf(out, "Sending Channels\n\n")
w := tablewriter.New(tablewriter.Col("ID"),
tablewriter.Col("Status"),
tablewriter.Col("Sending To"),
tablewriter.Col("Root Cid"),
tablewriter.Col("Initiated?"),
tablewriter.Col("Transferred"),
tablewriter.Col("Voucher"),
tablewriter.NewLineCol("Message"))
for _, channel := range sendingChannels {
w.Write(toChannelOutput(color, "Sending To", channel))
}
w.Flush(out)
fmt.Fprintf(out, "\nReceiving Channels\n\n")
w = tablewriter.New(tablewriter.Col("ID"),
tablewriter.Col("Status"),
tablewriter.Col("Receiving From"),
tablewriter.Col("Root Cid"),
tablewriter.Col("Initiated?"),
tablewriter.Col("Transferred"),
tablewriter.Col("Voucher"),
tablewriter.NewLineCol("Message"))
for _, channel := range receivingChannels {
w.Write(toChannelOutput(color, "Receiving From", channel))
}
w.Flush(out)
}
func channelStatusString(useColor bool, status datatransfer.Status) string {
s := datatransfer.Statuses[status]
if !useColor {
return s
}
switch status {
case datatransfer.Failed, datatransfer.Cancelled:
return color.RedString(s)
case datatransfer.Completed:
return color.GreenString(s)
default:
return s
}
}
func toChannelOutput(useColor bool, otherPartyColumn string, channel lapi.DataTransferChannel) map[string]interface{} {
rootCid := channel.BaseCID.String()
rootCid = "..." + rootCid[len(rootCid)-8:]
otherParty := channel.OtherPeer.String()
otherParty = "..." + otherParty[len(otherParty)-8:]
initiated := "N"
if channel.IsInitiator {
initiated = "Y"
}
voucher := channel.Voucher
if len(voucher) > 40 {
voucher = "..." + voucher[len(voucher)-37:]
}
return map[string]interface{}{
"ID": channel.TransferID,
"Status": channelStatusString(useColor, channel.Status),
otherPartyColumn: otherParty,
"Root Cid": rootCid,
"Initiated?": initiated,
"Transferred": channel.Transferred,
"Voucher": voucher,
"Message": channel.Message,
}
}
+34 -5
View File
@@ -26,7 +26,7 @@ import (
var log = logging.Logger("cli")
const (
metadataTraceConetxt = "traceContext"
metadataTraceContext = "traceContext"
)
// custom CLI error
@@ -67,6 +67,19 @@ func (a APIInfo) AuthHeader() http.Header {
return nil
}
// The flag passed on the command line with the listen address of the API
// server (only used by the tests)
func flagForAPI(t repo.RepoType) string {
switch t {
case repo.FullNode:
return "api"
case repo.StorageMiner:
return "miner-api"
default:
panic(fmt.Sprintf("Unknown repo type: %v", t))
}
}
func flagForRepo(t repo.RepoType) string {
switch t {
case repo.FullNode:
@@ -102,6 +115,20 @@ func envForRepoDeprecation(t repo.RepoType) string {
}
func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
// Check if there was a flag passed with the listen address of the API
// server (only used by the tests)
apiFlag := flagForAPI(t)
if ctx.IsSet(apiFlag) {
strma := ctx.String(apiFlag)
strma = strings.TrimSpace(strma)
apima, err := multiaddr.NewMultiaddr(strma)
if err != nil {
return APIInfo{}, err
}
return APIInfo{Addr: apima}, nil
}
envKey := envForRepo(t)
env, ok := os.LookupEnv(envKey)
if !ok {
@@ -132,7 +159,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
p, err := homedir.Expand(ctx.String(repoFlag))
if err != nil {
return APIInfo{}, xerrors.Errorf("cound not expand home dir (%s): %w", repoFlag, err)
return APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", repoFlag, err)
}
r, err := repo.NewFS(p)
@@ -198,17 +225,17 @@ func GetFullNodeAPI(ctx *cli.Context) (api.FullNode, jsonrpc.ClientCloser, error
return client.NewFullNodeRPC(addr, headers)
}
func GetStorageMinerAPI(ctx *cli.Context) (api.StorageMiner, jsonrpc.ClientCloser, error) {
func GetStorageMinerAPI(ctx *cli.Context, opts ...jsonrpc.Option) (api.StorageMiner, jsonrpc.ClientCloser, error) {
addr, headers, err := GetRawAPI(ctx, repo.StorageMiner)
if err != nil {
return nil, nil, err
}
return client.NewStorageMinerRPC(addr, headers)
return client.NewStorageMinerRPC(addr, headers, opts...)
}
func DaemonContext(cctx *cli.Context) context.Context {
if mtCtx, ok := cctx.App.Metadata[metadataTraceConetxt]; ok {
if mtCtx, ok := cctx.App.Metadata[metadataTraceContext]; ok {
return mtCtx.(context.Context)
}
@@ -238,6 +265,7 @@ var CommonCommands = []*cli.Command{
logCmd,
waitApiCmd,
fetchParamCmd,
pprofCmd,
VersionCmd,
}
@@ -256,6 +284,7 @@ var Commands = []*cli.Command{
WithCategory("developer", fetchParamCmd),
WithCategory("network", netCmd),
WithCategory("network", syncCmd),
pprofCmd,
VersionCmd,
}
+79
View File
@@ -20,10 +20,12 @@ var mpoolCmd = &cli.Command{
Usage: "Manage message pool",
Subcommands: []*cli.Command{
mpoolPending,
mpoolClear,
mpoolSub,
mpoolStat,
mpoolReplaceCmd,
mpoolFindCmd,
mpoolConfig,
},
}
@@ -82,6 +84,38 @@ var mpoolPending = &cli.Command{
},
}
var mpoolClear = &cli.Command{
Name: "clear",
Usage: "Clear all pending messages from the mpool (USE WITH CARE)",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "local",
Usage: "also clear local messages",
},
&cli.BoolFlag{
Name: "really-do-it",
Usage: "must be specified for the action to take effect",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
really := cctx.Bool("really-do-it")
if !really {
return fmt.Errorf("--really-do-it must be specified for this action to have an effect; you have been warned.")
}
local := cctx.Bool("local")
ctx := ReqContext(cctx)
return api.MpoolClear(ctx, local)
},
}
var mpoolSub = &cli.Command{
Name: "sub",
Usage: "Subscribe to mpool changes",
@@ -415,3 +449,48 @@ var mpoolFindCmd = &cli.Command{
return nil
},
}
var mpoolConfig = &cli.Command{
Name: "config",
Usage: "get or set current mpool configuration",
ArgsUsage: "[new-config]",
Action: func(cctx *cli.Context) error {
if cctx.Args().Len() > 1 {
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
if cctx.Args().Len() == 0 {
cfg, err := api.MpoolGetConfig(ctx)
if err != nil {
return err
}
bytes, err := json.Marshal(cfg)
if err != nil {
return err
}
fmt.Println(string(bytes))
} else {
cfg := new(types.MpoolConfig)
bytes := []byte(cctx.Args().Get(0))
err := json.Unmarshal(bytes, cfg)
if err != nil {
return err
}
return api.MpoolSetConfig(ctx, cfg)
}
return nil
},
}
+12 -2
View File
@@ -12,6 +12,7 @@ import (
"text/tabwriter"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/go-address"
@@ -231,10 +232,10 @@ var msigInspectCmd = &cli.Command{
})
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
fmt.Fprintf(w, "ID\tState\tTo\tValue\tMethod\tParams\n")
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%s\t%s\t%d\t%x\n", txid, state(tx), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%d\t%x\n", txid, state(tx), len(tx.Approved), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
}
if err := w.Flush(); err != nil {
return xerrors.Errorf("flushing output: %+v", err)
@@ -355,6 +356,15 @@ var msigProposeCmd = &cli.Command{
from = defaddr
}
act, err := api.StateGetActor(ctx, msig, types.EmptyTSK)
if err != nil {
return fmt.Errorf("failed to look up multisig %s: %w", msig, err)
}
if act.Code != builtin.MultisigActorCodeID {
return fmt.Errorf("actor %s is not a multisig actor", msig)
}
msgCid, err := api.MsigPropose(ctx, msig, dest, types.BigInt(value), from, method, params)
if err != nil {
return err
+2 -2
View File
@@ -222,8 +222,8 @@ var NetReachability = &cli.Command{
}
fmt.Println("AutoNAT status: ", i.Reachability.String())
if i.PublicAddr != nil {
fmt.Println("Public address: ", i.PublicAddr.String())
if i.PublicAddr != "" {
fmt.Println("Public address: ", i.PublicAddr)
}
return nil
},
+12 -13
View File
@@ -5,9 +5,8 @@ import (
"encoding/base64"
"fmt"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/urfave/cli/v2"
@@ -71,7 +70,7 @@ var paychGetCmd = &cli.Command{
return err
}
fmt.Println(chAddr)
fmt.Fprintln(cctx.App.Writer, chAddr)
return nil
},
}
@@ -94,7 +93,7 @@ var paychListCmd = &cli.Command{
}
for _, v := range chs {
fmt.Println(v.String())
fmt.Fprintln(cctx.App.Writer, v.String())
}
return nil
},
@@ -135,7 +134,7 @@ var paychSettleCmd = &cli.Command{
return fmt.Errorf("settle message execution failed (exit code %d)", mwait.Receipt.ExitCode)
}
fmt.Printf("Settled channel %s\n", ch)
fmt.Fprintf(cctx.App.Writer, "Settled channel %s\n", ch)
return nil
},
}
@@ -175,7 +174,7 @@ var paychCloseCmd = &cli.Command{
return fmt.Errorf("collect message execution failed (exit code %d)", mwait.Receipt.ExitCode)
}
fmt.Printf("Collected funds for channel %s\n", ch)
fmt.Fprintf(cctx.App.Writer, "Collected funds for channel %s\n", ch)
return nil
},
}
@@ -239,7 +238,7 @@ var paychVoucherCreateCmd = &cli.Command{
return err
}
fmt.Println(enc)
fmt.Fprintln(cctx.App.Writer, enc)
return nil
},
}
@@ -275,7 +274,7 @@ var paychVoucherCheckCmd = &cli.Command{
return err
}
fmt.Println("voucher is valid")
fmt.Fprintln(cctx.App.Writer, "voucher is valid")
return nil
},
}
@@ -356,9 +355,9 @@ var paychVoucherListCmd = &cli.Command{
return err
}
fmt.Printf("Lane %d, Nonce %d: %s; %s\n", v.Lane, v.Nonce, v.Amount.String(), enc)
fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s; %s\n", v.Lane, v.Nonce, v.Amount.String(), enc)
} else {
fmt.Printf("Lane %d, Nonce %d: %s\n", v.Lane, v.Nonce, v.Amount.String())
fmt.Fprintf(cctx.App.Writer, "Lane %d, Nonce %d: %s\n", v.Lane, v.Nonce, v.Amount.String())
}
}
@@ -415,8 +414,8 @@ var paychVoucherBestSpendableCmd = &cli.Command{
return err
}
fmt.Println(enc)
fmt.Printf("Amount: %s\n", best.Amount)
fmt.Fprintln(cctx.App.Writer, enc)
fmt.Fprintf(cctx.App.Writer, "Amount: %s\n", best.Amount)
return nil
},
}
@@ -462,7 +461,7 @@ var paychVoucherSubmitCmd = &cli.Command{
return fmt.Errorf("message execution failed (exit code %d)", mwait.Receipt.ExitCode)
}
fmt.Println("channel updated successfully")
fmt.Fprintln(cctx.App.Writer, "channel updated successfully")
return nil
},
+228
View File
@@ -0,0 +1,228 @@
package cli
import (
"bytes"
"context"
"flag"
"os"
"strconv"
"strings"
"testing"
"time"
"github.com/filecoin-project/specs-actors/actors/abi/big"
saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/multiformats/go-multiaddr"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/api/test"
"github.com/filecoin-project/lotus/chain/wallet"
builder "github.com/filecoin-project/lotus/node/test"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
)
func init() {
power.ConsensusMinerMinPower = big.NewInt(2048)
saminer.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
}
verifreg.MinVerifiedDealSize = big.NewInt(256)
}
// TestPaymentChannels does a basic test to exercise the payment channel CLI
// commands
func TestPaymentChannels(t *testing.T) {
_ = os.Setenv("BELLMAN_NO_GPU", "1")
blocktime := 5 * time.Millisecond
ctx := context.Background()
n, sn := builder.RPCMockSbBuilder(t, 2, test.OneMiner)
paymentCreator := n[0]
paymentReceiver := n[1]
miner := sn[0]
// Get everyone connected
addrs, err := paymentCreator.NetAddrsListen(ctx)
if err != nil {
t.Fatal(err)
}
if err := paymentReceiver.NetConnect(ctx, addrs); 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()
// Send some funds to register the receiver
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
if err != nil {
t.Fatal(err)
}
test.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
// Get the creator's address
creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx)
if err != nil {
t.Fatal(err)
}
// Create mock CLI
mockCLI := newMockCLI(t)
creatorCLI := mockCLI.client(paymentCreator.ListenAddr)
receiverCLI := mockCLI.client(paymentReceiver.ListenAddr)
// creator: paych get <creator> <receiver> <amount>
channelAmt := "100000"
cmd := []string{creatorAddr.String(), receiverAddr.String(), channelAmt}
chstr := creatorCLI.runCmd(paychGetCmd, cmd)
chAddr, err := address.NewFromString(chstr)
require.NoError(t, err)
// creator: paych voucher create <channel> <amount>
voucherAmt := 100
vamt := strconv.Itoa(voucherAmt)
cmd = []string{chAddr.String(), vamt}
voucher := creatorCLI.runCmd(paychVoucherCreateCmd, cmd)
// receiver: paych voucher add <channel> <voucher>
cmd = []string{chAddr.String(), voucher}
receiverCLI.runCmd(paychVoucherAddCmd, cmd)
// creator: paych settle <channel>
cmd = []string{chAddr.String()}
creatorCLI.runCmd(paychSettleCmd, cmd)
// Wait for the chain to reach the settle height
chState := getPaychState(ctx, t, paymentReceiver, chAddr)
waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt)
// receiver: paych collect <channel>
cmd = []string{chAddr.String()}
receiverCLI.runCmd(paychCloseCmd, cmd)
}
type mockCLI struct {
t *testing.T
cctx *cli.Context
out *bytes.Buffer
}
func newMockCLI(t *testing.T) *mockCLI {
// Create a CLI App with an --api flag so that we can specify which node
// the command should be executed against
app := cli.NewApp()
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "api",
Hidden: true,
},
}
var out bytes.Buffer
app.Writer = &out
app.Setup()
cctx := cli.NewContext(app, &flag.FlagSet{}, nil)
return &mockCLI{t: t, cctx: cctx, out: &out}
}
func (c *mockCLI) client(addr multiaddr.Multiaddr) *mockCLIClient {
return &mockCLIClient{t: c.t, addr: addr, cctx: c.cctx, out: c.out}
}
// mockCLIClient runs commands against a particular node
type mockCLIClient struct {
t *testing.T
addr multiaddr.Multiaddr
cctx *cli.Context
out *bytes.Buffer
}
func (c *mockCLIClient) runCmd(cmd *cli.Command, input []string) string {
// prepend --api=<node api listener address>
apiFlag := "--api=" + c.addr.String()
input = append([]string{apiFlag}, input...)
fs := c.flagSet(cmd)
err := fs.Parse(input)
require.NoError(c.t, err)
err = cmd.Action(cli.NewContext(c.cctx.App, fs, c.cctx))
require.NoError(c.t, err)
// Get the output
str := strings.TrimSpace(c.out.String())
c.out.Reset()
return str
}
func (c *mockCLIClient) flagSet(cmd *cli.Command) *flag.FlagSet {
// Apply app level flags (so we can process --api 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
}
// waitForHeight waits for the node to reach the given chain epoch
func waitForHeight(ctx context.Context, t *testing.T, node test.TestNode, height abi.ChainEpoch) {
atHeight := make(chan struct{})
chainEvents := events.NewEvents(ctx, node)
err := chainEvents.ChainAt(func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error {
close(atHeight)
return nil
}, nil, 1, height)
if err != nil {
t.Fatal(err)
}
select {
case <-atHeight:
case <-ctx.Done():
}
}
// getPaychState gets the state of the payment channel with the given address
func getPaychState(ctx context.Context, t *testing.T, node test.TestNode, chAddr address.Address) paych.State {
act, err := node.StateGetActor(ctx, chAddr, types.EmptyTSK)
require.NoError(t, err)
store := cbor.NewCborStore(apibstore.NewAPIBlockstore(node))
var chState paych.State
err = store.Get(ctx, act.Head, &chState)
require.NoError(t, err)
return chState
}
+58
View File
@@ -0,0 +1,58 @@
package cli
import (
"io"
"net/http"
"os"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/node/repo"
manet "github.com/multiformats/go-multiaddr-net"
)
var pprofCmd = &cli.Command{
Name: "pprof",
Hidden: true,
Subcommands: []*cli.Command{
PprofGoroutines,
},
}
var PprofGoroutines = &cli.Command{
Name: "goroutines",
Usage: "Get goroutine stacks",
Action: func(cctx *cli.Context) error {
ti, ok := cctx.App.Metadata["repoType"]
if !ok {
log.Errorf("unknown repo type, are you sure you want to use GetAPI?")
ti = repo.FullNode
}
t, ok := ti.(repo.RepoType)
if !ok {
log.Errorf("repoType type does not match the type of repo.RepoType")
}
ainfo, err := GetAPIInfo(cctx, t)
if err != nil {
return xerrors.Errorf("could not get API info: %w", err)
}
_, addr, err := manet.DialArgs(ainfo.Addr)
if err != nil {
return err
}
addr = "http://" + addr + "/debug/pprof/goroutine?debug=2"
r, err := http.Get(addr)
if err != nil {
return err
}
if _, err := io.Copy(os.Stdout, r.Body); err != nil {
return err
}
return r.Body.Close()
},
}
+73 -2
View File
@@ -67,6 +67,7 @@ var stateCmd = &cli.Command{
stateWaitMsgCmd,
stateSearchMsgCmd,
stateMinerInfo,
stateMarketCmd,
},
}
@@ -104,6 +105,9 @@ var stateMinerInfo = &cli.Command{
fmt.Printf("Owner:\t%s\n", mi.Owner)
fmt.Printf("Worker:\t%s\n", mi.Worker)
for i, controlAddress := range mi.ControlAddresses {
fmt.Printf("Control %d: \t%s\n", i, controlAddress)
}
fmt.Printf("PeerID:\t%s\n", mi.PeerId)
fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize)
fmt.Printf("Multiaddrs: \t")
@@ -561,10 +565,30 @@ var stateGetActorCmd = &cli.Command{
return err
}
var strtype string
switch a.Code {
case builtin.AccountActorCodeID:
strtype = "account"
case builtin.MultisigActorCodeID:
strtype = "multisig"
case builtin.CronActorCodeID:
strtype = "cron"
case builtin.InitActorCodeID:
strtype = "init"
case builtin.StorageMinerActorCodeID:
strtype = "miner"
case builtin.StorageMarketActorCodeID:
strtype = "market"
case builtin.StoragePowerActorCodeID:
strtype = "power"
default:
strtype = "unknown"
}
fmt.Printf("Address:\t%s\n", addr)
fmt.Printf("Balance:\t%s\n", types.FIL(a.Balance))
fmt.Printf("Nonce:\t\t%d\n", a.Nonce)
fmt.Printf("Code:\t\t%s\n", a.Code)
fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype)
fmt.Printf("Head:\t\t%s\n", a.Head)
return nil
@@ -1515,7 +1539,54 @@ var stateCircSupplyCmd = &cli.Command{
return err
}
fmt.Println(types.FIL(circ))
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))
return nil
},
}
var stateMarketCmd = &cli.Command{
Name: "market",
Usage: "Inspect the storage market actor",
Subcommands: []*cli.Command{
stateMarketBalanceCmd,
},
}
var stateMarketBalanceCmd = &cli.Command{
Name: "balance",
Usage: "Get the market balance (locked and escrowed) for a given account",
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return ShowHelp(cctx, fmt.Errorf("must specify address to print market balance for"))
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := ReqContext(cctx)
ts, err := LoadTipSet(ctx, cctx, api)
if err != nil {
return err
}
addr, err := address.NewFromString(cctx.Args().First())
if err != nil {
return err
}
balance, err := api.StateMarketBalance(ctx, addr, ts.Key())
fmt.Printf("Escrow: %s\n", types.FIL(balance.Escrow))
fmt.Printf("Locked: %s\n", types.FIL(balance.Locked))
return nil
},
+1 -1
View File
@@ -25,7 +25,7 @@ import (
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/ipfs/go-datastore"
+3 -3
View File
@@ -21,9 +21,9 @@ import (
"github.com/filecoin-project/go-address"
paramfetch "github.com/filecoin-project/go-paramfetch"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-storage/storage"
+1 -1
View File
@@ -14,7 +14,7 @@ func main() {
if err := logging.SetLogLevel("*", "info"); err != nil {
log.Fatal(err)
}
log.Info("Starting chainwatch")
log.Info("Starting chainwatch", " v", build.UserVersion())
app := &cli.App{
Name: "lotus-chainwatch",
+55 -49
View File
@@ -1,18 +1,22 @@
package processor
import (
"bytes"
"context"
"fmt"
"time"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/types"
cw_util "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/util"
"github.com/filecoin-project/specs-actors/actors/builtin"
_init "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid"
typegen "github.com/whyrusleeping/cbor-gen"
)
func (p *Processor) setupCommonActors() error {
@@ -141,49 +145,41 @@ func (p Processor) storeActorAddresses(ctx context.Context, actors map[cid.Cid]A
addressToID[builtin.StorageMarketActorAddr] = builtin.StorageMarketActorAddr
addressToID[builtin.VerifiedRegistryActorAddr] = builtin.VerifiedRegistryActorAddr
addressToID[builtin.BurntFundsActorAddr] = builtin.BurntFundsActorAddr
addressesToUpdate := []UpdateAddresses{}
pred := state.NewStatePredicates(p.node)
for _, act := range actors[builtin.InitActorCodeID] {
for _, info := range act {
changed, val, err := pred.OnInitActorChange(pred.OnAddressMapChange())(ctx, info.parentTsKey, info.tsKey)
if err != nil {
return err
}
if !changed {
continue
}
changes := val.(*state.InitActorAddressChanges)
for _, add := range changes.Added {
addressToID[add.PK] = add.ID
}
// we'll need to update any addresses that were modified, this indicates a reorg.
for _, mod := range changes.Modified {
addressesToUpdate = append(addressesToUpdate, UpdateAddresses{
Old: mod.From,
New: mod.To,
})
}
}
}
updateTx, err := p.db.Begin()
initActor, err := p.node.StateGetActor(ctx, builtin.InitActorAddr, types.EmptyTSK)
if err != nil {
return err
}
for _, updates := range addressesToUpdate {
if _, err := updateTx.Exec(
fmt.Sprintf("update id_address_map set id=%s, address=%s where id=%s and address=%s", updates.New.ID, updates.New.PK, updates.Old.ID, updates.Old.PK),
); err != nil {
return err
}
}
if err := updateTx.Commit(); err != nil {
initActorRaw, err := p.node.ChainReadObj(ctx, initActor.Head)
if err != nil {
return err
}
var initActorState _init.State
if err := initActorState.UnmarshalCBOR(bytes.NewReader(initActorRaw)); err != nil {
return err
}
ctxStore := cw_util.NewAPIIpldStore(ctx, p.node)
addrMap, err := adt.AsMap(ctxStore, initActorState.AddressMap)
if err != nil {
return err
}
// gross..
var actorID typegen.CborInt
if err := addrMap.ForEach(&actorID, func(key string) error {
longAddr, err := address.NewFromBytes([]byte(key))
if err != nil {
return err
}
shortAddr, err := address.NewIDAddress(uint64(actorID))
if err != nil {
return err
}
addressToID[longAddr] = shortAddr
return nil
}); err != nil {
return err
}
tx, err := p.db.Begin()
if err != nil {
return err
@@ -215,8 +211,10 @@ create temp table iam (like id_address_map excluding constraints) on commit drop
return err
}
if _, err := tx.Exec(`insert into id_address_map select * from iam on conflict (id) do nothing`); err != nil {
return xerrors.Errorf("actor put: %w", err)
// HACK until chain watch can handle reorgs we need to update this table when ID -> PubKey mappings change
if _, err := tx.Exec(`insert into id_address_map select * from iam on conflict (id) do update set address = EXCLUDED.address`); err != nil {
log.Warnw("Failed to update id_address_map table, this is a known issue")
return nil
}
return tx.Commit()
@@ -233,20 +231,24 @@ func (p *Processor) storeActorHeads(actors map[cid.Cid]ActorTips) error {
return err
}
if _, err := tx.Exec(`
create temp table a (like actors excluding constraints) on commit drop;
create temp table a_tmp (like actors excluding constraints) on commit drop;
`); err != nil {
return xerrors.Errorf("prep temp: %w", err)
}
stmt, err := tx.Prepare(`copy a (id, code, head, nonce, balance, stateroot) from stdin `)
stmt, err := tx.Prepare(`copy a_tmp (id, code, head, nonce, balance, stateroot) from stdin `)
if err != nil {
return err
}
for code, actTips := range actors {
actorName := code.String()
if builtin.IsBuiltinActor(code) {
actorName = builtin.ActorNameByCode(code)
}
for _, actorInfo := range actTips {
for _, a := range actorInfo {
if _, err := stmt.Exec(a.addr.String(), code.String(), a.act.Head.String(), a.act.Nonce, a.act.Balance.String(), a.stateroot.String()); err != nil {
if _, err := stmt.Exec(a.addr.String(), actorName, a.act.Head.String(), a.act.Nonce, a.act.Balance.String(), a.stateroot.String()); err != nil {
return err
}
}
@@ -257,7 +259,7 @@ func (p *Processor) storeActorHeads(actors map[cid.Cid]ActorTips) error {
return err
}
if _, err := tx.Exec(`insert into actors select * from a on conflict do nothing `); err != nil {
if _, err := tx.Exec(`insert into actors select * from a_tmp on conflict do nothing `); err != nil {
return xerrors.Errorf("actor put: %w", err)
}
@@ -275,20 +277,24 @@ func (p *Processor) storeActorStates(actors map[cid.Cid]ActorTips) error {
return err
}
if _, err := tx.Exec(`
create temp table a (like actor_states excluding constraints) on commit drop;
create temp table as_tmp (like actor_states excluding constraints) on commit drop;
`); err != nil {
return xerrors.Errorf("prep temp: %w", err)
}
stmt, err := tx.Prepare(`copy a (head, code, state) from stdin `)
stmt, err := tx.Prepare(`copy as_tmp (head, code, state) from stdin `)
if err != nil {
return err
}
for code, actTips := range actors {
actorName := code.String()
if builtin.IsBuiltinActor(code) {
actorName = builtin.ActorNameByCode(code)
}
for _, actorInfo := range actTips {
for _, a := range actorInfo {
if _, err := stmt.Exec(a.act.Head.String(), code.String(), a.state); err != nil {
if _, err := stmt.Exec(a.act.Head.String(), actorName, a.state); err != nil {
return err
}
}
@@ -299,7 +305,7 @@ func (p *Processor) storeActorStates(actors map[cid.Cid]ActorTips) error {
return err
}
if _, err := tx.Exec(`insert into actor_states select * from a on conflict do nothing `); err != nil {
if _, err := tx.Exec(`insert into actor_states select * from as_tmp on conflict do nothing `); err != nil {
return xerrors.Errorf("actor put: %w", err)
}
+15 -6
View File
@@ -88,6 +88,8 @@ create table if not exists sector_info
verified_deal_weight text not null,
initial_pledge text not null,
expected_day_reward text not null,
expected_storage_pledge text not null,
constraint sector_info_pk
primary key (miner_id, sector_id, sealed_cid)
@@ -307,6 +309,7 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA
}
stmt, err := tx.Prepare(`copy spi (miner_id, sector_id, sealed_cid, state_root, seal_rand_epoch, expiration_epoch, precommit_deposit, precommit_epoch, deal_weight, verified_deal_weight, is_replace_capacity, replace_sector_deadline, replace_sector_partition, replace_sector_number) from STDIN`)
if err != nil {
return xerrors.Errorf("Failed to prepare miner precommit info statement: %w", err)
}
@@ -319,7 +322,7 @@ func (p *Processor) storeMinerPreCommitInfo(ctx context.Context, miners []minerA
changes, err := p.getMinerPreCommitChanges(ctx, m)
if err != nil {
if strings.Contains(err.Error(), "address not found") {
if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
continue
} else {
return err
@@ -431,7 +434,7 @@ func (p *Processor) storeMinerSectorInfo(ctx context.Context, miners []minerActo
return xerrors.Errorf("Failed to create temp table for sector_: %w", err)
}
stmt, err := tx.Prepare(`copy si (miner_id, sector_id, sealed_cid, state_root, activation_epoch, expiration_epoch, deal_weight, verified_deal_weight, initial_pledge) from STDIN`)
stmt, err := tx.Prepare(`copy si (miner_id, sector_id, sealed_cid, state_root, activation_epoch, expiration_epoch, deal_weight, verified_deal_weight, initial_pledge, expected_day_reward, expected_storage_pledge) from STDIN`)
if err != nil {
return xerrors.Errorf("Failed to prepare miner sector info statement: %w", err)
}
@@ -439,7 +442,7 @@ func (p *Processor) storeMinerSectorInfo(ctx context.Context, miners []minerActo
for _, m := range miners {
changes, err := p.getMinerSectorChanges(ctx, m)
if err != nil {
if strings.Contains(err.Error(), "address not found") {
if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
continue
} else {
return err
@@ -463,6 +466,8 @@ func (p *Processor) storeMinerSectorInfo(ctx context.Context, miners []minerActo
added.DealWeight.String(),
added.VerifiedDealWeight.String(),
added.InitialPledge.String(),
added.ExpectedDayReward.String(),
added.ExpectedStoragePledge.String(),
); err != nil {
return err
}
@@ -518,7 +523,7 @@ func (p *Processor) getMinerPartitionsDifferences(ctx context.Context, miners []
m := m
grp.Go(func() error {
if err := p.diffMinerPartitions(ctx, m, events); err != nil {
if strings.Contains(err.Error(), "address not found") {
if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
return nil
}
return err
@@ -873,17 +878,21 @@ func (p *Processor) storeMinersActorInfoState(ctx context.Context, miners []mine
for _, m := range miners {
mi, err := p.node.StateMinerInfo(ctx, m.common.addr, m.common.tsKey)
if err != nil {
if strings.Contains(err.Error(), "address not found") {
if strings.Contains(err.Error(), types.ErrActorNotFound.Error()) {
continue
} else {
return err
}
}
var pid string
if mi.PeerId != nil {
pid = mi.PeerId.String()
}
if _, err := stmt.Exec(
m.common.addr.String(),
mi.Owner.String(),
mi.Worker.String(),
mi.PeerId.String(),
pid,
mi.SectorSize.ShortString(),
); err != nil {
log.Errorw("failed to store miner state", "state", m.state, "info", m.state.Info, "error", err)
+1 -2
View File
@@ -30,11 +30,10 @@ func (p *Processor) subMpool(ctx context.Context) {
loop:
for {
time.Sleep(10 * time.Millisecond)
select {
case update := <-sub:
updates = append(updates, update)
default:
case <-time.After(10 * time.Millisecond):
break loop
}
}
+135
View File
@@ -0,0 +1,135 @@
package processor
import (
"bytes"
"context"
"time"
"golang.org/x/xerrors"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
)
type powerActorInfo struct {
common actorInfo
epochSmoothingEstimate *smoothing.FilterEstimate
}
func (p *Processor) setupPower() error {
tx, err := p.db.Begin()
if err != nil {
return err
}
if _, err := tx.Exec(`
create table if not exists power_smoothing_estimates
(
state_root text not null
constraint power_smoothing_estimates_pk
primary key,
position_estimate text not null,
velocity_estimate text not null
);
`); err != nil {
return err
}
return tx.Commit()
}
func (p *Processor) HandlePowerChanges(ctx context.Context, powerTips ActorTips) error {
powerChanges, err := p.processPowerActors(ctx, powerTips)
if err != nil {
return xerrors.Errorf("Failed to process power actors: %w", err)
}
if err := p.persistPowerActors(ctx, powerChanges); err != nil {
return err
}
return nil
}
func (p *Processor) processPowerActors(ctx context.Context, powerTips ActorTips) ([]powerActorInfo, error) {
start := time.Now()
defer func() {
log.Debugw("Processed Power Actors", "duration", time.Since(start).String())
}()
var out []powerActorInfo
for tipset, powers := range powerTips {
for _, act := range powers {
var pw powerActorInfo
pw.common = act
powerActor, err := p.node.StateGetActor(ctx, builtin.StoragePowerActorAddr, tipset)
if err != nil {
return nil, xerrors.Errorf("get power state (@ %s): %w", pw.common.stateroot.String(), err)
}
powerStateRaw, err := p.node.ChainReadObj(ctx, powerActor.Head)
if err != nil {
return nil, xerrors.Errorf("read state obj (@ %s): %w", pw.common.stateroot.String(), err)
}
var powerActorState power.State
if err := powerActorState.UnmarshalCBOR(bytes.NewReader(powerStateRaw)); err != nil {
return nil, xerrors.Errorf("unmarshal state (@ %s): %w", pw.common.stateroot.String(), err)
}
pw.epochSmoothingEstimate = powerActorState.ThisEpochQAPowerSmoothed
out = append(out, pw)
}
}
return out, nil
}
func (p *Processor) persistPowerActors(ctx context.Context, powers []powerActorInfo) error {
// NB: use errgroup when there is more than a single store operation
return p.storePowerSmoothingEstimates(powers)
}
func (p *Processor) storePowerSmoothingEstimates(powers []powerActorInfo) error {
tx, err := p.db.Begin()
if err != nil {
return xerrors.Errorf("begin power_smoothing_estimates tx: %w", err)
}
if _, err := tx.Exec(`create temp table rse (like power_smoothing_estimates) on commit drop`); err != nil {
return xerrors.Errorf("prep power_smoothing_estimates: %w", err)
}
stmt, err := tx.Prepare(`copy rse (state_root, position_estimate, velocity_estimate) from stdin;`)
if err != nil {
return xerrors.Errorf("prepare tmp power_smoothing_estimates: %w", err)
}
for _, powerState := range powers {
if _, err := stmt.Exec(
powerState.common.stateroot.String(),
powerState.epochSmoothingEstimate.PositionEstimate.String(),
powerState.epochSmoothingEstimate.VelocityEstimate.String(),
); err != nil {
return xerrors.Errorf("failed to store smoothing estimate: %w", err)
}
}
if err := stmt.Close(); err != nil {
return xerrors.Errorf("close prepared power_smoothing_estimates: %w", err)
}
if _, err := tx.Exec(`insert into power_smoothing_estimates select * from rse on conflict do nothing`); err != nil {
return xerrors.Errorf("insert power_smoothing_estimates from tmp: %w", err)
}
if err := tx.Commit(); err != nil {
return xerrors.Errorf("commit power_smoothing_estimates tx: %w", err)
}
return nil
}
+18 -3
View File
@@ -88,6 +88,10 @@ func (p *Processor) setupSchemas() error {
return err
}
if err := p.setupPower(); err != nil {
return err
}
return nil
}
@@ -166,6 +170,14 @@ func (p *Processor) Start(ctx context.Context) {
return nil
})
grp.Go(func() error {
if err := p.HandlePowerChanges(ctx, actorChanges[builtin.StoragePowerActorCodeID]); err != nil {
return xerrors.Errorf("Failed to handle power actor changes: %w", err)
}
log.Info("Processes Power Changes")
return nil
})
grp.Go(func() error {
if err := p.HandleMessageChanges(ctx, toProcess); err != nil {
return xerrors.Errorf("Failed to handle message changes: %w", err)
@@ -336,16 +348,19 @@ where rnk <= $1
}
var c string
if err := rows.Scan(&c); err != nil {
return nil, xerrors.Errorf("Failed to scan unprocessed blocks: %w", err)
log.Errorf("Failed to scan unprocessed blocks: %s", err.Error())
continue
}
ci, err := cid.Parse(c)
if err != nil {
return nil, xerrors.Errorf("Failed to parse unprocessed blocks: %w", err)
log.Errorf("Failed to parse unprocessed blocks: %s", err.Error())
continue
}
bh, err := p.node.ChainGetBlock(ctx, ci)
if err != nil {
// this is a pretty serious issue.
return nil, xerrors.Errorf("Failed to get block header %s: %w", ci.String(), err)
log.Errorf("Failed to get block header %s: %s", ci.String(), err.Error())
continue
}
out[ci] = bh
if bh.Height < minBlock {
+64 -1
View File
@@ -11,6 +11,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
@@ -24,6 +25,8 @@ type rewardActorInfo struct {
// base reward in attofil for each block found during this epoch
baseBlockReward big.Int
epochSmoothingEstimate *smoothing.FilterEstimate
}
func (p *Processor) setupRewards() error {
@@ -53,6 +56,15 @@ create table if not exists chain_power
primary key,
baseline_power text not null
);
create table if not exists reward_smoothing_estimates
(
state_root text not null
constraint reward_smoothing_estimates_pk
primary key,
position_estimate text not null,
velocity_estimate text not null
);
`); err != nil {
return err
}
@@ -63,7 +75,7 @@ create table if not exists chain_power
func (p *Processor) HandleRewardChanges(ctx context.Context, rewardTips ActorTips, nullRounds []types.TipSetKey) error {
rewardChanges, err := p.processRewardActors(ctx, rewardTips, nullRounds)
if err != nil {
log.Fatalw("Failed to process reward actors", "error", err)
return xerrors.Errorf("Failed to process reward actors: %w", err)
}
if err := p.persistRewardActors(ctx, rewardChanges); err != nil {
@@ -103,6 +115,7 @@ func (p *Processor) processRewardActors(ctx context.Context, rewardTips ActorTip
rw.baseBlockReward = rewardActorState.ThisEpochReward
rw.baselinePower = rewardActorState.ThisEpochBaselinePower
rw.epochSmoothingEstimate = rewardActorState.ThisEpochRewardSmoothed
out = append(out, rw)
}
}
@@ -162,6 +175,13 @@ func (p *Processor) persistRewardActors(ctx context.Context, rewards []rewardAct
return nil
})
grp.Go(func() error {
if err := p.storeRewardSmoothingEstimates(rewards); err != nil {
return err
}
return nil
})
return grp.Wait()
}
@@ -243,3 +263,46 @@ func (p *Processor) storeBaseBlockReward(rewards []rewardActorInfo) error {
return nil
}
func (p *Processor) storeRewardSmoothingEstimates(rewards []rewardActorInfo) error {
tx, err := p.db.Begin()
if err != nil {
return xerrors.Errorf("begin reward_smoothing_estimates tx: %w", err)
}
if _, err := tx.Exec(`create temp table rse (like reward_smoothing_estimates) on commit drop`); err != nil {
return xerrors.Errorf("prep reward_smoothing_estimates: %w", err)
}
stmt, err := tx.Prepare(`copy rse (state_root, position_estimate, velocity_estimate) from stdin;`)
if err != nil {
return xerrors.Errorf("prepare tmp reward_smoothing_estimates: %w", err)
}
for _, rewardState := range rewards {
if rewardState.epochSmoothingEstimate == nil {
continue
}
if _, err := stmt.Exec(
rewardState.common.stateroot.String(),
rewardState.epochSmoothingEstimate.PositionEstimate.String(),
rewardState.epochSmoothingEstimate.VelocityEstimate.String(),
); err != nil {
return xerrors.Errorf("failed to store smoothing estimate: %w", err)
}
}
if err := stmt.Close(); err != nil {
return xerrors.Errorf("close prepared reward_smoothing_estimates: %w", err)
}
if _, err := tx.Exec(`insert into reward_smoothing_estimates select * from rse on conflict do nothing`); err != nil {
return xerrors.Errorf("insert reward_smoothing_estimates from tmp: %w", err)
}
if err := tx.Commit(); err != nil {
return xerrors.Errorf("commit reward_smoothing_estimates tx: %w", err)
}
return nil
}
+13 -4
View File
@@ -46,7 +46,11 @@ create table if not exists chain_economics
(
parent_state_root text not null
constraint chain_economics_pk primary key,
circulating_fil text not null
circulating_fil text not null,
vested_fil text not null,
mined_fil text not null,
burnt_fil text not null,
locked_fil text not null
);
create table if not exists block_cids
@@ -235,7 +239,7 @@ func (s *Syncer) unsyncedBlocks(ctx context.Context, head *types.TipSet, since t
log.Debugw("To visit", "toVisit", toVisit.Len(), "toSync", len(toSync), "current_height", bh.Height)
}
if len(bh.Parents) == 0 {
if bh.Height == 0 {
continue
}
@@ -283,11 +287,16 @@ func (s *Syncer) storeCirculatingSupply(ctx context.Context, tipset *types.TipSe
return err
}
ceInsert := `insert into chain_economics (parent_state_root, circulating_fil) values ('%s', '%s');`
ceInsert := `insert into chain_economics (parent_state_root, circulating_fil, vested_fil, mined_fil, burnt_fil, locked_fil)` +
`values ('%s', '%s', '%s', '%s', '%s', '%s');`
if _, err := s.db.Exec(fmt.Sprintf(ceInsert,
tipset.ParentState().String(),
supply.String(),
supply.FilCirculating.String(),
supply.FilVested.String(),
supply.FilMined.String(),
supply.FilBurnt.String(),
supply.FilLocked.String(),
)); err != nil {
return xerrors.Errorf("insert circulating supply for tipset (%s): %w", tipset.Key().String(), err)
}
+1 -1
View File
@@ -21,7 +21,7 @@ import (
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
+1 -1
View File
@@ -29,7 +29,7 @@
<span>When creating miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min.</span>
</div>
<div class="Index-node">
<span>If you don't have an owner/worker address, you can create it by following <a target="_blank" href="https://docs.lotu.sh/en+mining#get-started-22083">these instructions</a>.</span>
<span>If you don't have an owner/worker address, you can create it by following <a target="_blank" href="https://lotu.sh/en+mining#get-started-22083">these instructions</a>.</span>
</div>
</div>
<div class="Index-footer">
+76
View File
@@ -0,0 +1,76 @@
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/urfave/cli/v2"
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Value: "bls",
Usage: "specify key type to generate (bls or secp256k1)",
},
}
app.Action = func(cctx *cli.Context) error {
memks := wallet.NewMemKeyStore()
w, err := wallet.NewWallet(memks)
if err != nil {
return err
}
var kt crypto.SigType
switch cctx.String("type") {
case "bls":
kt = crypto.SigTypeBLS
case "secp256k1":
kt = crypto.SigTypeSecp256k1
default:
return fmt.Errorf("unrecognized key type: %q", cctx.String("type"))
}
kaddr, err := w.GenerateKey(kt)
if err != nil {
return err
}
ki, err := w.Export(kaddr)
if err != nil {
return err
}
fi, err := os.Create(fmt.Sprintf("%s.key", kaddr))
if err != nil {
return err
}
defer fi.Close()
b, err := json.Marshal(ki)
if err != nil {
return err
}
if _, err := fi.Write(b); err != nil {
return fmt.Errorf("failed to write key info to file: %w", err)
}
fmt.Println("Generated new key: ", kaddr)
return nil
}
if err := app.Run(os.Args); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
+185 -59
View File
@@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"strconv"
"time"
"github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
@@ -20,6 +21,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
@@ -70,16 +72,24 @@ func main() {
EnvVars: []string{"LOTUS_PCR_PATH"},
Value: "~/.lotuspcr", // TODO: Consider XDG_DATA_HOME
},
&cli.StringFlag{
Name: "log-level",
EnvVars: []string{"LOTUS_PCR_LOG_LEVEL"},
Hidden: true,
Value: "info",
},
},
Before: func(cctx *cli.Context) error {
return logging.SetLogLevel("main", cctx.String("log-level"))
},
Commands: local,
}
if err := app.Run(os.Args); err != nil {
log.Warn(err)
log.Errorw("exit in error", "err", err)
os.Exit(1)
return
}
}
var versionCmd = &cli.Command{
@@ -90,6 +100,7 @@ var versionCmd = &cli.Command{
return nil
},
}
var runCmd = &cli.Command{
Name: "run",
Usage: "Start message reimpursement",
@@ -97,19 +108,36 @@ var runCmd = &cli.Command{
&cli.StringFlag{
Name: "from",
EnvVars: []string{"LOTUS_PCR_FROM"},
Usage: "wallet address to send refund from",
},
&cli.BoolFlag{
Name: "no-sync",
EnvVars: []string{"LOTUS_PCR_NO_SYNC"},
Usage: "do not wait for chain sync to complete",
},
&cli.IntFlag{
Name: "percent-extra",
Value: 3,
Name: "percent-extra",
EnvVars: []string{"LOTUS_PCR_PERCENT_EXTRA"},
Usage: "extra funds to send above the refund",
Value: 3,
},
&cli.IntFlag{
Name: "head-delay",
Usage: "the number of tipsets to delay message processing to smooth chain reorgs",
Value: int(build.MessageConfidence),
Name: "max-message-queue",
EnvVars: []string{"LOTUS_PCR_MAX_MESSAGE_QUEUE"},
Usage: "set the maximum number of messages that can be queue in the mpool",
Value: 3000,
},
&cli.BoolFlag{
Name: "dry-run",
EnvVars: []string{"LOTUS_PCR_DRY_RUN"},
Usage: "do not send any messages",
Value: false,
},
&cli.IntFlag{
Name: "head-delay",
EnvVars: []string{"LOTUS_PCR_HEAD_DELAY"},
Usage: "the number of tipsets to delay message processing to smooth chain reorgs",
Value: int(build.MessageConfidence),
},
},
Action: func(cctx *cli.Context) error {
@@ -150,15 +178,52 @@ var runCmd = &cli.Command{
}
percentExtra := cctx.Int("percent-extra")
maxMessageQueue := cctx.Int("max-message-queue")
dryRun := cctx.Bool("dry-run")
rf := &refunder{
api: api,
wallet: from,
percentExtra: percentExtra,
dryRun: dryRun,
}
for tipset := range tipsetsCh {
if err := ProcessTipset(ctx, api, tipset, from, percentExtra); err != nil {
refunds, err := rf.ProcessTipset(ctx, tipset)
if err != nil {
return err
}
if err := rf.Refund(ctx, tipset, refunds); err != nil {
return err
}
if err := r.SetHeight(tipset.Height()); err != nil {
return err
}
for {
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
if err != nil {
log.Warnw("failed to fetch pending messages", "err", err)
time.Sleep(time.Duration(int64(time.Second) * int64(build.BlockDelaySecs)))
continue
}
count := 0
for _, msg := range msgs {
if msg.Message.From == from {
count = count + 1
}
}
if count < maxMessageQueue {
break
}
log.Warnw("messages in mpool over max message queue", "message_count", count, "max_message_queue", maxMessageQueue)
time.Sleep(time.Duration(int64(time.Second) * int64(build.BlockDelaySecs)))
}
}
return nil
@@ -167,6 +232,7 @@ var runCmd = &cli.Command{
type MinersRefund struct {
refunds map[address.Address]types.BigInt
count int
}
func NewMinersRefund() *MinersRefund {
@@ -180,11 +246,13 @@ func (m *MinersRefund) Track(addr address.Address, value types.BigInt) {
m.refunds[addr] = types.NewInt(0)
}
m.count = m.count + 1
m.refunds[addr] = types.BigAdd(m.refunds[addr], value)
}
func (m *MinersRefund) Count() int {
return len(m.refunds)
return m.count
}
func (m *MinersRefund) Miners() []address.Address {
@@ -200,50 +268,58 @@ func (m *MinersRefund) GetRefund(addr address.Address) types.BigInt {
return m.refunds[addr]
}
type processTipSetApi interface {
type refunderNodeApi interface {
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]api.Message, error)
ChainGetParentReceipts(ctx context.Context, blockCid cid.Cid) ([]*types.MessageReceipt, error)
ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
StateMinerInitialPledgeCollateral(ctx context.Context, addr address.Address, precommitInfo miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error)
StateSectorPreCommitInfo(ctx context.Context, addr address.Address, sector abi.SectorNumber, tsk types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error)
GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error)
}
func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipSet, wallet address.Address, percentExtra int) error {
log.Infow("processing tipset", "height", tipset.Height(), "key", tipset.Key().String())
type refunder struct {
api refunderNodeApi
wallet address.Address
percentExtra int
dryRun bool
}
func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*MinersRefund, error) {
cids := tipset.Cids()
if len(cids) == 0 {
return fmt.Errorf("no cids in tipset")
log.Errorw("no cids in tipset", "height", tipset.Height(), "key", tipset.Key())
return nil, fmt.Errorf("no cids in tipset")
}
msgs, err := api.ChainGetParentMessages(ctx, cids[0])
msgs, err := r.api.ChainGetParentMessages(ctx, cids[0])
if err != nil {
log.Errorw("failed to get tipset parent messages", "err", err)
return nil
log.Errorw("failed to get tipset parent messages", "err", err, "height", tipset.Height(), "key", tipset.Key())
return nil, nil
}
recps, err := api.ChainGetParentReceipts(ctx, cids[0])
recps, err := r.api.ChainGetParentReceipts(ctx, cids[0])
if err != nil {
log.Errorw("failed to get tipset parent receipts", "err", err)
return nil
log.Errorw("failed to get tipset parent receipts", "err", err, "height", tipset.Height(), "key", tipset.Key())
return nil, nil
}
if len(msgs) != len(recps) {
log.Errorw("message length does not match receipts length", "messages", len(msgs), "receipts", len(recps))
return nil
log.Errorw("message length does not match receipts length", "height", tipset.Height(), "key", tipset.Key(), "messages", len(msgs), "receipts", len(recps))
return nil, nil
}
refunds := NewMinersRefund()
count := 0
refundValue := types.NewInt(0)
for i, msg := range msgs {
m := msg.Message
a, err := api.StateGetActor(ctx, m.To, tipset.Key())
a, err := r.api.StateGetActor(ctx, m.To, tipset.Key())
if err != nil {
log.Warnw("failed to look up state actor", "actor", m.To)
log.Warnw("failed to look up state actor", "height", tipset.Height(), "key", tipset.Key(), "actor", m.To)
continue
}
@@ -251,39 +327,87 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS
continue
}
// we only care to look at PreCommitSector messages
if m.Method != builtin.MethodsMiner.PreCommitSector {
var messageMethod string
switch m.Method {
case builtin.MethodsMiner.ProveCommitSector:
messageMethod = "ProveCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var proveCommitSector miner.ProveCommitSectorParams
if err := proveCommitSector.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode provecommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
// We use the parent tipset key because precommit information is removed when ProveCommitSector is executed
precommitChainInfo, err := r.api.StateSectorPreCommitInfo(ctx, m.To, proveCommitSector.SectorNumber, tipset.Parents())
if err != nil {
log.Warnw("failed to get precommit info for sector", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber)
continue
}
precommitTipset, err := r.api.ChainGetTipSetByHeight(ctx, precommitChainInfo.PreCommitEpoch, tipset.Key())
if err != nil {
log.Warnf("failed to lookup precommit epoch", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitChainInfo.Info, precommitTipset.Key())
if err != nil {
log.Warnw("failed to get initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber)
}
collateral = big.Sub(collateral, precommitChainInfo.PreCommitDeposit)
if collateral.LessThan(big.Zero()) {
log.Debugw("skipping zero pledge collateral difference", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", proveCommitSector.SectorNumber)
continue
}
refundValue = collateral
case builtin.MethodsMiner.PreCommitSector:
messageMethod = "PreCommitSector"
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "method", messageMethod, "cid", msg.Cid, "miner", m.To, "exitcode", recps[i].ExitCode)
continue
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To)
continue
}
collateral, err := r.api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate initial pledge collateral", "err", err, "method", messageMethod, "cid", msg.Cid, "miner", m.To, "sector_number", precommitInfo.SectorNumber)
continue
}
refundValue = collateral
default:
continue
}
if recps[i].ExitCode != exitcode.Ok {
log.Debugw("skipping non-ok exitcode message", "cid", msg.Cid.String(), "exitcode", recps[i].ExitCode)
if r.percentExtra > 0 {
refundValue = types.BigAdd(refundValue, types.BigMul(types.BigDiv(refundValue, types.NewInt(100)), types.NewInt(uint64(r.percentExtra))))
}
var precommitInfo miner.SectorPreCommitInfo
if err := precommitInfo.UnmarshalCBOR(bytes.NewBuffer(m.Params)); err != nil {
log.Warnw("failed to decode precommit params", "err", err)
continue
}
log.Debugw("processing message", "method", messageMethod, "cid", msg.Cid, "from", m.From, "to", m.To, "value", m.Value, "gas_fee_cap", m.GasFeeCap, "gas_premium", m.GasPremium, "gas_used", recps[i].GasUsed, "refund", refundValue)
refundValue, err := api.StateMinerInitialPledgeCollateral(ctx, m.To, precommitInfo, tipset.Key())
if err != nil {
log.Warnw("failed to calculate", "err", err)
continue
}
if percentExtra > 0 {
refundValue = types.BigAdd(refundValue, types.BigDiv(refundValue, types.NewInt(100*uint64(percentExtra))))
}
log.Infow("processing message", "from", m.From, "to", m.To, "value", m.Value.String(), "gas_fee_cap", m.GasFeeCap.String(), "gas_premium", m.GasPremium.String(), "gas_used", fmt.Sprintf("%d", recps[i].GasUsed), "refund", refundValue.String())
count = count + 1
refunds.Track(m.From, refundValue)
}
return refunds, nil
}
func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) error {
if refunds.Count() == 0 {
log.Debugw("no messages to refund in tipset")
log.Debugw("no messages to refund in tipset", "height", tipset.Height(), "key", tipset.Key())
return nil
}
@@ -294,15 +418,15 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS
refundValue := refunds.GetRefund(maddr)
// We want to try and ensure these messages get mined quickly
gasPremium, err := api.GasEstimateGasPremium(ctx, 0, wallet, 0, tipset.Key())
gasPremium, err := r.api.GasEstimateGasPremium(ctx, 0, r.wallet, 0, tipset.Key())
if err != nil {
log.Warnw("failed to estimate gas premium", "err", err)
log.Warnw("failed to estimate gas premium", "err", err, "height", tipset.Height(), "key", tipset.Key())
continue
}
msg := &types.Message{
Value: refundValue,
From: wallet,
From: r.wallet,
To: maddr,
GasPremium: gasPremium,
@@ -312,32 +436,34 @@ func ProcessTipset(ctx context.Context, api processTipSetApi, tipset *types.TipS
messages = append(messages, msg)
}
balance, err := api.WalletBalance(ctx, wallet)
balance, err := r.api.WalletBalance(ctx, r.wallet)
if err != nil {
log.Errorw("failed to get wallet balance", "err", err, "height", tipset.Height(), "key", tipset.Key())
return xerrors.Errorf("failed to get wallet balance :%w", err)
}
// Calculate the minimum balance as the total refund we need to issue plus 5% to cover fees
minBalance := types.BigAdd(refundSum, types.BigDiv(refundSum, types.NewInt(500)))
if balance.LessThan(minBalance) {
log.Errorw("not sufficent funds to cover refunds", "balance", balance.String(), "refund_sum", refundSum.String(), "minimum_required", minBalance.String())
log.Errorw("not sufficent funds to cover refunds", "balance", balance, "refund_sum", refundSum, "minimum_required", minBalance)
return xerrors.Errorf("wallet does not have enough balance to cover refund")
}
failures := 0
refundSum.SetUint64(0)
for _, msg := range messages {
if _, err = api.MpoolPushMessage(ctx, msg, nil); err != nil {
log.Errorw("failed to MpoolPushMessage", "err", err, "msg", msg)
failures = failures + 1
continue
if !r.dryRun {
if _, err = r.api.MpoolPushMessage(ctx, msg, nil); err != nil {
log.Errorw("failed to MpoolPushMessage", "err", err, "msg", msg)
failures = failures + 1
continue
}
}
refundSum = types.BigAdd(refundSum, msg.Value)
}
log.Infow("tipset stats", "messages_sent", len(messages)-failures, "refund_sum", refundSum.String(), "messages_failures", failures)
log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count())
return nil
}
+23 -6
View File
@@ -22,17 +22,18 @@ import (
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/go-jsonrpc/auth"
paramfetch "github.com/filecoin-project/go-paramfetch"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/build"
lcli "github.com/filecoin-project/lotus/cli"
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/sealtasks"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/lotus/lib/lotuslog"
"github.com/filecoin-project/lotus/lib/rpcenc"
"github.com/filecoin-project/lotus/node/repo"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/sealtasks"
"github.com/filecoin-project/sector-storage/stores"
)
var log = logging.Logger("main")
@@ -105,6 +106,11 @@ var runCmd = &cli.Command{
Name: "no-local-storage",
Usage: "don't use storageminer repo for sector storage",
},
&cli.BoolFlag{
Name: "addpiece",
Usage: "enable addpiece",
Value: true,
},
&cli.BoolFlag{
Name: "precommit1",
Usage: "enable precommit1 (32G sectors: 1 core, 128GiB Memory)",
@@ -158,7 +164,9 @@ var runCmd = &cli.Command{
var closer func()
var err error
for {
nodeApi, closer, err = lcli.GetStorageMinerAPI(cctx)
nodeApi, closer, err = lcli.GetStorageMinerAPI(cctx,
jsonrpc.WithNoReconnect(),
jsonrpc.WithTimeout(30*time.Second))
if err == nil {
break
}
@@ -204,6 +212,9 @@ var runCmd = &cli.Command{
taskTypes = append(taskTypes, sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize)
if cctx.Bool("addpiece") {
taskTypes = append(taskTypes, sealtasks.TTAddPiece)
}
if cctx.Bool("precommit1") {
taskTypes = append(taskTypes, sealtasks.TTPreCommit1)
}
@@ -337,10 +348,12 @@ var runCmd = &cli.Command{
log.Info("Setting up control endpoint at " + address)
rpcServer := jsonrpc.NewServer()
readerHandler, readerServerOpt := rpcenc.ReaderParamDecoder()
rpcServer := jsonrpc.NewServer(readerServerOpt)
rpcServer.Register("Filecoin", apistruct.PermissionedWorkerAPI(workerApi))
mux.Handle("/rpc/v0", rpcServer)
mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler)
mux.PathPrefix("/remote").HandlerFunc((&stores.FetchHandler{Local: localStore}).ServeHTTP)
mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof
@@ -418,9 +431,13 @@ func watchMinerConn(ctx context.Context, cctx *cli.Context, nodeApi api.StorageM
"run",
fmt.Sprintf("--listen=%s", cctx.String("listen")),
fmt.Sprintf("--no-local-storage=%t", cctx.Bool("no-local-storage")),
fmt.Sprintf("--addpiece=%t", cctx.Bool("addpiece")),
fmt.Sprintf("--precommit1=%t", cctx.Bool("precommit1")),
fmt.Sprintf("--unseal=%t", cctx.Bool("unseal")),
fmt.Sprintf("--precommit2=%t", cctx.Bool("precommit2")),
fmt.Sprintf("--commit=%t", cctx.Bool("commit")),
fmt.Sprintf("--parallel-fetch-limit=%d", cctx.Int("parallel-fetch-limit")),
fmt.Sprintf("--timeout=%s", cctx.String("timeout")),
}, os.Environ()); err != nil {
fmt.Println(err)
}
+2 -1
View File
@@ -5,8 +5,9 @@ import (
"github.com/filecoin-project/specs-storage/storage"
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/sector-storage"
)
type worker struct {
+5 -4
View File
@@ -48,10 +48,11 @@ var genesisNewCmd = &cli.Command{
return xerrors.New("seed genesis new [genesis.json]")
}
out := genesis.Template{
Accounts: []genesis.Actor{},
Miners: []genesis.Miner{},
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
NetworkName: cctx.String("network-name"),
Accounts: []genesis.Actor{},
Miners: []genesis.Miner{},
VerifregRootKey: gen.DefaultVerifregRootkeyActor,
RemainderAccount: gen.DefaultRemainderAccountActor,
NetworkName: cctx.String("network-name"),
}
if out.NetworkName == "" {
out.NetworkName = "localnet-" + uuid.New().String()
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"os"
"github.com/docker/go-units"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
logging "github.com/ipfs/go-log/v2"
"github.com/mitchellh/go-homedir"
+5 -4
View File
@@ -19,7 +19,7 @@ import (
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/zerocomm"
"github.com/filecoin-project/lotus/extern/sector-storage/zerocomm"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
@@ -27,10 +27,10 @@ import (
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
"github.com/filecoin-project/sector-storage/stores"
)
var log = logging.Logger("preseal")
@@ -114,6 +114,7 @@ func PreSeal(maddr address.Address, spt abi.RegisteredSealProof, offset abi.Sect
}
miner := &genesis.Miner{
ID: maddr,
Owner: minerAddr.Address,
Worker: minerAddr.Address,
MarketBalance: big.Zero(),
+89
View File
@@ -0,0 +1,89 @@
package main
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/gbrlsnchs/jwt/v3"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/api/apistruct"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/modules"
)
var jwtCmd = &cli.Command{
Name: "jwt",
Usage: "work with lotus jwt secrets and tokens",
Description: `The subcommands of jwt provide helpful tools for working with jwt files without
having to run the lotus daemon.`,
Subcommands: []*cli.Command{
jwtNewCmd,
},
}
var jwtNewCmd = &cli.Command{
Name: "new",
Usage: "create a new jwt secret and token for lotus",
ArgsUsage: "<name>",
Description: `Jwt tokens are used to authenticate api requests to the lotus daemon.
The created jwt token have full privileges and should not be shared.`,
Flags: []cli.Flag{},
Action: func(cctx *cli.Context) error {
if !cctx.Args().Present() {
return fmt.Errorf("please specify a name")
}
keyName := cctx.Args().First()
sk, err := ioutil.ReadAll(io.LimitReader(rand.Reader, 32))
if err != nil {
return err
}
keyInfo := types.KeyInfo{
Type: modules.KTJwtHmacSecret,
PrivateKey: sk,
}
p := modules.JwtPayload{
Allow: apistruct.AllPermissions,
}
token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey))
if err != nil {
return err
}
filename := fmt.Sprintf("jwt-%s.jwts", keyName)
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
defer func() {
if err := file.Close(); err != nil {
log.Warnf("failed to close output file: %w", err)
}
}()
bytes, err := json.Marshal(keyInfo)
if err != nil {
return err
}
encoded := hex.EncodeToString(bytes)
if _, err := file.Write([]byte(encoded)); err != nil {
return err
}
filenameToken := fmt.Sprintf("jwt-%s.token", keyName)
return ioutil.WriteFile(filenameToken, token, 0600)
},
}
+1 -1
View File
@@ -330,7 +330,7 @@ var keyinfoNewCmd = &cli.Command{
filename = strings.ReplaceAll(filename, "<addr>", keyAddr)
filename = strings.ReplaceAll(filename, "<type>", keyType)
file, err := os.Create(filename)
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return err
}
+1
View File
@@ -19,6 +19,7 @@ func main() {
base16Cmd,
bitFieldCmd,
keyinfoCmd,
jwtCmd,
noncefix,
bigIntParseCmd,
staterootCmd,
+388 -2
View File
@@ -2,16 +2,26 @@ package main
import (
"fmt"
"os"
"strings"
"github.com/fatih/color"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/lib/tablewriter"
"github.com/filecoin-project/lotus/storage"
)
var actorCmd = &cli.Command{
@@ -19,6 +29,9 @@ var actorCmd = &cli.Command{
Usage: "manipulate the miner actor",
Subcommands: []*cli.Command{
actorSetAddrsCmd,
actorWithdrawCmd,
actorSetPeeridCmd,
actorControl,
},
}
@@ -54,7 +67,14 @@ var actorSetAddrsCmd = &cli.Command{
return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err)
}
addrs = append(addrs, maddr.Bytes())
maddrNop2p, strip := ma.SplitFunc(maddr, func(c ma.Component) bool {
return c.Protocol().Code == ma.P_P2P
})
if strip != nil {
fmt.Println("Stripping peerid ", strip, " from ", maddr)
}
addrs = append(addrs, maddrNop2p.Bytes())
}
maddr, err := nodeAPI.ActorAddress(ctx)
@@ -79,7 +99,7 @@ var actorSetAddrsCmd = &cli.Command{
From: minfo.Worker,
Value: types.NewInt(0),
GasLimit: gasLimit,
Method: 18,
Method: builtin.MethodsMiner.ChangeMultiaddrs,
Params: params,
}, nil)
if err != nil {
@@ -91,3 +111,369 @@ var actorSetAddrsCmd = &cli.Command{
},
}
var actorSetPeeridCmd = &cli.Command{
Name: "set-peer-id",
Usage: "set the peer id of your miner",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "gas-limit",
Usage: "set gas limit",
Value: 0,
},
},
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)
pid, err := peer.IDFromString(cctx.Args().Get(0))
if err != nil {
return fmt.Errorf("failed to parse input as a peerId: %w", err)
}
maddr, err := nodeAPI.ActorAddress(ctx)
if err != nil {
return err
}
minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)})
if err != nil {
return err
}
gasLimit := cctx.Int64("gas-limit")
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
To: maddr,
From: minfo.Worker,
Value: types.NewInt(0),
GasLimit: gasLimit,
Method: builtin.MethodsMiner.ChangePeerID,
Params: params,
}, nil)
if err != nil {
return err
}
fmt.Printf("Requested peerid change in message %s\n", smsg.Cid())
return nil
},
}
var actorWithdrawCmd = &cli.Command{
Name: "withdraw",
Usage: "withdraw available balance",
ArgsUsage: "[amount (FIL)]",
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
}
available, err := api.StateMinerAvailableBalance(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
amount := available
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)
if amount.GreaterThan(available) {
return xerrors.Errorf("can't withdraw more funds than available; requested: %s; available: %s", amount, available)
}
}
params, err := actors.SerializeParams(&miner.WithdrawBalanceParams{
AmountRequested: amount, // Default to attempting to withdraw all the extra funds in the miner actor
})
if err != nil {
return err
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
To: maddr,
From: mi.Owner,
Value: types.NewInt(0),
Method: builtin.MethodsMiner.WithdrawBalance,
Params: params,
}, nil)
if err != nil {
return err
}
fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid())
return nil
},
}
var actorControl = &cli.Command{
Name: "control",
Usage: "Manage control addresses",
Subcommands: []*cli.Command{
actorControlList,
actorControlSet,
},
}
var actorControlList = &cli.Command{
Name: "list",
Usage: "Get currently set control addresses",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
},
&cli.BoolFlag{
Name: "color",
Value: true,
},
},
Action: func(cctx *cli.Context) error {
color.NoColor = !cctx.Bool("color")
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
}
tw := tablewriter.New(
tablewriter.Col("name"),
tablewriter.Col("ID"),
tablewriter.Col("key"),
tablewriter.Col("use"),
tablewriter.Col("balance"),
)
postAddr, err := storage.AddressFor(ctx, api, mi, storage.PoStAddr, types.FromFil(1))
if err != nil {
return xerrors.Errorf("getting address for post: %w", err)
}
printKey := func(name string, a address.Address) {
b, err := api.WalletBalance(ctx, a)
if err != nil {
fmt.Printf("%s\t%s: error getting balance: %s\n", name, a, err)
return
}
k, err := api.StateAccountKey(ctx, a, types.EmptyTSK)
if err != nil {
fmt.Printf("%s\t%s: error getting account key: %s\n", name, a, err)
return
}
kstr := k.String()
if !cctx.Bool("verbose") {
kstr = kstr[:9] + "..."
}
bstr := types.FIL(b).String()
switch {
case b.LessThan(types.FromFil(10)):
bstr = color.RedString(bstr)
case b.LessThan(types.FromFil(50)):
bstr = color.YellowString(bstr)
default:
bstr = color.GreenString(bstr)
}
var uses []string
if a == mi.Worker {
uses = append(uses, color.YellowString("other"))
}
if a == postAddr {
uses = append(uses, color.GreenString("post"))
}
tw.Write(map[string]interface{}{
"name": name,
"ID": a,
"key": kstr,
"use": strings.Join(uses, " "),
"balance": bstr,
})
}
printKey("owner", mi.Owner)
printKey("worker", mi.Worker)
for i, ca := range mi.ControlAddresses {
printKey(fmt.Sprintf("control-%d", i), ca)
}
return tw.Flush(os.Stdout)
},
}
var actorControlSet = &cli.Command{
Name: "set",
Usage: "Set control address(-es)",
ArgsUsage: "[...address]",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "really-do-it",
Usage: "Actually send transaction performing the action",
Value: false,
},
},
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
}
del := map[address.Address]struct{}{}
existing := map[address.Address]struct{}{}
for _, controlAddress := range mi.ControlAddresses {
ka, err := api.StateAccountKey(ctx, controlAddress, types.EmptyTSK)
if err != nil {
return err
}
del[ka] = struct{}{}
existing[ka] = struct{}{}
}
var toSet []address.Address
for i, as := range cctx.Args().Slice() {
a, err := address.NewFromString(as)
if err != nil {
return xerrors.Errorf("parsing address %d: %w", i, err)
}
ka, err := api.StateAccountKey(ctx, a, types.EmptyTSK)
if err != nil {
return err
}
// make sure the address exists on chain
_, err = api.StateLookupID(ctx, ka, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("looking up %s: %w", ka, err)
}
delete(del, ka)
toSet = append(toSet, ka)
}
for a := range del {
fmt.Println("Remove", a)
}
for _, a := range toSet {
if _, exists := existing[a]; !exists {
fmt.Println("Add", a)
}
}
if !cctx.Bool("really-do-it") {
fmt.Println("Pass --really-do-it to actually execute this action")
return nil
}
cwp := &miner.ChangeWorkerAddressParams{
NewWorker: mi.Worker,
NewControlAddrs: toSet,
}
sp, err := actors.SerializeParams(cwp)
if err != nil {
return xerrors.Errorf("serializing params: %w", err)
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
From: mi.Owner,
To: maddr,
Method: builtin.MethodsMiner.ChangeWorkerAddress,
Value: big.Zero(),
Params: sp,
}, nil)
if err != nil {
return xerrors.Errorf("mpool push: %w", err)
}
fmt.Println("Message CID:", smsg.Cid())
return nil
},
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/node/config"
)
var configCmd = &cli.Command{
Name: "config",
Usage: "Output default configuration",
Action: func(cctx *cli.Context) error {
comm, err := config.ConfigComment(config.DefaultStorageMiner())
if err != nil {
return err
}
fmt.Println(string(comm))
return nil
},
}
+2 -1
View File
@@ -11,9 +11,9 @@ import (
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
sealing "github.com/filecoin-project/storage-fsm"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
@@ -143,6 +143,7 @@ func infoCmdAct(cctx *cli.Context) error {
fmt.Printf("Miner Balance: %s\n", color.YellowString("%s", types.FIL(mact.Balance)))
fmt.Printf("\tPreCommit: %s\n", types.FIL(mas.PreCommitDeposits))
fmt.Printf("\tPledge: %s\n", types.FIL(mas.InitialPledgeRequirement))
fmt.Printf("\tLocked: %s\n", types.FIL(mas.LockedFunds))
color.Green("\tAvailable: %s", types.FIL(types.BigSub(mact.Balance, types.BigAdd(mas.LockedFunds, mas.PreCommitDeposits))))
wb, err := api.WalletBalance(ctx, mi.Worker)
+5
View File
@@ -148,6 +148,11 @@ var infoAllCmd = &cli.Command{
}
}
fmt.Println("\n#: Goroutines")
if err := lcli.PprofGoroutines.Action(cctx); err != nil {
return err
}
return nil
},
}
+21 -6
View File
@@ -7,12 +7,13 @@ import (
"encoding/binary"
"encoding/json"
"fmt"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/docker/go-units"
"github.com/google/uuid"
"github.com/ipfs/go-datastore"
@@ -25,9 +26,9 @@ import (
"github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util"
paramfetch "github.com/filecoin-project/go-paramfetch"
sectorstorage "github.com/filecoin-project/sector-storage"
"github.com/filecoin-project/sector-storage/ffiwrapper"
"github.com/filecoin-project/sector-storage/stores"
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"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
@@ -41,13 +42,13 @@ import (
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
"github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/miner"
"github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage"
sealing "github.com/filecoin-project/storage-fsm"
)
var initCmd = &cli.Command{
@@ -107,6 +108,10 @@ var initCmd = &cli.Command{
Usage: "set gas premium for initialization messages in AttoFIL",
Value: "0",
},
&cli.StringFlag{
Name: "from",
Usage: "select which address to send actor creation message from",
},
},
Action: func(cctx *cli.Context) error {
log.Info("Initializing lotus miner")
@@ -440,6 +445,7 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
SealProofType: spt,
}, sectorstorage.SealerConfig{
ParallelFetchLimit: 10,
AllowAddPiece: true,
AllowPreCommit1: true,
AllowPreCommit2: true,
AllowCommit: true,
@@ -630,9 +636,18 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID,
return address.Undef, err
}
sender := owner
if fromstr := cctx.String("from"); fromstr != "" {
faddr, err := address.NewFromString(fromstr)
if err != nil {
return address.Undef, fmt.Errorf("could not parse from address: %w", err)
}
sender = faddr
}
createStorageMinerMsg := &types.Message{
To: builtin.StoragePowerActorAddr,
From: owner,
From: sender,
Value: big.Zero(),
Method: builtin.MethodsPower.CreateMiner,
+2 -1
View File
@@ -32,11 +32,12 @@ func main() {
initCmd,
runCmd,
stopCmd,
configCmd,
lcli.WithCategory("chain", actorCmd),
lcli.WithCategory("chain", rewardsCmd),
lcli.WithCategory("chain", infoCmd),
lcli.WithCategory("market", storageDealsCmd),
lcli.WithCategory("market", retrievalDealsCmd),
lcli.WithCategory("market", dataTransfersCmd),
lcli.WithCategory("storage", sectorsCmd),
lcli.WithCategory("storage", provingCmd),
lcli.WithCategory("storage", storageCmd),
+116 -3
View File
@@ -5,10 +5,12 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"text/tabwriter"
"time"
tm "github.com/buger/goterm"
"github.com/docker/go-units"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-cidutil/cidenc"
@@ -338,6 +340,12 @@ var dealsImportDataCmd = &cli.Command{
var dealsListCmd = &cli.Command{
Name: "list",
Usage: "List all deals for this miner",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
@@ -352,17 +360,38 @@ var dealsListCmd = &cli.Command{
return err
}
sort.Slice(deals, func(i, j int) bool {
return deals[i].CreationTime.Time().Before(deals[j].CreationTime.Time())
})
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
_, _ = fmt.Fprintf(w, "ProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\n")
verbose := cctx.Bool("verbose")
if verbose {
_, _ = fmt.Fprintf(w, "Creation\tProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\tMessage\n")
} else {
_, _ = fmt.Fprintf(w, "ProposalCid\tDealId\tState\tClient\tSize\tPrice\tDuration\n")
}
for _, deal := range deals {
propcid := deal.ProposalCid.String()
propcid = "..." + propcid[len(propcid)-8:]
if !verbose {
propcid = "..." + propcid[len(propcid)-8:]
}
fil := types.FIL(types.BigMul(deal.Proposal.StoragePricePerEpoch, types.NewInt(uint64(deal.Proposal.Duration()))))
_, _ = fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s\n", propcid, deal.DealID, storagemarket.DealStates[deal.State], deal.Proposal.Client, units.BytesSize(float64(deal.Proposal.PieceSize)), fil, deal.Proposal.Duration())
if verbose {
_, _ = fmt.Fprintf(w, "%s\t", deal.CreationTime.Time().Format(time.Stamp))
}
_, _ = fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\t%s", propcid, deal.DealID, storagemarket.DealStates[deal.State], deal.Proposal.Client, units.BytesSize(float64(deal.Proposal.PieceSize)), fil, deal.Proposal.Duration())
if verbose {
_, _ = fmt.Fprintf(w, "\t%s", deal.Message)
}
_, _ = fmt.Fprintln(w)
}
return w.Flush()
@@ -487,3 +516,87 @@ var setSealDurationCmd = &cli.Command{
return nodeApi.SectorSetExpectedSealDuration(ctx, time.Duration(delay))
},
}
var dataTransfersCmd = &cli.Command{
Name: "data-transfers",
Usage: "Manage data transfers",
Subcommands: []*cli.Command{
transfersListCmd,
},
}
var transfersListCmd = &cli.Command{
Name: "list",
Usage: "List ongoing data transfers for this miner",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "color",
Usage: "use color in display output",
Value: true,
},
&cli.BoolFlag{
Name: "completed",
Usage: "show completed data transfers",
},
&cli.BoolFlag{
Name: "watch",
Usage: "watch deal updates in real-time, rather than a one time list",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := lcli.GetStorageMinerAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := lcli.ReqContext(cctx)
channels, err := api.MarketListDataTransfers(ctx)
if err != nil {
return err
}
completed := cctx.Bool("completed")
color := cctx.Bool("color")
watch := cctx.Bool("watch")
if watch {
channelUpdates, err := api.MarketDataTransferUpdates(ctx)
if err != nil {
return err
}
for {
tm.Clear() // Clear current screen
tm.MoveCursor(1, 1)
lcli.OutputDataTransferChannels(tm.Screen, channels, completed, color)
tm.Flush()
select {
case <-ctx.Done():
return nil
case channelUpdate := <-channelUpdates:
var found bool
for i, existing := range channels {
if existing.TransferID == channelUpdate.TransferID &&
existing.OtherPeer == channelUpdate.OtherPeer &&
existing.IsSender == channelUpdate.IsSender &&
existing.IsInitiator == channelUpdate.IsInitiator {
channels[i] = channelUpdate
found = true
break
}
}
if !found {
channels = append(channels, channelUpdate)
}
}
}
}
lcli.OutputDataTransferChannels(os.Stdout, channels, completed, color)
return nil
},
}
-78
View File
@@ -1,78 +0,0 @@
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
var rewardsCmd = &cli.Command{
Name: "rewards",
Subcommands: []*cli.Command{
rewardsRedeemCmd,
},
}
var rewardsRedeemCmd = &cli.Command{
Name: "redeem",
Usage: "Redeem block rewards",
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
}
mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
if err != nil {
return err
}
params, err := actors.SerializeParams(&miner.WithdrawBalanceParams{
AmountRequested: mact.Balance, // Default to attempting to withdraw all the extra funds in the miner actor
})
if err != nil {
return err
}
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
To: maddr,
From: mi.Owner,
Value: types.NewInt(0),
Method: builtin.MethodsMiner.WithdrawBalance,
Params: params,
}, nil)
if err != nil {
return err
}
fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid())
return nil
},
}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"github.com/fatih/color"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/sector-storage/storiface"
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
+2 -2
View File
@@ -18,8 +18,8 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/sector-storage/fsutil"
"github.com/filecoin-project/sector-storage/stores"
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/lotus/chain/types"
+1 -1
View File
@@ -30,6 +30,7 @@ import (
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/vm"
lcli "github.com/filecoin-project/lotus/cli"
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/lotus/lib/peermgr"
"github.com/filecoin-project/lotus/lib/ulimit"
@@ -39,7 +40,6 @@ import (
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/modules/testing"
"github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/sector-storage/ffiwrapper"
)
const (
+23 -2
View File
@@ -67,6 +67,12 @@
"slug": "en+setup-troubleshooting",
"github": "en/setup-troubleshooting.md",
"value": null
},
{
"title": "Environment Variables",
"slug": "en+env-vars",
"github": "en/environment-vars.md",
"value": null
}
]
},
@@ -75,8 +81,16 @@
"slug": "en+arch",
"github": "en/architecture.md",
"value": null,
"posts": []
}, {
"posts": [
{
"title": "The Message Pool",
"slug": "en+mpool",
"github": "en/mpool.md",
"value": null
}
]
},
{
"title": "Storage Mining",
"slug": "en+mining",
"github": "en/mining.md",
@@ -135,6 +149,13 @@
"value": null,
"posts": []
},
{
"title": "Payment Channels",
"slug": "en+payment-channels",
"github": "en/payment-channels.md",
"value": null,
"posts": []
},
{
"title": "Command Line Interface",
"slug": "en+cli",
+1 -1
View File
@@ -1,6 +1,6 @@
# Pond UI
Pond is a graphical testbed for [Lotus](https://docs.lotu.sh). Using it will setup a separate local network which is helpful for debugging. Pond will spin up nodes, connect them in a given topology, start them mining, and observe how they function over time.
Pond is a graphical testbed for [Lotus](https://lotu.sh). Using it will setup a separate local network which is helpful for debugging. Pond will spin up nodes, connect them in a given topology, start them mining, and observe how they function over time.
## Build
+1 -1
View File
@@ -37,7 +37,7 @@ It is important to note that the key store also holds the *private* key associat
There is no explicit Filecoin message or CLI command that creates an account actor but rather it is implicit in the public-key address reflected by the wallet. The first time the VM sees it as the receiving address of a Filecoin message it will automatically create the associated account actor.
We will trigger its creation then by sending funds to it, needed for the creation of the storage miner (note this document reflects the Filecoin Testnet, where we actually don't need funds to create a miner but will do the full procedure regardless to show the full cycle). In the Testnet we can send funds to an account trough the [Faucet](https://faucet.testnet.filecoin.io/funds.html), inserting the address returned by the `wallet new` command.
We will trigger its creation then by sending funds to it, needed for the creation of the storage miner (note this document reflects the Filecoin Testnet, where we actually don't need funds to create a miner but will do the full procedure regardless to show the full cycle). In the Testnet we can send funds to an account through the [Faucet](http://spacerace.faucet.glif.io/), inserting the address returned by the `wallet new` command.
FIXME: Is there an easy way to visualize the message generated by the Faucet?
+60
View File
@@ -0,0 +1,60 @@
# Lotus Environment Variables
## Building
## Common
The environment variables are common across most lotus binaries.
### `LOTUS_FD_MAX`
Sets the file descriptor limit for the process. This should be set high (8192
or higher) if you ever notice 'too many open file descriptor' errors.
### `LOTUS_JAEGER`
This can be set to enable jaeger trace reporting. The value should be the url
of the jaeger trace collector, the default for most jaeger setups should be
`localhost:6831`.
### `LOTUS_DEV`
If set to a non-empty value, certain parts of the application will print more
verbose information to aid in development of the software. Not recommended for
end users.
## Lotus Daemon
### `LOTUS_PATH`
Sets the location for the lotus daemon on-disk repo. If left empty, this defaults to `~/.lotus`.
### `LOTUS_SKIP_GENESIS_CHECK`
Can be set to `_yes_` if you wish to run a lotus network with a different
genesis than the default one built into your lotus binary.
### `LOTUS_CHAIN_TIPSET_CACHE`
Sets the cache size for the chainstore tipset cache. The default value is 8192,
but if your usage of the lotus API involves frequent arbitrary tipset lookups,
you may want to increase this.
### `LOTUS_CHAIN_INDEX_CACHE`
Sets the cache size for the chainstore epoch index cache. The default value is 32768,
but if your usage of the lotus API involves frequent deep chain lookups for
block heights that are very far from the current chain height, you may want to
increase this.
## Lotus Miner
A number of environment variables are respected for configuring the behavior of the filecoin proving subsystem. For more details on those [see here](https://github.com/filecoin-project/rust-fil-proofs/#settings).
### `LOTUS_MINER_PATH`
Sets the location for the lotus miners on-disk repo. If left empty, this defaults to `~/.lotusminer`.
+2 -2
View File
@@ -30,7 +30,7 @@ to a Lotus Node over the JSON-RPC API.
### How do I set up a Lotus Node?
Follow the instructions found [here](https://docs.lotu.sh/en+getting-started).
Follow the instructions found [here](https://lotu.sh/en+getting-started).
### Where can I get the latest version of Lotus?
@@ -52,7 +52,7 @@ Stop the Lotus daemon, and delete all related files, including sealed and chain
running `rm ~/.lotus ~/.lotusminer`.
Then, install Lotus afresh by following the instructions
found [here](https://docs.lotu.sh/en+getting-started).
found [here](https://lotu.sh/en+getting-started).
### Can I configure where the node's config and data goes?
+4 -4
View File
@@ -6,10 +6,10 @@ For more details about Filecoin, check out the [Filecoin Docs](https://docs.file
## What can I learn here?
- How to install Lotus on [Arch Linux](https://docs.lotu.sh/en+install-lotus-arch), [Ubuntu](https://docs.lotu.sh/en+install-lotus-ubuntu), or [MacOS](https://docs.lotu.sh/en+install-lotus-macos).
- Joining the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet).
- [Storing](https://docs.lotu.sh/en+storing-data) or [retrieving](https://docs.lotu.sh/en+retrieving-data) data.
- Mining Filecoin using the **Lotus Miner** in your [CLI](https://docs.lotu.sh/en+mining).
- How to install Lotus on [Arch Linux](https://lotu.sh/en+install-lotus-arch), [Ubuntu](https://lotu.sh/en+install-lotus-ubuntu), or [MacOS](https://lotu.sh/en+install-lotus-macos).
- Joining the [Lotus Testnet](https://lotu.sh/en+join-testnet).
- [Storing](https://lotu.sh/en+storing-data) or [retrieving](https://lotu.sh/en+retrieving-data) data.
- Mining Filecoin using the **Lotus Miner** in your [CLI](https://lotu.sh/en+mining).
## How is Lotus designed?
+1 -1
View File
@@ -48,4 +48,4 @@ env env RUSTFLAGS="-C target-cpu=native -g" FFI_BUILD_FROM_SOURCE=1 make clean d
sudo make install
```
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet).
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://lotu.sh/en+join-testnet).
+1 -1
View File
@@ -51,4 +51,4 @@ env env RUSTFLAGS="-C target-cpu=native -g" FFI_BUILD_FROM_SOURCE=1 make clean d
sudo make install
```
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus TestNet](https://docs.lotu.sh/en+join-testnet).
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus TestNet](https://lotu.sh/en+join-testnet).
+1 -1
View File
@@ -59,4 +59,4 @@ make clean && make all
sudo make install
```
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet).
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://lotu.sh/en+join-testnet).
+1 -1
View File
@@ -51,4 +51,4 @@ sudo make install
```
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://docs.lotu.sh/en+join-testnet).
After installing Lotus, you can run the `lotus` command directly from your CLI to see usage documentation. Next, you can join the [Lotus Testnet](https://lotu.sh/en+join-testnet).
+4 -4
View File
@@ -9,7 +9,7 @@ Anyone can set up a **Lotus Node** and connect to the **Lotus Testnet**. This is
If you are trying to use `lotus` from China. You should set this **environment variable** on your machine:
```sh
IPFS_GATEWAY="https://proof-parameters.s3.cn-south-1.jdcloud-oss.com/ipfs/"
export IPFS_GATEWAY="https://proof-parameters.s3.cn-south-1.jdcloud-oss.com/ipfs/"
```
## Get started
@@ -26,9 +26,9 @@ In another terminal window, check your connection with peers:
lotus net peers | wc -l
```
In order to connect to the network, you need to be connected to at least 1 peer. If youre seeing 0 peers, read our [troubleshooting notes](https://docs.lotu.sh/en+setup-troubleshooting).
In order to connect to the network, you need to be connected to at least 1 peer. If youre seeing 0 peers, read our [troubleshooting notes](https://lotu.sh/en+setup-troubleshooting).
Make sure that you have a reasonable "open files limit" set on your machine, such as 10000. If you're seeing a lower value, such as 256 (default on macOS), read our [troubleshooting notes](https://docs.lotu.sh/en+setup-troubleshooting) on how to update it prior to starting the Lotus daemon.
Make sure that you have a reasonable "open files limit" set on your machine, such as 10000. If you're seeing a lower value, such as 256 (default on macOS), read our [troubleshooting notes](https://lotu.sh/en+setup-troubleshooting) on how to update it prior to starting the Lotus daemon.
## Chain sync
@@ -57,7 +57,7 @@ Here is an example of the response:
t1aswwvjsae63tcrniz6x5ykvsuotlgkvlulnqpsi
```
- Visit the [faucet](https://faucet.testnet.filecoin.io) to add funds.
- Visit the [faucet](http://spacerace.faucet.glif.io/) to add funds.
- Paste the address you created.
- Press the send button.

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