Compare commits

...
Author SHA1 Message Date
i-norden 87b8e0a8fd trying to fix gen-check error 2023-10-19 19:18:43 -05:00
i-norden 82f754f31e gofmt 2023-10-19 14:26:09 -05:00
i-norden 670b72ff1f update CHANGELOG.md 2023-10-19 13:54:49 -05:00
i-norden a17b6af00c update default-lotus-config.toml 2023-10-19 13:32:02 -05:00
i-norden a8829a049e add FilterThresholdEpoch configuration setting for defining a static starting epoch above which the node will return filtered logs 2023-10-19 13:31:49 -05:00
Andrew Jackson (Ajax) 14a7ae339f Merge pull request #11338 from filecoin-project/fix/storage-alloc-err-soft
storage: Return soft err when sector alloc fails in acquire
2023-10-18 09:38:49 -05:00
Aayush Rajasekaran 0374c50728 Merge pull request #11336 from filecoin-project/asr/merge-feat-nv21
chore: merge feat/nv21 into master
2023-10-17 09:39:49 -04:00
Aayush 864eef3e4c fix: cachefiles: add SynthPorep layers 2023-10-17 09:19:46 -04:00
Aayush 6187f6b7ac chore: deps: update to go-state-types v0.12.5 2023-10-17 09:12:54 -04:00
Łukasz Magiera d981baa362 storage: Return soft err when sector alloc fails in acquire 2023-10-17 11:42:41 +02:00
Aayush 40582335e9 feat: re-enable full cachefiles test coverage 2023-10-16 12:28:12 -04:00
Aayush 5e76b05b17 Merge branch 'feat/nv21' into asr/merge-feat-nv21 2023-10-16 11:13:33 -04:00
Łukasz Magiera 9fc3c3351a Merge pull request #9746 from filecoin-project/feat/maximize-feecap-cfg
feat: mpool/wdpost: Maximize feecap config
2023-10-13 14:22:58 +02:00
Aayush Rajasekaran 2b367225e4 Merge pull request #11321 from filecoin-project/asr/tweak-equivocation
feat: miner: defensive check for equivocation
2023-10-11 12:29:29 -04:00
Łukasz MagieraandAayush Rajasekaran 861134d923 mpool: Fix CapGasFee maxFee handling
Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com>
2023-10-11 16:49:00 +02:00
Aayush 00aad34194 messagepool: refactor CapGasFee logic to be cleaner 2023-10-10 11:20:26 -04:00
Aayush 7778fc2473 feat: miner: defensive check for equivocation 2023-10-10 10:15:04 -04:00
Łukasz Magiera 0787ff3bc3 Merge pull request #11315 from filecoin-project/fix/remove-ec1-bootstrappers
Remove PL's european bootstrap nodes from mainnet.pi
2023-10-09 13:00:55 +02:00
GlacierWalrus 46a3150784 Remove PL's european bootstrap nodes from mainnet.pi
Remove Protocol Labs's EU bootstrap nodes, as they've been decommissioned as
part of a cost reduction project.
2023-10-09 10:25:35 +00:00
Łukasz Magiera 1927b26abf fee config: Default MaximizeWindowPoStFeeCap to true 2023-10-03 11:53:26 +02:00
Łukasz Magiera 444e75ef77 feat: mpool/wdpost: Maximize feecap config 2023-10-03 11:32:49 +02:00
Łukasz Magiera 0e26a8d99b Merge pull request #11299 from criadoperez/fix/criadoperez
docs: Link the release section in the release flow doc
2023-10-02 11:06:45 +00:00
Friðrik Ásmundsson 3fd57ff7d9 Merge pull request #11270 from filecoin-project/benchmark-binaries
feat: Add lotus-bench cli option to stress test any binary
2023-09-28 10:15:06 +00:00
Friðrik Ásmundsson a791a795e9 Merge pull request #11276 from filecoin-project/setup-grafana-prometheus-docs
feat: Instructions for setting up Grafana/Prometheus for monitoring local lotus node
2023-09-28 10:14:30 +00:00
Fridrik Asmundsson 5b394f0f98 small fixes 2023-09-27 14:06:26 +00:00
Fridrik Asmundsson e0f90274e4 fix spelling 2023-09-27 14:03:50 +00:00
Alejandro 1d893d6630 Completed TODO in code 2023-09-26 13:03:46 +02:00
Łukasz Magiera d64bc2c9be Merge pull request #11294 from filecoin-project/phi-connect-listen-not-set
fix: worker: Connect when --listen is not set
2023-09-25 15:06:23 +02:00
Phi f1c70720df Handle both IPv4 and IPv6
use net.JoinHostPort(minerIP, minerPort) to handle both IPv4 and IPv6 addresses.
2023-09-25 14:38:59 +02:00
Phi 3f2d2eb659 Connect to newAddress
Connect to newAddress
2023-09-25 14:38:59 +02:00
Łukasz Magiera 121cd97f65 Merge pull request #11288 from cloudxin/patch-1
Update mainnet.pi
2023-09-25 13:21:31 +02:00
Łukasz Magiera a8d693a2c0 Merge pull request #11274 from filecoin-project/fix/update-splitstore-config-comments
fix: config: Update ColdStoreType comments
2023-09-22 15:36:54 +02:00
Phi e8570bd69c Remove double default
Remove double default
2023-09-22 15:24:55 +02:00
Łukasz Magiera ac85a2e23b Merge pull request #11171 from ipfs-force-community/opt/remove-repeat-check
opt: fix duplicate check exitcode
2023-09-22 14:52:34 +02:00
Łukasz Magiera 2acbdb43d7 Merge pull request #11225 from filecoin-project/update-go-libp2p-v031
update go-libp2p to v0.31.0
2023-09-22 14:49:01 +02:00
Łukasz Magiera 444da43228 Merge pull request #11255 from Aloxaf/Aloxaf-patch-2
fix: sealing: typo in FinalizeReplicaUpdate
2023-09-22 14:01:51 +02:00
Łukasz Magiera 99990504b5 Merge pull request #11263 from Icarus9913/libp2p/remove-deprecated-method
fix: deps: stop using go-libp2p deprecated peer.ID.Pretty
2023-09-22 13:59:18 +02:00
renran 2fc2875106 Update mainnet.pi
add venus node boostrap
2023-09-22 16:27:42 +08:00
Jie Hou c11a5bce59 Merge pull request #11277 from filecoin-project/0919_jie_flip_flags
Feat: Lotus Daemon CLI: Auto remove existing chain if importing chain file or snapshot
2023-09-21 11:25:58 -07:00
Jie Hou 49044b4c69 Address review comments, again 2023-09-21 10:00:03 -07:00
Aayush Rajasekaran 70cb445a12 Merge pull request #11273 from filecoin-project/fix/wrap-sign-error
fix: cli: Wrap error in wallet sign
2023-09-21 09:34:39 -04:00
Łukasz Magiera 30e4259eff Merge pull request #11275 from filecoin-project/add-vscode-to-gitignore
fix: Add .vscode to gitignore
2023-09-21 15:10:39 +02:00
Jie Hou 5b9914790c Fix lint 2023-09-21 02:15:26 -07:00
Jie Hou bdffac300a Add to changelog 2023-09-20 09:45:06 -07:00
Jie Hou 10a9eb2155 Address review comments 2023-09-20 09:33:53 -07:00
Fridrik Asmundsson 768b2b3812 Update README.md 2023-09-20 14:15:03 +00:00
Fridrik Asmundsson 113b8b5002 Fix after testing with ubuntu 2023-09-20 11:15:45 +00:00
Phi-rjanandŁukasz Magiera f7c254b3de Update cli/wallet.go
Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com>
2023-09-20 11:17:57 +02:00
Jie Hou 00335441ce Auto remove existing chain if importing chain file or snapshot 2023-09-19 11:24:12 -07:00
Fridrik Asmundsson 26e9703548 Add instructions for setting up Grafana+Prometheus
This PR also includes location where to put our grafana dashboards
which we should maintain in repo.
2023-09-19 17:24:02 +00:00
Phi 8b77839d38 Make gen
Make gen
2023-09-19 13:21:07 +02:00
Fridrik Asmundsson d23b96fc32 Add .vscode to gitignore 2023-09-19 10:57:32 +00:00
Phi e5f32f288d Update ColdStoreType comments
Update comments to say that "discard" is the default mode in SplitStore.
2023-09-19 12:32:41 +02:00
Phi 7e40f8636b Wrap error in wallet sign if msig
Wrap error when a msig is trying to sign a msg, explaining that msigs needs to propose & approve.
2023-09-19 10:57:35 +02:00
Friðrik Ásmundsson 8aaa8de975 Merge pull request #11269 from filecoin-project/throttle-splitstore-purging
fix: Add time slicing to splitstore purging to reduce lock congestion
2023-09-18 16:54:30 +00:00
Aayush Rajasekaran 35ceb02c50 Merge pull request #11261 from filecoin-project/eth_filert_flake_debug
eth_filter flake debug
2023-09-18 11:57:12 -04:00
Aayush Rajasekaran 89a0b25377 Merge pull request #11271 from filecoin-project/fix/unsealing-print
fix: cli: Add print to unseal cmd
2023-09-18 11:55:07 -04:00
Fridrik Asmundsson 2d7a9b0551 Moved work duration to a constant 2023-09-18 15:43:01 +00:00
Friðrik Ásmundsson 26b35b7f8e feat: Add ETA to lotus sync wait (#11211) 2023-09-15 10:29:27 -07:00
Fridrik Asmundsson 087d799547 Increase time spent pausing to 4sec 2023-09-15 10:57:43 +00:00
Phi 6892c35aec Add print to unseal cmd
Add print to unseal cmd
2023-09-15 09:22:18 +08:00
Fridrik Asmundsson 861731ee7c Add support to easily benchmark binary for understanding their latencies/histogram 2023-09-14 14:17:42 +00:00
Fridrik Asmundsson 131f87afb1 Update changelog 2023-09-14 13:58:01 +00:00
Fridrik Asmundsson d9755dfb1c Add time slicing ot splitstore purging to reduce lock congestion 2023-09-14 13:39:15 +00:00
Aayush Rajasekaran e06604d342 Merge pull request #11262 from filecoin-project/steb/fix-dial-spam
fix: networking: avoid dialing when trying to handshake peers
2023-09-12 10:35:22 -04:00
Icarus9913 2a8ea957fa stop using go-libp2p deprecated peer.ID.Pretty
Signed-off-by: Icarus9913 <icaruswu66@qq.com>
2023-09-12 13:13:34 +08:00
Aayush 89dede32ac drop unused imports 2023-09-11 13:50:55 -04:00
Steven Allen cfaeb2718f fix: networking: avoid dialing when trying to handshake peers
Also, avoid handshaking with peers that don't support the handshake
protocol.
2023-09-08 14:52:14 -07:00
Aayush Rajasekaran f06d67c5a2 Merge pull request #11253 from filecoin-project/shed/add-Mpool-select-timing
fix: shed: additional metrics in `mpool miner-select-messages`
2023-09-08 12:18:13 -04:00
Andrew Jackson (Ajax) 7ef93448fb eth_filter flake debug 2023-09-08 11:17:51 -05:00
Aayush Rajasekaran d70674c369 Merge pull request #11259 from filecoin-project/asr/quick-fix
fix: test: temporarily exempt SynthPorep constants from test
2023-09-08 12:17:17 -04:00
Aayush 45eb890917 fix: test: temporarily exempt SynthPorep constants from test 2023-09-08 11:51:30 -04:00
Aloxaf 0dd7976ffb fix: sealing: typo in FinalizeReplicaUpdate 2023-09-08 10:15:58 +08:00
Phi d771aa353e Update comment
Update comment
2023-09-07 11:27:28 +02:00
Phi 7c61e890c5 Add timing in miner-select-messages
Add timing in `lotus-shed mpool miner-select-messages` cmd. And printing amount of message in the mpool
2023-09-07 11:19:10 +02:00
Aayush Rajasekaran 8ab6eaa6e3 Merge pull request #11230 from filecoin-project/asr/test-seal-and-verify-3-needs-to-stop
feat: skip TestSealAndVerify3 until it's fixed
2023-09-06 14:48:38 -04:00
Aayush Rajasekaran 4ea712c011 Merge pull request #11241 from filecoin-project/asr/fix-miner-logs
fix: miner: correct duration logs in mineOne
2023-09-06 11:45:10 -04:00
Mikers 5e5a81bf23 add go linter - "unused" (#11235)
* add go linter - "unused"

* use _ to name unused but needed padding variable

* remove unused code

* add queue test to appease unused linter

* remove unused code in test

* remove unused func

* remove unused struct identified by linter

* remove unused variable

* remove unused code

* remove unused file

* remove unused struct

* remove unused function

* remove unused observe peers function in raft

* remove unused declareFaults function

* annotate nolint:unused on needed methods
2023-09-05 12:19:43 -10:00
Andrew Jackson (Ajax) ef9a9175a1 Merge pull request #11247 from filecoin-project/bumpTo1235
chore: build: bump master to v1.23.5-dev
2023-09-05 12:19:59 -05:00
Andrew Jackson (Ajax) 20266857e6 v1.23.5-assets 2023-09-05 12:08:30 -05:00
Andrew Jackson (Ajax) 14fba589bc 1235 2023-09-05 11:32:11 -05:00
Aayush 82b13afed6 fix: miner: correct duration logs in mineOne 2023-09-05 12:10:14 -04:00
Aayush Rajasekaran 9567dee00c Merge pull request #11228 from filecoin-project/asr/log-slow-block
feat: miner: log detailed timing breakdown when mining takes longer than the block's timestamp
2023-09-05 12:07:28 -04:00
Andrew Jackson (Ajax) 70895afa3e Merge pull request #11011 from filecoin-project/fix/snap-unseal
Snapdeals unsealing fixes
2023-09-05 10:25:34 -05:00
Phi-rjan 37b8afd197 Merge pull request #11224 from filecoin-project/fix/DataCid-env-check
fix: worker: Convert `DC_[SectorSize]_[ResourceRestriction]` if set
2023-09-05 12:44:35 +02:00
Jiaying Wang 4ded4cf49e Merge pull request #11232 from filecoin-project/update-changelog-pr-template
docs: Update PR template to callout remembering to update CHANGELOG
2023-09-01 18:33:35 -04:00
Andrew Jackson (Ajax) b73c016f6d unseal - comments 2023-09-01 17:15:56 -05:00
Aayush Rajasekaran d590c53400 Merge pull request #11157 from filecoin-project/asr/add-time-to-base
feat: miner: implement FRC-0051
2023-09-01 15:30:41 -04:00
Aayush 114a3bbf3f add some logs 2023-09-01 15:02:13 -04:00
Aayush b68ced7b19 address review 2023-09-01 15:01:22 -04:00
Aayush 43d1d62fc6 Make EquivocationDelaySecs a build param 2023-09-01 15:01:22 -04:00
Aayush 668d615be6 Add comments, re-select messages if refreshing base 2023-09-01 15:01:22 -04:00
Aayush 91d2c02765 feat: miner: implement FRC-0051 2023-09-01 15:01:22 -04:00
Fridrik Asmundsson 5fb41d7098 Update PR template to callout remembering to update CHANGELOG 2023-09-01 18:17:28 +00:00
Aayush b92cff74f2 feat: skip TestSealAndVerify3 until it's fixed 2023-09-01 10:08:55 -04:00
Aayush f3b3ff0dd2 feat: miner: log detailed timing breakdown when mining takes longer than the block's timestamp 2023-08-31 10:28:38 -04:00
Jennifer Wang 7e6da3d76f rebase 2023-08-31 09:51:52 -04:00
Jennifer Wang 0d5c99cb3c revert some ffi updates 2023-08-31 09:46:10 -04:00
Łukasz Magiera 077f3f0c33 ffiwrapper: Fix sector key regen 2023-08-31 09:46:10 -04:00
Łukasz Magiera 8ea44e82d1 ffiwrapper: Correctly create unsealed file when doesn't exist 2023-08-31 09:46:10 -04:00
Łukasz Magiera e74eb6af09 make the linter happy 2023-08-31 09:46:10 -04:00
Jennifer Wang ad6b0575c1 make gen, mod tidy 2023-08-31 09:46:10 -04:00
Łukasz Magiera a965fc660e fix build 2023-08-31 09:46:10 -04:00
Jennifer Wang 4b78c4ea1e ffiwrapper: Fix sector acquire logic in unsealing 2023-08-31 09:46:10 -04:00
Łukasz Magiera 6167bcc8ce ffiwrapper: Fix sector acquire logic in unsealing 2023-08-31 09:46:10 -04:00
Łukasz Magiera fa0f117edd ffiwrapper: Fix multiple bugs in snapdeals unsealing 2023-08-31 09:46:10 -04:00
Łukasz Magiera bcc2d7fd10 ffiwrapper: Fix RegenerateSectorKey 2023-08-31 09:46:10 -04:00
Jennifer Wang b0b39424e4 ffiwrapper: Test lower-level GenerateSDR 2023-08-31 09:46:10 -04:00
Marten Seemann 41dd8954aa update go-libp2p to v0.31.0 2023-08-31 11:18:17 +07:00
Aayush Rajasekaran d71d647aaf Merge pull request #11100 from filecoin-project/traceapi
Add new tracing API
2023-08-30 11:34:06 -04:00
Phi f3da600b28 Make lint-happy
Make lint-happy
2023-08-30 11:32:20 +02:00
Phi 20fe979857 Check if DC_[SectorSize]_[ResourceRestriction] is set
Check if DC_[SectorSize]_[ResourceRestriction] is set and convert to DC_[ResourceRestriction] to make sure its enforced by the scheduler.
2023-08-30 11:14:13 +02:00
Łukasz Magiera cf0ff92008 Merge pull request #11214 from filecoin-project/rvagg/one-and-only-one-ROOT
fix(client): single-root error message
2023-08-30 09:37:40 +02:00
Aayush Rajasekaran 9d9de747a9 Merge pull request #11221 from filecoin-project/ci/go1.20
fix: dockerfile: Bump to Go 1.20.7 image
2023-08-29 14:24:05 -04:00
Łukasz Magiera 1e8e63e39e fix: dockerfile: Bump to Go 1.20.7 image 2023-08-29 18:58:36 +02:00
Fridrik Asmundsson 0096d521c3 fix decoding toplevel output in trace_replayBlockTransactions 2023-08-29 12:27:08 +00:00
Fridrik Asmundsson 144bbdfd3b Added trace api as experimental feature to changelog 2023-08-29 11:26:52 +00:00
Fridrik Asmundsson 13e1b4b3df Added todo to support native actors calling another when created 2023-08-29 10:38:21 +00:00
Rod Vagg b6fe914748 fix(client): single-root error message 2023-08-29 14:46:39 +10:00
Fridrik Asmundsson 930e9b957c fix lint 2023-08-28 18:47:45 +00:00
Fridrik Asmundsson 57e825901e Update FFI 2023-08-28 17:51:47 +00:00
Fridrik Asmundsson aef0ecf2d2 Run make gen 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson ed407689e6 Parse input/output for delegate call + other smaller things 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 029a4a72b8 Address most recent comments 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 10a5480895 Decode output using top level trace 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson ee3cdf0e97 Fix use filecoin addr + other small refactor
After changing in prev commit to use to ethereum addresses the
comparison does not make sense against builtin actors. This
fixes that by storing also the filecoin addresses in each trace

Also renamed filecoin related fields to Filecoin prefix.

Also remove requirement call to InvokeContract needed to come
from a evm actor
2023-08-28 17:48:22 +00:00
Fridrik Asmundsson cf255127a4 Decode eth param/return values and change them to ethbytes type 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson cb5e6e0cd1 The From/To address should be in eth format 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 8d8891a431 Moved tracing types to ethtypes to address circular dependencies 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson ef7bcfec06 Do not compute message index as traces should be in message execution order 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson a1b890c8c7 return wrapped errors 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 4068e0710d Do not return interface{} from trace api methods 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson ebb54bc381 fix naming lint 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson ba1ee60d1b Refactor eth.go 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 7f99d15071 Small refactor and cleanup 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson fd69f8bbd8 Check all errors 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson abeb842d93 Address lint errors 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 392ef1beb7 Handle delegatecall 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 2c902db0e1 Handle more edge cases 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson c1eaa2f864 Translate call input/output into Solidity ABI 2023-08-28 17:48:22 +00:00
Fridrik Asmundsson 1b0f54a61b Add new tracing API 2023-08-28 17:48:22 +00:00
Aayush Rajasekaran c4214e23bf Merge pull request #11206 from AnomalRoil/fix/ctxonlongops
fix: chain: cancel long operations upon ctx cancelation
2023-08-28 13:33:08 -04:00
Aayush Rajasekaran a79f96a531 Merge pull request #11212 from filecoin-project/fix/master-cli-ci
ci: Use larger executor for cli tests
2023-08-28 10:28:50 -04:00
Łukasz Magiera f8faa85cba make gen 2023-08-28 16:12:14 +02:00
Łukasz Magiera d83956aa6d ci: Ensure params in sealer tests 2023-08-28 13:43:50 +02:00
Łukasz Magiera 4223e411b6 ci: Use larger executer for cli tests 2023-08-28 13:24:00 +02:00
Łukasz Magiera bce5535679 Merge pull request #11182 from filecoin-project/TestSealerDLBefore
Take Download out of Sealer time
2023-08-25 10:27:42 +02:00
Aayush Rajasekaran 1c9344d805 Merge pull request #11202 from gammazero/fix/update-cached-message-sequence
fix: chain: Do not update message info cache until after message validation
2023-08-24 10:59:47 -04:00
Łukasz Magiera ae2ae3b9ed Merge pull request #11189 from filecoin-project/update-go-libp2p-v0300
update go-libp2p to v0.30.0
2023-08-24 16:15:26 +02:00
Yolan Romailler 13ade62e27 fix: cancel long operations upon ctx cancelation 2023-08-24 15:30:33 +02:00
Aayush Rajasekaran 50cd87e953 Merge pull request #11201 from filecoin-project/asr/merge-nv21
chore: merge feat/nv21 into master
2023-08-24 09:25:45 -04:00
Łukasz Magiera 366329b085 Merge pull request #11087 from filecoin-project/fix/pc1-retr-loop
fix: sealing pipeline: Fix PC1 retry loop
2023-08-24 11:08:39 +02:00
gammazero 03826aac87 fix doc check 2023-08-23 19:05:21 -07:00
gammazero 7774ca0179 Add sequence number DoS test 2023-08-23 16:53:21 -07:00
gammazero ca23a4406c Do not update message info cache until after message validation
The sequence number used for replay detection was being updated before message validation confirmed that the message originated from the correct host. This would allow one host A to create a message with the ID of another host B that could then update the cached sequence number for B. While the message from A would fail validation and be ignored, the cached sequence number for B would get updated. This would lead to a temporary DoS for host B as its messages were incorrectly rejected as replays.

This fixes the issue by setting the cached sequence number after message validation.
2023-08-23 14:30:22 -07:00
Aayush 5bfea36a17 Merge branch 'feat/nv21' into asr/merge-nv21 2023-08-23 11:44:59 -04:00
Łukasz Magiera 882f00fbf3 sealing: retrySoftErr: Better comment on ctx handling 2023-08-23 17:29:18 +02:00
Marten Seemann 413008a98f bump qtls to v0.3.3 2023-08-23 11:43:02 +07:00
Aayush Rajasekaran 0ff655a0a0 Merge pull request #11196 from filecoin-project/chore/update-test-vectors
chore: test-vectors: update
2023-08-22 16:59:01 -04:00
Steven Allen d581f58896 chore: test-vectors: update
Update the test-vectors repo to the "last" release. This release deletes
most of the code (that depended on an ancient version of lotus anyways)
as we now rely on the "fvm" test vectors for all but historical tests.
2023-08-22 13:17:46 -07:00
Aayush Rajasekaran 62f52c672c Merge pull request #11194 from filecoin-project/steb/fix-tagged-releases
fix: build: use tagged releases
2023-08-22 15:37:15 -04:00
Steven Allen eae61009b0 fix: build: use existing upstream branches
Unfortunately, we can't _yet_ merge the schema branch. But we will in a
moment. But this at least fixes go-state-types

These dependencies were based on branches which no longer exist.
2023-08-22 11:56:37 -07:00
Aayush Rajasekaran 7491956197 Merge pull request #11167 from filecoin-project/asr/randomness
feat: refactor: return randomness base to FVM without hashing
2023-08-22 12:15:24 -04:00
Aayush 2f113e58ca fix tvx 2023-08-22 12:03:26 -04:00
Aayush 7e6ed09628 refactor: move vm.Rand to rand.Rand 2023-08-22 11:34:28 -04:00
Aayush c90faf0754 fixup conformance tests to incorporate randomness changes 2023-08-22 10:08:38 -04:00
Łukasz Magiera 5281a6d307 Merge pull request #11188 from filecoin-project/shed-msg-add-exec-trace
feat: shed: Add exec traces to `lotus-shed msg`
2023-08-22 13:50:29 +02:00
Łukasz Magiera 5f5c6a08a4 Merge pull request #11191 from filecoin-project/nonsense/remove-trace-goroutine
fix: markets/dagstore: remove trace goroutine for dagstore wrapper
2023-08-22 12:30:13 +02:00
Phi 825064669d Continue if msg not found on-chain
Continue if msg not found on-chain
2023-08-22 10:56:50 +02:00
Aayush 034f6cf832 wip: 2 more randomness fetching APIs 2023-08-21 16:32:27 -04:00
Aayush 91ee13b461 fix: refactor rand_replay 2023-08-21 16:28:59 -04:00
Aayush e5fbba7958 Refactor: Rand: Return randomness digest to VM 2023-08-21 15:44:49 -04:00
Aayush 98a82d3dfe Refactor: Rand: Rename DrawRandomness to DrawRandomnessFromBase 2023-08-21 15:03:46 -04:00
Aayush 05ac9453cd Refactor: Rand: return randomness base without hashing 2023-08-21 15:03:46 -04:00
Andrew Jackson (Ajax) cb7231cb8a Merge pull request #11177 from filecoin-project/sbansal/unseal-background
fix: sealing: Run unsealing in the background for better ux
2023-08-21 11:37:59 -05:00
Anton Evangelatov 9028df409c fix: markets/dagstore: remove trace goroutine for dagstore wrapper 2023-08-21 17:55:45 +02:00
Łukasz Magiera 1fe7493897 Merge pull request #11183 from LexLuthr/lexluthr/ddo-gateway
#11181: feat: Lotus Gateway: add allocation and claim related GET APIs to gateway
2023-08-21 16:06:15 +02:00
Phi e1ed24ddd0 Put exec-trace behind flag
Put exec-trace behind flag
2023-08-21 13:55:49 +02:00
Łukasz Magiera 92f31ee0be Merge pull request #11187 from filecoin-project/fix/lotus-wallet-build
fix: build: Allow lotus-wallet to be built independently
2023-08-21 13:39:31 +02:00
Łukasz Magiera 2ee879d1ec Merge pull request #11190 from filecoin-project/fix/wallet-sigint
fix: wallet: Make import handle SIGINT/SIGTERM
2023-08-21 13:38:23 +02:00
Phi 5edc7dcdb3 Consider SIGTERM as well
Consider SIGTERM as well
2023-08-21 10:37:42 +02:00
Marten Seemann c42e57b51c downgrade go.mod to Go 1.19 2023-08-21 15:02:37 +07:00
Marten Seemann 93f95d2ef9 Revert "stop using deprecated functions from the math/rand package"
This reverts commit d50cf4eb64.
2023-08-21 15:02:06 +07:00
Phi c1fd48a14b Make lotus wallet import respect sigint
Make `lotus wallet import` respect sigint
2023-08-21 09:10:47 +02:00
Marten Seemann d50cf4eb64 stop using deprecated functions from the math/rand package 2023-08-21 13:53:46 +07:00
Marten Seemann bca0ec4f9c update go-libp2p v0.30.0 2023-08-21 10:44:37 +07:00
Phi 539a524271 Make exec-trace human readable
Make exec-trace human readable
2023-08-20 20:11:27 +02:00
Phi 51be40291a Add BUILD_DEPS to lotus-wallet
Add BUILD_DEPS to lotus-wallet
2023-08-20 19:58:33 +02:00
Phi c1231125e9 Print receipt
Print receipt
2023-08-20 19:54:17 +02:00
Phi 925498f938 Add exec-trace and receipt
Add exec-trace and receipt to the lotus-shed msg command
2023-08-20 10:06:00 +02:00
LexLuthr bcc8b9d02f add allocation and claim APIs 2023-08-18 11:28:01 +04:00
Andrew Jackson (Ajax) c48bf864a4 Take Download out of Sealer time 2023-08-17 22:34:08 -05:00
Aayush Rajasekaran cbbb76b2f0 Merge pull request #11169 from filecoin-project/asr/client-can-allocate
feat: test: Test that verified clients can directly transfer datacap, creating allocations
2023-08-17 09:51:12 -04:00
Aayush e8020e8f4e feat: test: Test that verified clients can directly transfer datacap, creating allocations 2023-08-17 09:40:29 -04:00
Łukasz Magiera 23cd5832c7 Merge pull request #11180 from filecoin-project/macSealTest
mac seal test
2023-08-17 15:10:37 +02:00
Andrew Jackson (Ajax) 76bca6c392 mac seal test 2023-08-17 07:30:19 -05:00
Shrenuj Bansal 9e69576410 log unseal failures 2023-08-16 17:40:27 -04:00
Shrenuj Bansal 38350b8d8a Run unsealing in the background for better ux 2023-08-16 17:20:39 -04:00
Łukasz Magiera 80928586d1 Merge pull request #11140 from filecoin-project/fix/wallet-balance-cmd
fix: cli: Only display `warning` if behind sync
2023-08-16 15:57:34 +02:00
Łukasz Magiera 22f490132e Merge pull request #11141 from filecoin-project/fix/worker-IPv6
fix: worker: Support IPv6 formatted API-keys
2023-08-16 15:55:05 +02:00
Łukasz Magiera c46aea6a36 Merge pull request #11164 from filecoin-project/go-libp2p-v029
update go-libp2p to v0.29.2
2023-08-16 12:15:52 +02:00
Aayush Rajasekaran b226a7dbff Merge pull request #11159 from filecoin-project/asr/fix-frc-0051
fix: chainstore: do not get stuck in unhappy equivocation cases
2023-08-15 13:58:26 -04:00
simlecode a750e63a7b opt: fix duplicate check exitcode 2023-08-15 16:28:03 +08:00
Łukasz Magiera 33182967eb Merge pull request #11142 from filecoin-project/feat/act-precommv2
sealing: Switch to calling PreCommitSectorBatch2
2023-08-14 21:31:24 +02:00
Łukasz Magiera b11fba3561 itests: Port deadline-toggling itest to nv20 2023-08-14 20:25:36 +02:00
Marten Seemann 2f0fbe26f8 update go-libp2p to v0.29.2 2023-08-14 18:46:28 +07:00
Aayush 12e076e9ea fix: chainstore: do not get stuck in unhappy equivocation cases 2023-08-11 17:32:39 -04:00
Aayush Rajasekaran 7b43f90a3b Merge pull request #11158 from filecoin-project/asr/miner-refactors
feat: miner: 2 minor refactors
2023-08-11 13:20:25 -04:00
Aayush 3566e96b55 refactor: pass more specialized params to computeTicket 2023-08-11 09:52:26 -04:00
Aayush 20e831b9ea refactor: drop unused param from IsRoundWinner 2023-08-11 09:48:09 -04:00
Łukasz Magiera 2c7c4ee845 Merge pull request #11155 from filecoin-project/asr/deflake
feat: deflake: TestGetBlockByNumber
2023-08-11 12:52:59 +02:00
Aayush Rajasekaran 49010a9b9a Merge pull request #11104 from filecoin-project/asr/frc-0051
feat: chainstore: FRC-0051: Remove all equivocated blocks from tipsets
2023-08-09 21:50:10 -04:00
Aayush 69f3580ca2 add more test cases covering chainstore equivocation 2023-08-09 21:00:50 -04:00
Aayush Rajasekaran 1da18e8058 Merge pull request #10987 from simlecode/feat/add-Eip155ChainID
feat: add Eip155ChainID to StateGetNetworkParams
2023-08-09 20:02:05 -04:00
Aayush 2cbdedc209 add more test cases covering chainstore equivocation 2023-08-09 19:40:53 -04:00
Aayush 0ff334912b Address review 2023-08-09 19:28:24 -04:00
Aayush 52657c5cb0 feat: chainstore: FRC-0051: Remove all equivocated blocks from tipsets 2023-08-09 19:28:24 -04:00
Aayush 62032e7c2a feat: deflake: TestGetBlockByNumber 2023-08-09 19:25:32 -04:00
Aayush Rajasekaran 93b0ea2108 Merge pull request #11154 from filecoin-project/asr/merge-releases-into-master
chore: merge releases into master
2023-08-09 18:23:55 -04:00
Aayush 32f21258a1 Merge branch 'releases' into asr/merge-releases-into-master 2023-08-09 18:11:18 -04:00
Aayush Rajasekaran bcde3bd60e Merge pull request #11152 from filecoin-project/steb/eth-gateway-filter-id-error
fix: gateway: return an error when an Eth filter is not found
2023-08-09 17:25:03 -04:00
Phi 3cec54f774 Make TestWalletBalance happy
Set up an expected call to ChainHead
2023-08-09 21:25:52 +02:00
Steven Allen a626b3e62c fix: gateway: return an error when an Eth filter is not found
Previously, we'd just return nothing.
2023-08-09 12:14:45 -07:00
Phi 18ae6bd18b Unify IsSyncDone
Unify IsSyncDone in cli/sync.go and cli/wallet.go
2023-08-09 17:13:25 +02:00
Aayush Rajasekaran 9310cd6036 Merge pull request #11147 from filecoin-project/asr/fix-test-rest
fix: CI: make test-unit-rest actually be the rest of the tests
2023-08-08 15:38:29 -04:00
Aayush Rajasekaran 0c34deb884 fix: CI: make test-unit-rest actually be the rest of the tests 2023-08-08 14:13:44 -04:00
Łukasz Magiera aa7220d9e8 itests: Drop sealing itests for legacy network versions 2023-08-08 18:51:30 +02:00
Aayush Rajasekaran 87458af858 Merge pull request #11145 from filecoin-project/update-logging
fix: downgrade harmless warning to debug
2023-08-08 12:22:09 -04:00
nemo c6d31c0d6d fix: downgrade harmless warning to debug 2023-08-08 10:52:35 -04:00
Łukasz Magiera 98aff9dcc6 sealing pipeline: Only set pc commd when deals are present 2023-08-08 15:35:19 +02:00
Łukasz Magiera 40cfe626b8 sealing pipeline: Set commd in precommit params 2023-08-08 15:12:50 +02:00
Łukasz Magiera 41fac326b1 sealing pipeline: Fix unit tests 2023-08-08 15:06:43 +02:00
Łukasz Magiera a4d22f585f sealing pipeline: Drop legacy single-pc1 submit path 2023-08-08 14:43:00 +02:00
Łukasz Magiera bb2ac5c22d ci: Drop legacy cc-replace itests 2023-08-08 13:53:24 +02:00
Phi 94e48ae860 Add IPv6 check and format appropriately
Add IPv6 check and format appropriately
2023-08-08 13:18:36 +02:00
Łukasz Magiera 1c73ac69b4 pc batch: drop individual precommit processing 2023-08-08 13:04:21 +02:00
Phi c4798a604a Make lint happy
Address the errcheck lint error by checking the return from conn.Close()
2023-08-08 12:49:04 +02:00
Łukasz Magiera ef2be0b546 sealing: pc batch: Call PreCommitSectorBatch2 2023-08-08 12:40:08 +02:00
Phi b6ba3b23bb fix: worker: Support IPv6
Add support for IPv6 in MINER_API_INFO env.
2023-08-08 12:21:59 +02:00
Phi 826ef40626 Only display chain sync in progress if behind sync
Only display `chain sync in progress` if behind sync
2023-08-08 10:06:19 +02:00
Łukasz Magiera 884246677b Merge pull request #11046 from filecoin-project/fix/fsm-commfail-loop
fix: sealing: Fix RetryCommitWait loop when sector cron activation fails
2023-08-07 12:11:57 -07:00
Łukasz Magiera f620310bfe address review 2023-08-02 17:04:58 +02:00
Łukasz Magiera 683432e6e0 Merge pull request #11119 from filecoin-project/chore/cleanup-compunscid
chore: legacy syscalls: Cleanup ComputeUnsealedSectorCID
2023-08-02 06:45:35 -07:00
Aayush Rajasekaran d082940d54 Merge pull request #11126 from filecoin-project/feat/move-cons-slasher
feat: chain node: Move consensus slasher to internal service
2023-08-01 11:59:40 -04:00
Łukasz Magiera fe7cf0c39a feat: chain node: Move consensus slasher to internal service 2023-08-01 17:34:44 +02:00
Łukasz Magiera 6636da1299 itests: Use Must-Post mining in TestDealsWithSealingAndRPC 2023-08-01 16:34:21 +02:00
Łukasz Magiera 9b4992b834 Merge pull request #11123 from mtrisic/fix/sector-import-randomness-mismatch
sector import: fix evaluating randomness when importing a sector
2023-08-01 04:40:18 -07:00
Mladen Trišić 9459c612fb sector import: fix evaluating randomness when importing a sector passing SubmitCommit state 2023-08-01 12:05:39 +02:00
Łukasz Magiera 8ce69d1397 Merge pull request #11121 from filecoin-project/asr/fix-test
fix: failing test: Tweak TestWindowPostV1P1NV20 test condition
2023-08-01 01:59:08 -07:00
ZenGround0 d900acc506 Merge pull request #11078 from filecoin-project/shed/zip-partition-info
feat:shed:gather partition metadata
2023-07-31 18:18:16 -04:00
Aayush b88e4abe05 fix: failing test: Tweak TestWindowPostV1P1NV20 test condition 2023-07-31 16:07:09 -04:00
Aayush Rajasekaran 8e56357450 Merge pull request #11120 from filecoin-project/asr/shut-up-disputer
feat: FVM: do not error on unsuccessful implicit messages
2023-07-31 15:37:12 -04:00
Aayush cd958e4f6e feat: FVM: do not error on unsuccessful implicit messages 2023-07-31 15:26:37 -04:00
zenground0 482c90412d Lint 2023-07-31 11:12:56 -06:00
zenground0 6a07def34a gen 2023-07-31 10:53:07 -06:00
Łukasz Magiera bf36ca93bb legacy syscalls: Cleanup ComputeUnsealedSectorCID 2023-07-31 12:43:47 +02:00
simlecode c3f421a9cd feat: add Eip155ChainID to StateGetNetworkParams 2023-07-28 16:03:59 +08:00
Friðrik Ásmundsson 3f93b86ebe Merge pull request #11088 from filecoin-project/backfill-events-cli
Add new lotus-shed command for backfillling actor events
2023-07-25 10:43:40 +00:00
Fridrik Asmundsson 719215122b Address PR feedback and move each epoch inside own tx 2023-07-24 14:18:31 +00:00
Fridrik Asmundsson 8a5950b3e9 Add new lotus-shed command for backfillling actor events 2023-07-24 11:37:30 +00:00
zenground0 df17f709a4 Record faulty status of sectors 2023-07-21 13:07:25 -06:00
Aayush Rajasekaran 977390e3c0 Merge pull request #11082 from filecoin-project/asr/fixup-rlpdecode
fix: ethtypes: handle length overflow case
2023-07-21 12:37:20 -04:00
Aayush 990b5a0bad fix: ethtypes: handle length overflow case 2023-07-21 12:26:29 -04:00
zenground0 8c4e705df3 Count all precommit sector numbers that we are checking 2023-07-21 09:30:45 -06:00
zenground0 2776e29042 Gather info about overhead operations in deadline summary 2023-07-21 08:53:24 -06:00
ZenGround0 15faab8412 Merge pull request #11075 from filecoin-project/bench/amt-churn
feat:lotus-bench:AMT benchmarking
2023-07-20 19:27:27 -04:00
zenground0 4d8f8d2600 Review Response 2023-07-20 16:59:11 -06:00
Phi-rjan 9624dc53f8 Merge pull request #11032 from filecoin-project/feat/remove-existing-chain 2023-07-20 18:41:25 +02:00
Łukasz Magiera 0a83896589 sealing pipeline: Better retry for soft errors 2023-07-19 09:51:59 -07:00
Łukasz Magiera d127208b85 sealing pipeline: Fix PC1 retry loop 2023-07-18 13:04:06 -07:00
Aayush Rajasekaran 2ddb52e103 feat: daemon: import: only setup stmgr if validating chain (#11084) 2023-07-18 08:03:34 -10:00
Aayush Rajasekaran d40946fb8c Merge pull request #11081 from filecoin-project/steb/bare-cbor
feat: vm: allow raw "cbor" in state and use the new go-multicodec
2023-07-18 12:53:44 -04:00
Aayush Rajasekaran 9e5e77b778 Merge pull request #11083 from filecoin-project/asr/shut-up
chore: stmgr: migrations: do not log noisily on cache misses
2023-07-18 10:33:39 -04:00
Aayush e17af657da chore: stmgr: migrations: do not log noisily on cache misses 2023-07-18 10:22:30 -04:00
Steven Allen 1fc47eb7d8 feat: vm: allow raw "cbor" in state and use the new go-multicodec
1. Switch to go-multicodec as the source of multicodec code information.
This gives us a central, generated source of multicodec codes.
2. Use this library inside the VM and shapshot logic to consistently
allow CBOR, in addition to DagCBOR.
3. Remove the hard-coded CBOR constant.
2023-07-17 11:24:01 -07:00
Aayush Rajasekaran 3af9fde0b4 Merge pull request #11080 from filecoin-project/asr/fix-drand-sched
fix: daemon: set real beacon schedule when importing chain
2023-07-17 14:13:47 -04:00
Aayush 09b566dde1 fix: daemon: set real beacon schedule when importing chain 2023-07-17 09:36:41 -04:00
Aayush Rajasekaran a1ded51024 Merge pull request #10998 from filecoin-project/update-libp2p-v028
chore: update go-libp2p to v0.28.1
2023-07-17 09:33:10 -04:00
Aayush e197d27f20 chore: deps: update go-libp2p to v0.28.1 2023-07-15 11:39:17 -04:00
Friðrik Ásmundsson 23d705e33b Merge pull request #11079 from filecoin-project/11053-decoderlp-panic
fix: DecodeRLP can panic
2023-07-15 11:13:14 +00:00
Fridrik Asmundsson 871d1ba547 fix: DecodeRLP can panic 2023-07-14 11:49:50 +00:00
Łukasz Magiera 03078cdb56 Merge pull request #11059 from filecoin-project/asr/deflake
feat: deflake: Use MockProofs
2023-07-14 09:19:18 +02:00
zenground0 38b21a713a Lint 2023-07-13 08:41:34 -06:00
zenground0 6eadc0ee57 gen 2023-07-13 07:37:51 -06:00
zenground0 eaf0200fe1 amt bench in good state 2023-07-12 23:58:02 -06:00
Aayush Rajasekaran 5aeb27ed94 Merge pull request #11063 from storswiftlabs/slasher
feat: daemon: improvemens to the consensus slasher
2023-07-12 16:59:30 -04:00
Aayush Rajasekaran 807a5dbaa8 Merge pull request #11016 from filecoin-project/sbansal/invert-validation-switch-checks
refactor: Make all validation error actions explicit
2023-07-11 11:31:40 -04:00
Aayush Rajasekaran 25c591fd6c Merge pull request #11064 from filecoin-project/11056-speedup-event-migration
fix: events: Improve performance of event migration from V1 to V2
2023-07-11 10:23:14 -04:00
Fridrik Asmundsson 0d7621be56 Add tmp indices to events table while performing migration to V2
After the migration we also perform db administration on the
events DB to reduce its file size on disk.
2023-07-11 10:16:47 +00:00
mx e9f57ae77f feat: daemon: improvemens to the consensus slasher 2023-07-11 16:40:28 +08:00
zenground0 9bd0e9ed58 Fix classic bug 2023-07-10 16:32:37 -06:00
zenground0 3f4429a5ef match json parsing 2023-07-10 16:00:03 -06:00
zenground0 921bdb85ab correct json parsing of addr 2023-07-10 15:54:07 -06:00
zenground0 921e5520ea debug 2023-07-10 15:32:19 -06:00
zenground0 cff7716707 Tool for measuring partition summaries 2023-07-10 15:28:14 -06:00
Shrenuj Bansal d463abae2f Merge pull request #11000 from filecoin-project/sbansal/update-release-template
chore: Extract stable release and post release portion outside of RC testing in template
2023-07-10 10:54:45 -04:00
Aayush Rajasekaran 3f71298c4b Merge pull request #11054 from filecoin-project/asr/max-event-length
feat: types: apply a max length when decoding events
2023-07-10 10:37:30 -04:00
Aayush Rajasekaran 7a93a70e6e Merge pull request #11060 from filecoin-project/asr/slasher-improvements
feat: slasher: improve UX
2023-07-10 10:30:18 -04:00
Aayush 5d072409f8 feat: deflake: Use MockProofs 2023-07-10 10:26:51 -04:00
Shrenuj Bansal cbbd7dea0c Merge pull request #11058 from filecoin-project/sbansal/add-prune-metrics
feat: Add a metric to display pruning of the node's peer
2023-07-10 09:45:41 -04:00
Aayush 4bc032430b feat: slasher: improve UX 2023-07-08 13:40:38 -04:00
Aayush Rajasekaran e58b1dfda2 Merge pull request #10979 from filecoin-project/asr/slasher-improvements
feat: daemon: improvemens to the consensus slasher
2023-07-08 13:05:34 -04:00
Aayush 7180b52d2c feat: improvements to the consensus slasher 2023-07-08 11:21:35 -04:00
Aayush 802a9f0a78 feat: refactor slashfilter to return bool indicating fault 2023-07-08 11:14:41 -04:00
Aayush 4cfdf8e83c feat: slasher: print error on failure 2023-07-08 11:14:41 -04:00
Aayush 07965467ee feat: fvm: apply a max length when decoding events 2023-07-08 11:05:01 -04:00
Shrenuj Bansal e54b32208c fix 2023-07-07 14:17:21 -04:00
Shrenuj Bansal 1b61d13733 Add temp debug logging 2023-07-07 13:51:15 -04:00
Shrenuj Bansal 60ee56a23e Add a metric to display pruning of the node's peer 2023-07-07 10:41:36 -04:00
ZenGround0 1358d70128 Merge pull request #11012 from filecoin-project/feat/stat-snapshot
feat:profiling:state summary and visualization
2023-07-06 16:28:05 -04:00
Łukasz Magiera 537d31416e Merge pull request #11031 from filecoin-project/feat/shed-block-json
feat: shed: command for decoding block headers
2023-07-06 11:55:02 +02:00
Łukasz Magiera e30f8af2d1 make gen 2023-07-06 09:35:10 +02:00
Łukasz Magiera 402895fdf0 itests: Test too-slow sector sealing cleanup 2023-07-06 09:27:09 +02:00
Łukasz Magiera a5f66b5605 Merge pull request #11045 from filecoin-project/fix/tune-down-log-lvl
fix: stores: Tune down StorageDeclareSector` log-lvl
2023-07-06 08:21:13 +02:00
Łukasz Magiera a03746c5df Merge pull request #11047 from filecoin-project/arajasek-patch-2
feat: docs: include FFI steps in lotus RELEASE_ISSUE_TEMPLATE
2023-07-06 08:19:39 +02:00
Shrenuj Bansal bc5637c60a keep default action as reject and make all error actions explicit 2023-07-05 12:13:01 -04:00
Aayush Rajasekaran 4240990c6c Merge pull request #11049 from filecoin-project/asr/v1.23.4
chore: build: update to v1.23.4-dev
2023-07-04 17:21:35 -04:00
Jiaying Wang 1a2a2314b3 Update and rename epic.md to task.md 2023-07-04 16:26:15 -04:00
Jiaying Wang 8ad89188fe Create epic.md 2023-07-04 16:24:30 -04:00
Aayush 13a65fdf56 feat: docs: add more steps to the release template 2023-07-04 16:08:21 -04:00
Aayush 126869ed98 chore: build: update to v1.23.4-dev 2023-07-04 15:51:09 -04:00
Aayush Rajasekaran d5ae0905f9 feat: docs: include FFI steps in lotus RELEASE_ISSUE_TEMPLATE 2023-07-04 15:03:58 -04:00
Łukasz Magiera 9b52b06ea9 fix: sealing: Fix RetryCommitWait loop when sector cron activation fails 2023-07-04 13:35:49 +02:00
Phi 2061c32a2e Check error
Check error
2023-07-04 11:53:28 +02:00
Phi dedfa143ce Extract removeExistingChain to seperate func
Extract removeExistingChain to seperate func
2023-07-04 11:30:06 +02:00
Phi 13224e3e0b Remove unused function
Remove unused clearSplitStoreDir function
2023-07-04 11:07:50 +02:00
Phi 8220e7f82f Tune down log-lvl
Tune down log-lvl
2023-07-04 09:35:49 +02:00
Łukasz Magiera 7b21420831 feat: shed: command for decoding block headers 2023-06-30 14:24:07 +02:00
Phi 5201744199 feat: snapshot: remove existing chain
Remove existing chain on a snapshot-import

log info instead of print

log info instead of print

Remove defer lock

Remove defer lock, and explicitly close the lockedRepo instead
2023-06-30 14:14:16 +02:00
zenground0 3f0ddcc553 Cleanup plotting script 2023-06-29 13:22:16 -06:00
zenground0 ab72f2e230 Lint 2023-06-28 22:35:28 -06:00
Shrenuj Bansal be3281bdcf Invert msg validation check to explicitly specify reject errors 2023-06-28 13:35:21 -04:00
zenground0 d2b2fba799 Remove debug pprof serving 2023-06-28 10:11:47 -06:00
zenground0 3cacbdfa18 Lint fixes 2023-06-28 09:52:47 -06:00
zenground0 016661b657 More cleanup 2023-06-28 09:17:57 -06:00
zenground0 3897bf14d1 Cleanup 2023-06-28 09:15:38 -06:00
zenground0 0cfdc9b5b6 Refactor for cleanup + measure top level HAMT churn 2023-06-27 17:57:00 -06:00
zenground0 77ea7ef90d Tweak path stuff 2023-06-27 11:29:14 -06:00
zenground0 4aa977f119 Touch up pathing 2023-06-27 11:00:20 -06:00
zenground0 8f3123d75b Churn json output is working 2023-06-27 00:54:02 -06:00
zenground0 36a88f45fc Output is buggy but halfway there 2023-06-25 17:36:21 -06:00
zenground0 d599833b64 WIP 2023-06-25 15:55:41 -06:00
Shrenuj Bansal 5f6977af1a Extract stable release and post release portion outside of RC testing in template 2023-06-21 09:44:37 -04:00
175 changed files with 7105 additions and 2369 deletions
+7 -3
View File
@@ -7,12 +7,12 @@ executors:
golang:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.19.12
- image: cimg/go:1.20.7
resource_class: medium+
golang-2xl:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.19.12
- image: cimg/go:1.20.7
resource_class: 2xlarge
ubuntu:
docker:
@@ -997,6 +997,7 @@ workflows:
suite: utest-unit-cli
target: "./cli/... ./cmd/... ./api/..."
get-params: true
executor: golang-2xl
- test:
name: test-unit-node
requires:
@@ -1004,12 +1005,14 @@ workflows:
suite: utest-unit-node
target: "./node/..."
- test:
name: test-unit-rest
requires:
- build
suite: utest-unit-rest
target: "./api/... ./blockstore/... ./build/... ./chain/... ./cli/... ./cmd/... ./conformance/... ./extern/... ./gateway/... ./journal/... ./lib/... ./markets/... ./node/... ./paychmgr/... ./storage/... ./tools/..."
target: "./blockstore/... ./build/... ./chain/... ./conformance/... ./gateway/... ./journal/... ./lib/... ./markets/... ./paychmgr/... ./tools/..."
executor: golang-2xl
- test:
name: test-unit-storage
@@ -1018,6 +1021,7 @@ workflows:
suite: utest-unit-storage
target: "./storage/... ./extern/..."
- test:
go-test-flags: "-run=TestMulticoreSDR"
requires:
+2
View File
@@ -65,6 +65,8 @@ func main() {
if err != nil {
panic(err)
}
// Redundantly flag both absolute and relative paths as excluded
excluded[filepath.Join(repo, s)] = struct{}{}
excluded[e] = struct{}{}
}
}
+3 -2
View File
@@ -7,12 +7,12 @@ executors:
golang:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.19.12
- image: cimg/go:1.20.7
resource_class: medium+
golang-2xl:
docker:
# Must match GO_VERSION_MIN in project root
- image: cimg/go:1.19.12
- image: cimg/go:1.20.7
resource_class: 2xlarge
ubuntu:
docker:
@@ -558,6 +558,7 @@ workflows:
suite: utest-[[ $suite ]]
target: "[[ $pkgs ]]"
[[if eq $suite "unit-cli"]]get-params: true[[end]]
[[if eq $suite "unit-cli"]]executor: golang-2xl[[end]]
[[- if eq $suite "unit-rest"]]executor: golang-2xl[[end]]
[[- end]]
- test:
+31
View File
@@ -0,0 +1,31 @@
---
name: New Task
about: A larger yet well-scoped task
title: '<title>'
labels: Needs Triage
assignees: ''
---
## User Story
<!-- Why? -->
## Acceptance Criteria
<!-- What? -->
<!-- add description-->
```[tasklist]
### Deliverables
```
## Technical Breakdown
```[tasklist]
### Development
```
```[tasklist]
### Testing
```
+1
View File
@@ -16,6 +16,7 @@ Before you mark the PR ready for review, please make sure that:
- example: ` fix: mempool: Introduce a cache for valid signatures`
- `PR type`: fix, feat, build, chore, ci, docs, perf, refactor, revert, style, test
- `area`, e.g. api, chain, state, market, mempool, multisig, networking, paych, proving, sealing, wallet, deps
- [ ] If the PR affects users (e.g., new feature, bug fix, system requirements change), update the CHANGELOG.md and add details to the UNRELEASED section.
- [ ] New features have usage guidelines and / or documentation updates in
- [ ] [Lotus Documentation](https://lotus.filecoin.io)
- [ ] [Discussion Tutorials](https://github.com/filecoin-project/lotus/discussions/categories/tutorials)
+1
View File
@@ -41,6 +41,7 @@ build/paramfetch.sh
bin/ipget
bin/tmp/*
.idea
.vscode
scratchpad
build/builtin-actors/v*
+1
View File
@@ -14,6 +14,7 @@ linters:
- varcheck
- deadcode
- scopelint
- unused
# We don't want to skip builtin/
skip-dirs-use-default: false
+9
View File
@@ -1,6 +1,15 @@
# Lotus changelog
# UNRELEASED
- chore: Auto remove local chain data when importing chain file or snapshot ([filecoin-project/lotus#11277](https://github.com/filecoin-project/lotus/pull/11277))
## New features
- feat: Added new tracing API (**HIGHLY EXPERIMENTAL**) supporting two RPC methods: `trace_block` and `trace_replayBlockTransactions` ([filecoin-project/lotus#11100](https://github.com/filecoin-project/lotus/pull/11100))
## Improvements
- fix: Add time slicing to splitstore purging step during compaction to reduce lock congestion [filecoin-project/lotus#11269](https://github.com/filecoin-project/lotus/pull/11269)
- feat: Added instructions on how to setup Prometheus/Grafana for monitoring a local Lotus node [filecoin-project/lotus#11276](https://github.com/filecoin-project/lotus/pull/11276)
- feat: Add a `FilterThresholdEpoch` configuration option [filecoin-project/lotus#11346](https://github.com/filecoin-project/lotus/pull/11346)
## New features
- feat: Add move-partition command ([filecoin-project/lotus#11290](https://github.com/filecoin-project/lotus/pull/11290))
+1 -1
View File
@@ -1,5 +1,5 @@
#####################################
FROM golang:1.19.12-bullseye AS lotus-builder
FROM golang:1.20.7-bullseye AS lotus-builder
MAINTAINER Lotus Development Team
RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev
+1 -1
View File
@@ -1 +1 @@
1.19.12
1.20.7
+1 -1
View File
@@ -73,7 +73,7 @@ All releases under an odd minor version number indicate **feature releases**. Th
Feature releases include new development and bug fixes. They are not mandatory, but still highly recommended, **as they may contain critical security fixes**. Note that some of these releases may be very small patch releases that include critical hotfixes. There is no way to distinguish between a bug fix release and a feature release on the "feature" version. Both cases will use the "patch" version number.
We aim to ship a new feature release of the Lotus software from our development (master) branch every 3 weeks, so users can expect a regular cadence of Lotus feature releases. Note that mandatory releases for network upgrades may disrupt this schedule. For more, see the Release Cycle section (TODO: Link).
We aim to ship a new feature release of the Lotus software from our development (master) branch every 3 weeks, so users can expect a regular cadence of Lotus feature releases. Note that mandatory releases for network upgrades may disrupt this schedule. For more, see the [Release Cycle section](#release-cycle).
### Examples Scenarios
+1 -1
View File
@@ -193,7 +193,7 @@ lotus-health:
.PHONY: lotus-health
BINS+=lotus-health
lotus-wallet:
lotus-wallet: $(BUILD_DEPS)
rm -f lotus-wallet
$(GOCC) build $(GOFLAGS) -o lotus-wallet ./cmd/lotus-wallet
.PHONY: lotus-wallet
+2
View File
@@ -133,6 +133,8 @@ Note: The default branch `master` is the dev branch where the latest new feature
6. You should now have Lotus installed. You can now [start the Lotus daemon and sync the chain](https://lotus.filecoin.io/lotus/install/linux/#start-the-lotus-daemon-and-sync-the-chain).
7. (Optional) Follow the [Setting Up Prometheus and Grafana](https://github.com/filecoin-project/lotus/tree/master/metrics/README.md) guide for detailed instructions on setting up a working monitoring system running against a local running lotus node.
## License
Dual-licensed under [MIT](https://github.com/filecoin-project/lotus/blob/master/LICENSE-MIT) + [Apache 2.0](https://github.com/filecoin-project/lotus/blob/master/LICENSE-APACHE)
+7
View File
@@ -867,6 +867,13 @@ type FullNode interface {
// Returns the client version
Web3ClientVersion(ctx context.Context) (string, error) //perm:read
// TraceAPI related methods
//
// Returns traces created at given block
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error) //perm:read
// Replays all transactions in a block returning the requested traces for each transaction
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) //perm:read
// CreateBackup creates node backup onder the specified file name. The
// method requires that the lotus daemon is running with the
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
+8
View File
@@ -9,6 +9,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-jsonrpc"
"github.com/filecoin-project/go-state-types/abi"
verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
"github.com/filecoin-project/go-state-types/dline"
apitypes "github.com/filecoin-project/lotus/api/types"
@@ -65,6 +66,11 @@ type Gateway interface {
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error)
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifregtypes.Allocation, error)
StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error)
StateGetAllocations(ctx context.Context, clientAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error)
StateGetClaim(ctx context.Context, providerAddr address.Address, claimId verifregtypes.ClaimId, tsk types.TipSetKey) (*verifregtypes.Claim, error)
StateGetClaims(ctx context.Context, providerAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error)
StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*ActorState, error)
StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error)
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
@@ -121,4 +127,6 @@ type Gateway interface {
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
Web3ClientVersion(ctx context.Context) (string, error)
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
}
+3
View File
@@ -40,6 +40,9 @@ func CreateEthRPCAliases(as apitypes.Aliaser) {
as.AliasMethod("eth_subscribe", "Filecoin.EthSubscribe")
as.AliasMethod("eth_unsubscribe", "Filecoin.EthUnsubscribe")
as.AliasMethod("trace_block", "Filecoin.EthTraceBlock")
as.AliasMethod("trace_replayBlockTransactions", "Filecoin.EthTraceReplayBlockTransactions")
as.AliasMethod("net_version", "Filecoin.NetVersion")
as.AliasMethod("net_listening", "Filecoin.NetListening")
+30
View File
@@ -1491,6 +1491,36 @@ func (mr *MockFullNodeMockRecorder) EthSyncing(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSyncing", reflect.TypeOf((*MockFullNode)(nil).EthSyncing), arg0)
}
// EthTraceBlock mocks base method.
func (m *MockFullNode) EthTraceBlock(arg0 context.Context, arg1 string) ([]*ethtypes.EthTraceBlock, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthTraceBlock", arg0, arg1)
ret0, _ := ret[0].([]*ethtypes.EthTraceBlock)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthTraceBlock indicates an expected call of EthTraceBlock.
func (mr *MockFullNodeMockRecorder) EthTraceBlock(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthTraceBlock", reflect.TypeOf((*MockFullNode)(nil).EthTraceBlock), arg0, arg1)
}
// EthTraceReplayBlockTransactions mocks base method.
func (m *MockFullNode) EthTraceReplayBlockTransactions(arg0 context.Context, arg1 string, arg2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthTraceReplayBlockTransactions", arg0, arg1, arg2)
ret0, _ := ret[0].([]*ethtypes.EthTraceReplayBlockTransaction)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthTraceReplayBlockTransactions indicates an expected call of EthTraceReplayBlockTransactions.
func (mr *MockFullNodeMockRecorder) EthTraceReplayBlockTransactions(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthTraceReplayBlockTransactions", reflect.TypeOf((*MockFullNode)(nil).EthTraceReplayBlockTransactions), arg0, arg1, arg2)
}
// EthUninstallFilter mocks base method.
func (m *MockFullNode) EthUninstallFilter(arg0 context.Context, arg1 ethtypes.EthFilterID) (bool, error) {
m.ctrl.T.Helper()
+117
View File
@@ -315,6 +315,10 @@ type FullNodeMethods struct {
EthSyncing func(p0 context.Context) (ethtypes.EthSyncingResult, error) `perm:"read"`
EthTraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) `perm:"read"`
EthTraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) `perm:"read"`
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"read"`
EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `perm:"read"`
@@ -731,6 +735,10 @@ type GatewayMethods struct {
EthSyncing func(p0 context.Context) (ethtypes.EthSyncingResult, error) ``
EthTraceBlock func(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) ``
EthTraceReplayBlockTransactions func(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) ``
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) ``
EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) ``
@@ -769,6 +777,16 @@ type GatewayMethods struct {
StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) ``
StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) ``
StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) ``
StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) ``
StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) ``
StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) ``
StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) ``
StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) ``
@@ -2446,6 +2464,28 @@ func (s *FullNodeStub) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult
return *new(ethtypes.EthSyncingResult), ErrNotSupported
}
func (s *FullNodeStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {
if s.Internal.EthTraceBlock == nil {
return *new([]*ethtypes.EthTraceBlock), ErrNotSupported
}
return s.Internal.EthTraceBlock(p0, p1)
}
func (s *FullNodeStub) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {
return *new([]*ethtypes.EthTraceBlock), ErrNotSupported
}
func (s *FullNodeStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
if s.Internal.EthTraceReplayBlockTransactions == nil {
return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported
}
return s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2)
}
func (s *FullNodeStub) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported
}
func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
if s.Internal.EthUninstallFilter == nil {
return false, ErrNotSupported
@@ -4668,6 +4708,28 @@ func (s *GatewayStub) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult,
return *new(ethtypes.EthSyncingResult), ErrNotSupported
}
func (s *GatewayStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {
if s.Internal.EthTraceBlock == nil {
return *new([]*ethtypes.EthTraceBlock), ErrNotSupported
}
return s.Internal.EthTraceBlock(p0, p1)
}
func (s *GatewayStub) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {
return *new([]*ethtypes.EthTraceBlock), ErrNotSupported
}
func (s *GatewayStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
if s.Internal.EthTraceReplayBlockTransactions == nil {
return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported
}
return s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2)
}
func (s *GatewayStub) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {
return *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported
}
func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
if s.Internal.EthUninstallFilter == nil {
return false, ErrNotSupported
@@ -4877,6 +4939,61 @@ func (s *GatewayStub) StateGetActor(p0 context.Context, p1 address.Address, p2 t
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocation == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetAllocation(p0, p1, p2, p3)
}
func (s *GatewayStub) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocationForPendingDeal == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetAllocationForPendingDeal(p0, p1, p2)
}
func (s *GatewayStub) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocations == nil {
return *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported
}
return s.Internal.StateGetAllocations(p0, p1, p2)
}
func (s *GatewayStub) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {
return *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported
}
func (s *GatewayStruct) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {
if s.Internal.StateGetClaim == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetClaim(p0, p1, p2, p3)
}
func (s *GatewayStub) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {
if s.Internal.StateGetClaims == nil {
return *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported
}
return s.Internal.StateGetClaims(p0, p1, p2)
}
func (s *GatewayStub) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {
return *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported
}
func (s *GatewayStruct) StateListMiners(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) {
if s.Internal.StateListMiners == nil {
return *new([]address.Address), ErrNotSupported
+10 -1
View File
@@ -56,9 +56,17 @@ type PubsubScore struct {
Score *pubsub.PeerScoreSnapshot
}
// MessageSendSpec contains optional fields which modify message sending behavior
type MessageSendSpec struct {
MaxFee abi.TokenAmount
// MaxFee specifies a cap on network fees related to this message
MaxFee abi.TokenAmount
// MsgUuid specifies a unique message identifier which can be used on node (or node cluster)
// level to prevent double-sends of messages even when nonce generation is not handled by sender
MsgUuid uuid.UUID
// MaximizeFeeCap makes message FeeCap be based entirely on MaxFee
MaximizeFeeCap bool
}
type MpoolMessageWhole struct {
@@ -312,6 +320,7 @@ type NetworkParams struct {
SupportedProofTypes []abi.RegisteredSealProof
PreCommitChallengeDelay abi.ChainEpoch
ForkUpgradeParams ForkUpgradeParams
Eip155ChainID int
}
type ForkUpgradeParams struct {
+6
View File
@@ -8,6 +8,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
"github.com/filecoin-project/go-state-types/dline"
abinetwork "github.com/filecoin-project/go-state-types/network"
@@ -61,6 +62,11 @@ type Gateway interface {
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error)
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
StateGetAllocationForPendingDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*verifregtypes.Allocation, error)
StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error)
StateGetAllocations(ctx context.Context, clientAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error)
StateGetClaim(ctx context.Context, providerAddr address.Address, claimId verifregtypes.ClaimId, tsk types.TipSetKey) (*verifregtypes.Claim, error)
StateGetClaims(ctx context.Context, providerAddr address.Address, tsk types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error)
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error)
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
+65
View File
@@ -478,6 +478,16 @@ type GatewayMethods struct {
StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) ``
StateGetAllocation func(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) ``
StateGetAllocationForPendingDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) ``
StateGetAllocations func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) ``
StateGetClaim func(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) ``
StateGetClaims func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) ``
StateGetReceipt func(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) ``
StateListMiners func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) ``
@@ -2850,6 +2860,61 @@ func (s *GatewayStub) StateGetActor(p0 context.Context, p1 address.Address, p2 t
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocation == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetAllocation(p0, p1, p2, p3)
}
func (s *GatewayStub) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocationForPendingDeal == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetAllocationForPendingDeal(p0, p1, p2)
}
func (s *GatewayStub) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {
if s.Internal.StateGetAllocations == nil {
return *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported
}
return s.Internal.StateGetAllocations(p0, p1, p2)
}
func (s *GatewayStub) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {
return *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported
}
func (s *GatewayStruct) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {
if s.Internal.StateGetClaim == nil {
return nil, ErrNotSupported
}
return s.Internal.StateGetClaim(p0, p1, p2, p3)
}
func (s *GatewayStub) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {
return nil, ErrNotSupported
}
func (s *GatewayStruct) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {
if s.Internal.StateGetClaims == nil {
return *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported
}
return s.Internal.StateGetClaims(p0, p1, p2)
}
func (s *GatewayStub) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {
return *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported
}
func (s *GatewayStruct) StateGetReceipt(p0 context.Context, p1 cid.Cid, p2 types.TipSetKey) (*types.MessageReceipt, error) {
if s.Internal.StateGetReceipt == nil {
return nil, ErrNotSupported
-1
View File
@@ -182,7 +182,6 @@ type SplitStore struct {
compactionIndex int64
pruneIndex int64
onlineGCCnt int64
ctx context.Context
cancel func()
+15 -2
View File
@@ -66,8 +66,9 @@ var (
)
const (
batchSize = 16384
cidKeySize = 128
batchSize = 16384
cidKeySize = 128
purgeWorkSliceDuration = time.Second
)
func (s *SplitStore) HeadChange(_, apply []*types.TipSet) error {
@@ -1372,9 +1373,21 @@ func (s *SplitStore) purge(coldr *ColdSetReader, checkpoint *Checkpoint, markSet
return err
}
now := time.Now()
err := coldr.ForEach(func(c cid.Cid) error {
batch = append(batch, c)
if len(batch) == batchSize {
// add some time slicing to the purge as this a very disk I/O heavy operation that
// requires write access to txnLk that may starve other operations that require
// access to the blockstore.
elapsed := time.Since(now)
if elapsed > purgeWorkSliceDuration {
// work 1 slice, sleep 4 slices, or 20% utilization
time.Sleep(4 * elapsed)
now = time.Now()
}
return deleteBatch()
}
+2 -4
View File
@@ -1,9 +1,6 @@
/dns4/bootstrap-0.mainnet.filops.net/tcp/1347/p2p/12D3KooWCVe8MmsEMes2FzgTpt9fXtmCY7wrq91GRiaC8PHSCCBj
/dns4/bootstrap-1.mainnet.filops.net/tcp/1347/p2p/12D3KooWCwevHg1yLCvktf2nvLu7L9894mcrJR4MsBCcm4syShVc
/dns4/bootstrap-2.mainnet.filops.net/tcp/1347/p2p/12D3KooWEWVwHGn2yR36gKLozmb4YjDJGerotAPGxmdWZx2nxMC4
/dns4/bootstrap-3.mainnet.filops.net/tcp/1347/p2p/12D3KooWKhgq8c7NQ9iGjbyK7v7phXvG6492HQfiDaGHLHLQjk7R
/dns4/bootstrap-4.mainnet.filops.net/tcp/1347/p2p/12D3KooWL6PsFNPhYftrJzGgF5U18hFoaVhfGk7xwzD8yVrHJ3Uc
/dns4/bootstrap-5.mainnet.filops.net/tcp/1347/p2p/12D3KooWLFynvDQiUpXoHroV1YxKHhPJgysQGH2k3ZGwtWzR4dFH
/dns4/bootstrap-6.mainnet.filops.net/tcp/1347/p2p/12D3KooWP5MwCiqdMETF9ub1P3MbCvQCcfconnYHbWg6sUJcDRQQ
/dns4/bootstrap-7.mainnet.filops.net/tcp/1347/p2p/12D3KooWRs3aY1p3juFjPy8gPN95PEQChm2QKGUCAdcDCC4EBMKf
/dns4/bootstrap-8.mainnet.filops.net/tcp/1347/p2p/12D3KooWScFR7385LTyR4zU1bYdzSiiAb5rnNABfVahPvVSzyTkR
@@ -13,4 +10,5 @@
/dns4/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt
/dns4/bootstrap-0.ipfsmain.cn/tcp/34721/p2p/12D3KooWQnwEGNqcM2nAcPtRR9rAX8Hrg4k9kJLCHoTR5chJfz6d
/dns4/bootstrap-1.ipfsmain.cn/tcp/34723/p2p/12D3KooWMKxMkD5DMpSWsW7dBddKxKT7L2GgbNuckz9otxvkvByP
/dns4/bootstarp-0.1475.io/tcp/61256/p2p/12D3KooWRzCVDwHUkgdK7eRgnoXbjDAELhxPErjHzbRLguSV1aRt
/dns4/bootstarp-0.1475.io/tcp/61256/p2p/12D3KooWRzCVDwHUkgdK7eRgnoXbjDAELhxPErjHzbRLguSV1aRt
/dns4/bootstrap-venus.mainnet.filincubator.com/tcp/8888/p2p/QmQu8C6deXwKvJP2D8B6QGyhngc3ZiDnFzEHBDx8yeBXST
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -132,6 +132,8 @@ const BlockDelaySecs = uint64(4)
const PropagationDelaySecs = uint64(1)
var EquivocationDelaySecs = uint64(0)
// SlashablePowerDelay is the number of epochs after ElectionPeriodStart, after
// which the miner is slashed
//
+2
View File
@@ -83,6 +83,8 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
const PropagationDelaySecs = uint64(6)
var EquivocationDelaySecs = uint64(2)
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2
+2
View File
@@ -123,6 +123,8 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
var PropagationDelaySecs = uint64(10)
var EquivocationDelaySecs = uint64(2)
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 4
+2
View File
@@ -121,6 +121,8 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
const PropagationDelaySecs = uint64(6)
var EquivocationDelaySecs = uint64(2)
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2
+2
View File
@@ -106,6 +106,8 @@ var ConsensusMinerMinPower = abi.NewStoragePower(10 << 40)
var PreCommitChallengeDelay = abi.ChainEpoch(150)
var PropagationDelaySecs = uint64(10)
var EquivocationDelaySecs = uint64(2)
func init() {
if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" {
SetAddressNetwork(address.Mainnet)
+1 -5
View File
@@ -9,7 +9,6 @@ package build
import (
"math/big"
"time"
"github.com/ipfs/go-cid"
@@ -34,6 +33,7 @@ var (
MinimumBaseFee = int64(100)
BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
PropagationDelaySecs = uint64(6)
EquivocationDelaySecs = uint64(2)
SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
@@ -139,7 +139,3 @@ const BootstrapPeerThreshold = 1
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
// As per https://github.com/ethereum-lists/chains
const Eip155ChainId = 31415926
// Reducing the delivery delay for equivocation of
// consistent broadcast to just half a second.
var CBDeliveryDelay = 500 * time.Millisecond
+1 -1
View File
@@ -37,7 +37,7 @@ func BuildTypeString() string {
}
// BuildVersion is the local build version
const BuildVersion = "1.23.3"
const BuildVersion = "1.23.5-dev"
func UserVersion() string {
if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" {
+3 -3
View File
@@ -3,14 +3,14 @@ package chain
import (
"fmt"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/hashicorp/golang-lru/arc/v2"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/build"
)
type BadBlockCache struct {
badBlocks *lru.ARCCache[cid.Cid, BadBlockReason]
badBlocks *arc.ARCCache[cid.Cid, BadBlockReason]
}
type BadBlockReason struct {
@@ -43,7 +43,7 @@ func (bbr BadBlockReason) String() string {
}
func NewBadBlockCache() *BadBlockCache {
cache, err := lru.NewARC[cid.Cid, BadBlockReason](build.BadBlockCacheSize)
cache, err := arc.NewARC[cid.Cid, BadBlockReason](build.BadBlockCacheSize)
if err != nil {
panic(err) // ok
}
+13 -13
View File
@@ -29,19 +29,6 @@ import (
var log = logging.Logger("drand")
type drandPeer struct {
addr string
tls bool
}
func (dp *drandPeer) Address() string {
return dp.addr
}
func (dp *drandPeer) IsTLS() bool {
return dp.tls
}
// DrandBeacon connects Lotus with a drand network in order to provide
// randomness to the system in a way that's aligned with Filecoin rounds/epochs.
//
@@ -235,3 +222,16 @@ func (db *DrandBeacon) maxBeaconRoundV2(latestTs uint64) uint64 {
}
var _ beacon.RandomBeacon = (*DrandBeacon)(nil)
func BeaconScheduleFromDrandSchedule(dcs dtypes.DrandSchedule, genesisTime uint64, ps *pubsub.PubSub) (beacon.Schedule, error) {
shd := beacon.Schedule{}
for _, dc := range dcs {
bc, err := NewDrandBeacon(genesisTime, build.BlockDelaySecs, ps, dc.Config)
if err != nil {
return nil, xerrors.Errorf("creating drand beacon: %w", err)
}
shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc})
}
return shd, nil
}
-3
View File
@@ -147,9 +147,6 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
return xerrors.Errorf("callback failed on cron message: %w", err)
}
}
if ret.ExitCode != 0 {
return xerrors.Errorf("cron exit was non-zero: %d", ret.ExitCode)
}
return nil
}
-3
View File
@@ -91,9 +91,6 @@ var RewardFunc = func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonito
}
}
if ret.ExitCode != 0 {
return xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
}
return nil
}
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"context"
"sync"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/hashicorp/golang-lru/arc/v2"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api"
@@ -14,11 +14,11 @@ type messageCache struct {
api EventAPI
blockMsgLk sync.Mutex
blockMsgCache *lru.ARCCache[cid.Cid, *api.BlockMessages]
blockMsgCache *arc.ARCCache[cid.Cid, *api.BlockMessages]
}
func newMessageCache(a EventAPI) *messageCache {
blsMsgCache, _ := lru.NewARC[cid.Cid, *api.BlockMessages](500)
blsMsgCache, _ := arc.NewARC[cid.Cid, *api.BlockMessages](500)
return &messageCache{
api: a,
-25
View File
@@ -1,25 +0,0 @@
package state
import (
"context"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
)
type contextStore struct {
ctx context.Context
cst *cbor.BasicIpldStore
}
func (cs *contextStore) Context() context.Context {
return cs.ctx
}
func (cs *contextStore) Get(ctx context.Context, c cid.Cid, out interface{}) error {
return cs.cst.Get(ctx, c, out)
}
func (cs *contextStore) Put(ctx context.Context, v interface{}) (cid.Cid, error) {
return cs.cst.Put(ctx, v)
}
+1 -1
View File
@@ -381,7 +381,7 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque
defer span.End()
if span.IsRecordingEvents() {
span.AddAttributes(
trace.StringAttribute("peer", peer.Pretty()),
trace.StringAttribute("peer", peer.String()),
)
}
defer func() {
+17 -6
View File
@@ -362,7 +362,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
rbase = entries[len(entries)-1]
}
eproof, err := IsRoundWinner(ctx, pts, round, m, rbase, mbi, mc)
eproof, err := IsRoundWinner(ctx, round, m, rbase, mbi, mc)
if err != nil {
return nil, nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
@@ -449,18 +449,19 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
}
func (cg *ChainGen) NextTipSetFromMinersWithMessagesAndNulls(base *types.TipSet, miners []address.Address, msgs [][]*types.SignedMessage, nulls abi.ChainEpoch) (*store.FullTipSet, error) {
ctx := context.TODO()
var blks []*types.FullBlock
for round := base.Height() + nulls + 1; len(blks) == 0; round++ {
for mi, m := range miners {
bvals, et, ticket, err := cg.nextBlockProof(context.TODO(), base, m, round)
bvals, et, ticket, err := cg.nextBlockProof(ctx, base, m, round)
if err != nil {
return nil, xerrors.Errorf("next block proof: %w", err)
}
if et != nil {
// TODO: maybe think about passing in more real parameters to this?
wpost, err := cg.eppProvs[m].ComputeProof(context.TODO(), nil, nil, round, network.Version0)
wpost, err := cg.eppProvs[m].ComputeProof(ctx, nil, nil, round, network.Version0)
if err != nil {
return nil, err
}
@@ -476,8 +477,18 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessagesAndNulls(base *types.TipSet,
}
fts := store.NewFullTipSet(blks)
if err := cg.cs.PutTipSet(context.TODO(), fts.TipSet()); err != nil {
return nil, err
if err := cg.cs.PersistTipsets(ctx, []*types.TipSet{fts.TipSet()}); err != nil {
return nil, xerrors.Errorf("failed to persist tipset: %w", err)
}
for _, blk := range blks {
if err := cg.cs.AddToTipSetTracker(ctx, blk.Header); err != nil {
return nil, xerrors.Errorf("failed to add to tipset tracker: %w", err)
}
}
if err := cg.cs.RefreshHeaviestTipSet(ctx, fts.TipSet().Height()); err != nil {
return nil, xerrors.Errorf("failed to put tipset: %w", err)
}
cg.CurTipset = fts
@@ -628,7 +639,7 @@ func (wpp *wppProvider) ComputeProof(context.Context, []proof7.ExtendedSectorInf
return ValidWpostForTesting, nil
}
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
func IsRoundWinner(ctx context.Context, round abi.ChainEpoch,
miner address.Address, brand types.BeaconEntry, mbi *api.MiningBaseInfo, a MiningCheckAPI) (*types.ElectionProof, error) {
buf := new(bytes.Buffer)
-17
View File
@@ -39,23 +39,6 @@ func (ps *Store) save(ctx context.Context, state *FundedAddressState) error {
return ps.ds.Put(ctx, k, b)
}
// get the state for the given address
func (ps *Store) get(ctx context.Context, addr address.Address) (*FundedAddressState, error) {
k := dskeyForAddr(addr)
data, err := ps.ds.Get(ctx, k)
if err != nil {
return nil, err
}
var state FundedAddressState
err = cborrpc.ReadCborRPC(bytes.NewReader(data), &state)
if err != nil {
return nil, err
}
return &state, nil
}
// forEach calls iter with each address in the datastore
func (ps *Store) forEach(ctx context.Context, iter func(*FundedAddressState)) error {
res, err := ps.ds.Query(ctx, dsq.Query{Prefix: dsKeyAddr})
+9 -7
View File
@@ -63,6 +63,9 @@ var MaxNonceGap = uint64(4)
const MaxMessageSize = 64 << 10 // 64KiB
// NOTE: When adding a new error type, please make sure to add the new error type in
// func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message)
// in /chain/sub/incoming.go
var (
ErrMessageTooBig = errors.New("message too big")
@@ -207,8 +210,10 @@ func ComputeRBF(curPrem abi.TokenAmount, replaceByFeeRatio types.Percent) abi.To
func CapGasFee(mff dtypes.DefaultMaxFeeFunc, msg *types.Message, sendSpec *api.MessageSendSpec) {
var maxFee abi.TokenAmount
var maximizeFeeCap bool
if sendSpec != nil {
maxFee = sendSpec.MaxFee
maximizeFeeCap = sendSpec.MaximizeFeeCap
}
if maxFee.Int == nil || maxFee.Equals(big.Zero()) {
mf, err := mff()
@@ -219,15 +224,12 @@ func CapGasFee(mff dtypes.DefaultMaxFeeFunc, msg *types.Message, sendSpec *api.M
maxFee = mf
}
gl := types.NewInt(uint64(msg.GasLimit))
totalFee := types.BigMul(msg.GasFeeCap, gl)
if totalFee.LessThanEqual(maxFee) {
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
return
gaslimit := types.NewInt(uint64(msg.GasLimit))
totalFee := types.BigMul(msg.GasFeeCap, gaslimit)
if maximizeFeeCap || totalFee.GreaterThan(maxFee) {
msg.GasFeeCap = big.Div(maxFee, gaslimit)
}
msg.GasFeeCap = big.Div(maxFee, gl)
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
}
-5
View File
@@ -232,11 +232,6 @@ func (sm *StateManager) hasExpensiveForkBetween(parent, height abi.ChainEpoch) b
return false
}
func (sm *StateManager) hasExpensiveFork(height abi.ChainEpoch) bool {
_, ok := sm.expensiveUpgrades[height]
return ok
}
func runPreMigration(ctx context.Context, sm *StateManager, fn PreMigrationFunc, cache *nv16.MemMigrationCache, ts *types.TipSet) {
height := ts.Height()
parent := ts.ParentState()
+4 -4
View File
@@ -7,7 +7,7 @@ import (
"strconv"
"sync"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/hashicorp/golang-lru/arc/v2"
"github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
cbor "github.com/ipfs/go-ipld-cbor"
@@ -156,7 +156,7 @@ type StateManager struct {
// We keep a small cache for calls to ExecutionTrace which helps improve
// performance for node operators like exchanges and block explorers
execTraceCache *lru.ARCCache[types.TipSetKey, tipSetCacheEntry]
execTraceCache *arc.ARCCache[types.TipSetKey, tipSetCacheEntry]
// We need a lock while making the copy as to prevent other callers
// overwrite the cache while making the copy
execTraceCacheLock sync.Mutex
@@ -213,10 +213,10 @@ func NewStateManager(cs *store.ChainStore, exec Executor, sys vm.SyscallBuilder,
}
log.Debugf("execTraceCache size: %d", execTraceCacheSize)
var execTraceCache *lru.ARCCache[types.TipSetKey, tipSetCacheEntry]
var execTraceCache *arc.ARCCache[types.TipSetKey, tipSetCacheEntry]
var err error
if execTraceCacheSize > 0 {
execTraceCache, err = lru.NewARC[types.TipSetKey, tipSetCacheEntry](execTraceCacheSize)
execTraceCache, err = arc.NewARC[types.TipSetKey, tipSetCacheEntry](execTraceCacheSize)
if err != nil {
return nil, err
}
+8
View File
@@ -388,6 +388,14 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
circ := big.Zero()
unCirc := big.Zero()
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
// this can be a lengthy operation, we need to cancel early when
// the context is cancelled to avoid resource exhaustion
select {
case <-ctx.Done():
// this will cause ForEach to return
return ctx.Err()
default:
}
switch {
case actor.Balance.IsZero():
// Do nothing for zero-balance actors
+2 -2
View File
@@ -70,7 +70,7 @@ func TestChainCheckpoint(t *testing.T) {
}
// See if the chain will take the fork, it shouldn't.
err = cs.MaybeTakeHeavierTipSet(context.Background(), last)
err = cs.RefreshHeaviestTipSet(context.Background(), last.Height())
require.NoError(t, err)
head = cs.GetHeaviestTipSet()
require.True(t, head.Equals(checkpoint))
@@ -80,7 +80,7 @@ func TestChainCheckpoint(t *testing.T) {
require.NoError(t, err)
// Now switch to the other fork.
err = cs.MaybeTakeHeavierTipSet(context.Background(), last)
err = cs.RefreshHeaviestTipSet(context.Background(), last.Height())
require.NoError(t, err)
head = cs.GetHeaviestTipSet()
require.True(t, head.Equals(last))
+12 -10
View File
@@ -16,6 +16,7 @@ import (
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/mock"
)
@@ -47,28 +48,29 @@ func TestIndexSeeks(t *testing.T) {
}
cur := mock.TipSet(gen)
if err := cs.PutTipSet(ctx, mock.TipSet(gen)); err != nil {
t.Fatal(err)
}
assert.NoError(t, cs.SetGenesis(ctx, gen))
// Put 113 blocks from genesis
for i := 0; i < 113; i++ {
nextts := mock.TipSet(mock.MkBlock(cur, 1, 1))
if err := cs.PutTipSet(ctx, nextts); err != nil {
t.Fatal(err)
}
nextBlk := mock.MkBlock(cur, 1, 1)
nextts := mock.TipSet(nextBlk)
assert.NoError(t, cs.PersistTipsets(ctx, []*types.TipSet{nextts}))
assert.NoError(t, cs.AddToTipSetTracker(ctx, nextBlk))
cur = nextts
}
assert.NoError(t, cs.RefreshHeaviestTipSet(ctx, cur.Height()))
// Put 50 null epochs + 1 block
skip := mock.MkBlock(cur, 1, 1)
skip.Height += 50
skipts := mock.TipSet(skip)
if err := cs.PutTipSet(ctx, skipts); err != nil {
assert.NoError(t, cs.PersistTipsets(ctx, []*types.TipSet{skipts}))
assert.NoError(t, cs.AddToTipSetTracker(ctx, skip))
if err := cs.RefreshHeaviestTipSet(ctx, skip.Height); err != nil {
t.Fatal(err)
}
+14 -12
View File
@@ -15,7 +15,7 @@ import (
"github.com/ipld/go-car"
carutil "github.com/ipld/go-car/util"
carv2 "github.com/ipld/go-car/v2"
mh "github.com/multiformats/go-multihash"
"github.com/multiformats/go-multicodec"
cbg "github.com/whyrusleeping/cbor-gen"
"go.uber.org/atomic"
"golang.org/x/sync/errgroup"
@@ -369,14 +369,16 @@ func (s *walkScheduler) Wait() error {
}
func (s *walkScheduler) enqueueIfNew(task walkTask) {
if task.c.Prefix().MhType == mh.IDENTITY {
if multicodec.Code(task.c.Prefix().MhType) == multicodec.Identity {
//log.Infow("ignored", "cid", todo.c.String())
return
}
// This lets through RAW and CBOR blocks, the only two types that we
// end up writing to the exported CAR.
if task.c.Prefix().Codec != cid.Raw && task.c.Prefix().Codec != cid.DagCBOR {
// This lets through RAW, CBOR, and DagCBOR blocks, the only types that we end up writing to
// the exported CAR.
switch multicodec.Code(task.c.Prefix().Codec) {
case multicodec.Cbor, multicodec.DagCbor, multicodec.Raw:
default:
//log.Infow("ignored", "cid", todo.c.String())
return
}
@@ -450,7 +452,8 @@ func (s *walkScheduler) processTask(t walkTask, workerN int) error {
// We exported the ipld block. If it wasn't a CBOR block, there's nothing
// else to do and we can bail out early as it won't have any links
// etc.
if t.c.Prefix().Codec != cid.DagCBOR || t.c.Prefix().MhType == mh.IDENTITY {
if multicodec.Code(t.c.Prefix().Codec) != multicodec.DagCbor ||
multicodec.Code(t.c.Prefix().MhType) == multicodec.Identity {
return nil
}
@@ -683,14 +686,13 @@ func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRe
prefix := c.Prefix()
// Don't include identity CIDs.
if prefix.MhType == mh.IDENTITY {
if multicodec.Code(prefix.MhType) == multicodec.Identity {
continue
}
// We only include raw and dagcbor, for now.
// Raw for "code" CIDs.
switch prefix.Codec {
case cid.Raw, cid.DagCBOR:
// We only include raw, cbor, and dagcbor, for now.
switch multicodec.Code(prefix.Codec) {
case multicodec.Cbor, multicodec.DagCbor, multicodec.Raw:
default:
continue
}
@@ -722,7 +724,7 @@ func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRe
}
func recurseLinks(ctx context.Context, bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
if root.Prefix().Codec != cid.DagCBOR {
if multicodec.Code(root.Prefix().Codec) != multicodec.DagCbor {
return in, nil
}
+171 -90
View File
@@ -11,7 +11,7 @@ import (
"sync"
"time"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/hashicorp/golang-lru/arc/v2"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore"
@@ -120,8 +120,8 @@ type ChainStore struct {
reorgCh chan<- reorg
reorgNotifeeCh chan ReorgNotifee
mmCache *lru.ARCCache[cid.Cid, mmCids]
tsCache *lru.ARCCache[types.TipSetKey, *types.TipSet]
mmCache *arc.ARCCache[cid.Cid, mmCids]
tsCache *arc.ARCCache[types.TipSetKey, *types.TipSet]
evtTypes [1]journal.EventType
journal journal.Journal
@@ -133,8 +133,8 @@ type ChainStore struct {
}
func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dstore.Batching, weight WeightFunc, j journal.Journal) *ChainStore {
c, _ := lru.NewARC[cid.Cid, mmCids](DefaultMsgMetaCacheSize)
tsc, _ := lru.NewARC[types.TipSetKey, *types.TipSet](DefaultTipSetCacheSize)
c, _ := arc.NewARC[cid.Cid, mmCids](DefaultMsgMetaCacheSize)
tsc, _ := arc.NewARC[types.TipSetKey, *types.TipSet](DefaultTipSetCacheSize)
if j == nil {
j = journal.NilJournal()
}
@@ -367,49 +367,32 @@ func (cs *ChainStore) UnmarkBlockAsValidated(ctx context.Context, blkid cid.Cid)
func (cs *ChainStore) SetGenesis(ctx context.Context, b *types.BlockHeader) error {
ts, err := types.NewTipSet([]*types.BlockHeader{b})
if err != nil {
return err
return xerrors.Errorf("failed to construct genesis tipset: %w", err)
}
if err := cs.PutTipSet(ctx, ts); err != nil {
return err
if err := cs.PersistTipsets(ctx, []*types.TipSet{ts}); err != nil {
return xerrors.Errorf("failed to persist genesis tipset: %w", err)
}
if err := cs.AddToTipSetTracker(ctx, b); err != nil {
return xerrors.Errorf("failed to add genesis tipset to tracker: %w", err)
}
if err := cs.RefreshHeaviestTipSet(ctx, ts.Height()); err != nil {
return xerrors.Errorf("failed to put genesis tipset: %w", err)
}
return cs.metadataDs.Put(ctx, dstore.NewKey("0"), b.Cid().Bytes())
}
func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
if err := cs.PersistTipsets(ctx, []*types.TipSet{ts}); err != nil {
return xerrors.Errorf("failed to persist tipset: %w", err)
}
expanded, err := cs.expandTipset(ctx, ts.Blocks()[0])
if err != nil {
return xerrors.Errorf("errored while expanding tipset: %w", err)
}
if expanded.Key() != ts.Key() {
log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids())
tsBlk, err := expanded.Key().ToStorageBlock()
if err != nil {
return xerrors.Errorf("failed to get tipset key block: %w", err)
}
if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil {
return xerrors.Errorf("failed to put tipset key block: %w", err)
}
}
if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil {
return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err)
}
return nil
}
// MaybeTakeHeavierTipSet evaluates the incoming tipset and locks it in our
// internal state as our new head, if and only if it is heavier than the current
// head and does not exceed the maximum fork length.
func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipSet) error {
// RefreshHeaviestTipSet receives a newTsHeight at which a new tipset might exist. It then:
// - "refreshes" the heaviest tipset that can be formed at its current heaviest height
// - if equivocation is detected among the miners of the current heaviest tipset, the head is immediately updated to the heaviest tipset that can be formed in a range of 5 epochs
//
// - forms the best tipset that can be formed at the _input_ height
// - compares the three tipset weights: "current" heaviest tipset, "refreshed" tipset, and best tipset at newTsHeight
// - updates "current" heaviest to the heaviest of those 3 tipsets (if an update is needed), assuming it doesn't violate the maximum fork rule
func (cs *ChainStore) RefreshHeaviestTipSet(ctx context.Context, newTsHeight abi.ChainEpoch) error {
for {
cs.heaviestLk.Lock()
if len(cs.reorgCh) < reorgChBuf/2 {
@@ -426,39 +409,90 @@ func (cs *ChainStore) MaybeTakeHeavierTipSet(ctx context.Context, ts *types.TipS
defer cs.heaviestLk.Unlock()
if ts.Equals(cs.heaviest) {
heaviestWeight, err := cs.weight(ctx, cs.StateBlockstore(), cs.heaviest)
if err != nil {
return xerrors.Errorf("failed to calculate currentHeaviest's weight: %w", err)
}
heaviestHeight := abi.ChainEpoch(0)
if cs.heaviest != nil {
heaviestHeight = cs.heaviest.Height()
}
// Before we look at newTs, let's refresh best tipset at current head's height -- this is done to detect equivocation
newHeaviest, newHeaviestWeight, err := cs.FormHeaviestTipSetForHeight(ctx, heaviestHeight)
if err != nil {
return xerrors.Errorf("failed to reform head at same height: %w", err)
}
// Equivocation has occurred! We need a new head NOW!
if newHeaviest == nil || newHeaviestWeight.LessThan(heaviestWeight) {
log.Warnf("chainstore heaviest tipset's weight SHRANK from %d (%s) to %d (%s) due to equivocation", heaviestWeight, cs.heaviest, newHeaviestWeight, newHeaviest)
// Unfortunately, we don't know what the right height to form a new heaviest tipset is.
// It is _probably_, but not _necessarily_, heaviestHeight.
// So, we need to explore a range of epochs, finding the heaviest tipset in that range.
// We thus try to form the heaviest tipset for 5 epochs above heaviestHeight (most of which will likely not exist),
// as well as for 5 below.
// This is slow, but we expect to almost-never be here (only if miners are equivocating, which carries a hefty penalty).
for i := heaviestHeight + 5; i > heaviestHeight-5; i-- {
possibleHeaviestTs, possibleHeaviestWeight, err := cs.FormHeaviestTipSetForHeight(ctx, i)
if err != nil {
return xerrors.Errorf("failed to produce head at height %d: %w", i, err)
}
if possibleHeaviestWeight.GreaterThan(newHeaviestWeight) {
newHeaviestWeight = possibleHeaviestWeight
newHeaviest = possibleHeaviestTs
}
}
// if we've found something, we know it's the heaviest equivocation-free head, take it IMMEDIATELY
if newHeaviest != nil {
errTake := cs.takeHeaviestTipSet(ctx, newHeaviest)
if errTake != nil {
return xerrors.Errorf("failed to take newHeaviest tipset as head: %w", err)
}
} else {
// if we haven't found something, just stay with our equivocation-y head
newHeaviest = cs.heaviest
}
}
// if the new height we were notified about isn't what we just refreshed at, see if we have a heavier tipset there
if newTsHeight != newHeaviest.Height() {
bestTs, bestTsWeight, err := cs.FormHeaviestTipSetForHeight(ctx, newTsHeight)
if err != nil {
return xerrors.Errorf("failed to form new heaviest tipset at height %d: %w", newTsHeight, err)
}
heavier := bestTsWeight.GreaterThan(newHeaviestWeight)
if bestTsWeight.Equals(newHeaviestWeight) {
heavier = breakWeightTie(bestTs, newHeaviest)
}
if heavier {
newHeaviest = bestTs
}
}
// Everything's the same as before, exit early
if newHeaviest.Equals(cs.heaviest) {
return nil
}
w, err := cs.weight(ctx, cs.StateBlockstore(), ts)
// At this point, it MUST be true that newHeaviest is heavier than cs.heaviest -- update if fork allows
exceeds, err := cs.exceedsForkLength(ctx, cs.heaviest, newHeaviest)
if err != nil {
return err
return xerrors.Errorf("failed to check fork length: %w", err)
}
heaviestW, err := cs.weight(ctx, cs.StateBlockstore(), cs.heaviest)
if exceeds {
return nil
}
err = cs.takeHeaviestTipSet(ctx, newHeaviest)
if err != nil {
return err
}
heavier := w.GreaterThan(heaviestW)
if w.Equals(heaviestW) && !ts.Equals(cs.heaviest) {
log.Errorw("weight draw", "currTs", cs.heaviest, "ts", ts)
heavier = breakWeightTie(ts, cs.heaviest)
}
if heavier {
// TODO: don't do this for initial sync. Now that we don't have a
// difference between 'bootstrap sync' and 'caught up' sync, we need
// some other heuristic.
exceeds, err := cs.exceedsForkLength(ctx, cs.heaviest, ts)
if err != nil {
return err
}
if exceeds {
return nil
}
return cs.takeHeaviestTipSet(ctx, ts)
return xerrors.Errorf("failed to take heaviest tipset: %w", err)
}
return nil
@@ -655,6 +689,16 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
return err
}
// write the tipsetkey block to the blockstore for EthAPI queries
tsBlk, err := ts.Key().ToStorageBlock()
if err != nil {
return xerrors.Errorf("failed to get tipset key block: %w", err)
}
if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil {
return xerrors.Errorf("failed to put tipset key block: %w", err)
}
if prevHeaviest != nil { // buf
if len(cs.reorgCh) > 0 {
log.Warnf("Reorg channel running behind, %d reorgs buffered", len(cs.reorgCh))
@@ -904,6 +948,14 @@ func ReorgOps(ctx context.Context, lts func(ctx context.Context, _ types.TipSetK
var leftChain, rightChain []*types.TipSet
for !left.Equals(right) {
// this can take a long time and lot of memory if the tipsets are far apart
// since it can be reached through remote calls, we need to
// cancel early when possible to prevent resource exhaustion.
select {
case <-ctx.Done():
return nil, nil, ctx.Err()
default:
}
if left.Height() > right.Height() {
leftChain = append(leftChain, left)
par, err := lts(ctx, left.Parents())
@@ -960,7 +1012,7 @@ func (cs *ChainStore) AddToTipSetTracker(ctx context.Context, b *types.BlockHead
// This means that we ideally want to keep only most recent 900 epochs in here
// Golang's map iteration starts at a random point in a map.
// With 5 tries per epoch, and 900 entries to keep, on average we will have
// ~136 garbage entires in the `cs.tipsets` map. (solve for 1-(1-x/(900+x))^5 == 0.5)
// ~136 garbage entries in the `cs.tipsets` map. (solve for 1-(1-x/(900+x))^5 == 0.5)
// Seems good enough to me
for height := range cs.tipsets {
@@ -975,6 +1027,7 @@ func (cs *ChainStore) AddToTipSetTracker(ctx context.Context, b *types.BlockHead
return nil
}
// PersistTipsets writes the provided blocks and the TipSetKey objects to the blockstore
func (cs *ChainStore) PersistTipsets(ctx context.Context, tipsets []*types.TipSet) error {
toPersist := make([]*types.BlockHeader, 0, len(tipsets)*int(build.BlocksPerEpoch))
tsBlks := make([]block.Block, 0, len(tipsets))
@@ -1027,44 +1080,72 @@ func (cs *ChainStore) persistBlockHeaders(ctx context.Context, b ...*types.Block
return err
}
func (cs *ChainStore) expandTipset(ctx context.Context, b *types.BlockHeader) (*types.TipSet, error) {
// Hold lock for the whole function for now, if it becomes a problem we can
// fix pretty easily
// FormHeaviestTipSetForHeight looks up all valid blocks at a given height, and returns the heaviest tipset that can be made at that height
// It does not consider ANY blocks from miners that have "equivocated" (produced 2 blocks at the same height)
func (cs *ChainStore) FormHeaviestTipSetForHeight(ctx context.Context, height abi.ChainEpoch) (*types.TipSet, types.BigInt, error) {
cs.tstLk.Lock()
defer cs.tstLk.Unlock()
all := []*types.BlockHeader{b}
tsets, ok := cs.tipsets[b.Height]
blockCids, ok := cs.tipsets[height]
if !ok {
return types.NewTipSet(all)
return nil, types.NewInt(0), nil
}
inclMiners := map[address.Address]cid.Cid{b.Miner: b.Cid()}
for _, bhc := range tsets {
if bhc == b.Cid() {
continue
}
// First, identify "bad" miners for the height
seenMiners := map[address.Address]struct{}{}
badMiners := map[address.Address]struct{}{}
blocks := make([]*types.BlockHeader, 0, len(blockCids))
for _, bhc := range blockCids {
h, err := cs.GetBlock(ctx, bhc)
if err != nil {
return nil, xerrors.Errorf("failed to load block (%s) for tipset expansion: %w", bhc, err)
return nil, types.NewInt(0), xerrors.Errorf("failed to load block (%s) for tipset expansion: %w", bhc, err)
}
if cid, found := inclMiners[h.Miner]; found {
log.Warnf("Have multiple blocks from miner %s at height %d in our tipset cache %s-%s", h.Miner, h.Height, h.Cid(), cid)
if _, seen := seenMiners[h.Miner]; seen {
badMiners[h.Miner] = struct{}{}
continue
}
seenMiners[h.Miner] = struct{}{}
blocks = append(blocks, h)
}
if types.CidArrsEqual(h.Parents, b.Parents) {
all = append(all, h)
inclMiners[h.Miner] = bhc
// Next, group by parent tipset
formableTipsets := make(map[types.TipSetKey][]*types.BlockHeader, 0)
for _, h := range blocks {
if _, bad := badMiners[h.Miner]; bad {
continue
}
ptsk := types.NewTipSetKey(h.Parents...)
formableTipsets[ptsk] = append(formableTipsets[ptsk], h)
}
maxWeight := types.NewInt(0)
var maxTs *types.TipSet
for _, headers := range formableTipsets {
ts, err := types.NewTipSet(headers)
if err != nil {
return nil, types.NewInt(0), xerrors.Errorf("unexpected error forming tipset: %w", err)
}
weight, err := cs.Weight(ctx, ts)
if err != nil {
return nil, types.NewInt(0), xerrors.Errorf("failed to calculate weight: %w", err)
}
heavier := weight.GreaterThan(maxWeight)
if weight.Equals(maxWeight) {
heavier = breakWeightTie(ts, maxTs)
}
if heavier {
maxWeight = weight
maxTs = ts
}
}
// TODO: other validation...?
return types.NewTipSet(all)
return maxTs, maxWeight, nil
}
func (cs *ChainStore) GetGenesis(ctx context.Context) (*types.BlockHeader, error) {
+169
View File
@@ -10,6 +10,7 @@ import (
"github.com/ipfs/go-datastore"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
@@ -238,3 +239,171 @@ func TestChainExportImportFull(t *testing.T) {
}
}
}
func TestEquivocations(t *testing.T) {
ctx := context.Background()
cg, err := gen.NewGenerator()
if err != nil {
t.Fatal(err)
}
var last *types.TipSet
for i := 0; i < 10; i++ {
ts, err := cg.NextTipSet()
if err != nil {
t.Fatal(err)
}
last = ts.TipSet.TipSet()
}
mTs, err := cg.NextTipSetFromMiners(last, []address.Address{last.Blocks()[0].Miner}, 0)
require.NoError(t, err)
require.Equal(t, 1, len(mTs.TipSet.TipSet().Cids()))
last = mTs.TipSet.TipSet()
require.NotEmpty(t, last.Blocks())
blk1 := *last.Blocks()[0]
// quick check: asking to form tipset at latest height just returns head
bestHead, bestHeadWeight, err := cg.ChainStore().FormHeaviestTipSetForHeight(ctx, last.Height())
require.NoError(t, err)
require.Equal(t, last.Key(), bestHead.Key())
require.Contains(t, last.Cids(), blk1.Cid())
expectedWeight, err := cg.ChainStore().Weight(ctx, bestHead)
require.NoError(t, err)
require.Equal(t, expectedWeight, bestHeadWeight)
// add another block by a different miner -- it should get included in the best tipset
blk2 := blk1
blk1Miner, err := address.IDFromAddress(blk2.Miner)
require.NoError(t, err)
blk2.Miner, err = address.NewIDAddress(blk1Miner + 50)
require.NoError(t, err)
addBlockToTracker(t, cg.ChainStore(), &blk2)
bestHead, bestHeadWeight, err = cg.ChainStore().FormHeaviestTipSetForHeight(ctx, last.Height())
require.NoError(t, err)
for _, blkCid := range last.Cids() {
require.Contains(t, bestHead.Cids(), blkCid)
}
require.Contains(t, bestHead.Cids(), blk2.Cid())
expectedWeight, err = cg.ChainStore().Weight(ctx, bestHead)
require.NoError(t, err)
require.Equal(t, expectedWeight, bestHeadWeight)
// add another block by a different miner, but on a different tipset -- it should NOT get included
blk3 := blk1
blk3.Miner, err = address.NewIDAddress(blk1Miner + 100)
require.NoError(t, err)
blk1Parent, err := cg.ChainStore().GetBlock(ctx, blk3.Parents[0])
require.NoError(t, err)
blk3.Parents = blk1Parent.Parents
addBlockToTracker(t, cg.ChainStore(), &blk3)
bestHead, bestHeadWeight, err = cg.ChainStore().FormHeaviestTipSetForHeight(ctx, last.Height())
require.NoError(t, err)
for _, blkCid := range last.Cids() {
require.Contains(t, bestHead.Cids(), blkCid)
}
require.Contains(t, bestHead.Cids(), blk2.Cid())
require.NotContains(t, bestHead.Cids(), blk3.Cid())
expectedWeight, err = cg.ChainStore().Weight(ctx, bestHead)
require.NoError(t, err)
require.Equal(t, expectedWeight, bestHeadWeight)
// add another block by the same miner as blk1 -- it should NOT get included, and blk1 should be excluded too
blk4 := blk1
blk4.Timestamp = blk1.Timestamp + 1
addBlockToTracker(t, cg.ChainStore(), &blk4)
bestHead, bestHeadWeight, err = cg.ChainStore().FormHeaviestTipSetForHeight(ctx, last.Height())
require.NoError(t, err)
for _, blkCid := range last.Cids() {
if blkCid != blk1.Cid() {
require.Contains(t, bestHead.Cids(), blkCid)
}
}
require.NotContains(t, bestHead.Cids(), blk4.Cid())
require.NotContains(t, bestHead.Cids(), blk1.Cid())
expectedWeight, err = cg.ChainStore().Weight(ctx, bestHead)
require.NoError(t, err)
require.Equal(t, expectedWeight, bestHeadWeight)
// check that after all of that, the chainstore's head has NOT changed
require.Equal(t, last.Key(), cg.ChainStore().GetHeaviestTipSet().Key())
// NOW, after all that, notify the chainstore to refresh its head
require.NoError(t, cg.ChainStore().RefreshHeaviestTipSet(ctx, blk1.Height+1))
originalHead := *last
newHead := cg.ChainStore().GetHeaviestTipSet()
// the newHead should be at the same height as the originalHead
require.Equal(t, originalHead.Height(), newHead.Height())
// the newHead should NOT be the same as the originalHead
require.NotEqual(t, originalHead.Key(), newHead.Key())
// specifically, it should not contain any blocks by blk1Miner
for _, b := range newHead.Blocks() {
require.NotEqual(t, blk1.Miner, b.Miner)
}
// now have blk2's Miner equivocate too! this causes us to switch to a tipset with a different parent!
blk5 := blk2
blk5.Timestamp = blk5.Timestamp + 1
addBlockToTracker(t, cg.ChainStore(), &blk5)
// notify the chainstore to refresh its head
require.NoError(t, cg.ChainStore().RefreshHeaviestTipSet(ctx, blk1.Height+1))
newHead = cg.ChainStore().GetHeaviestTipSet()
// the newHead should still be at the same height as the originalHead
require.Equal(t, originalHead.Height(), newHead.Height())
// BUT it should no longer have the same parents -- only blk3's miner is good, and they mined on a different tipset
require.Equal(t, 1, len(newHead.Blocks()))
require.Equal(t, blk3.Cid(), newHead.Cids()[0])
require.NotEqual(t, originalHead.Parents(), newHead.Parents())
// now have blk3's Miner equivocate too! this causes us to switch to a previous epoch entirely :(
blk6 := blk3
blk6.Timestamp = blk6.Timestamp + 1
addBlockToTracker(t, cg.ChainStore(), &blk6)
// trying to form a tipset at our previous height leads to emptiness
tryTs, tryTsWeight, err := cg.ChainStore().FormHeaviestTipSetForHeight(ctx, blk1.Height)
require.NoError(t, err)
require.Nil(t, tryTs)
require.True(t, tryTsWeight.IsZero())
// notify the chainstore to refresh its head
require.NoError(t, cg.ChainStore().RefreshHeaviestTipSet(ctx, blk1.Height+1))
newHead = cg.ChainStore().GetHeaviestTipSet()
// the newHead should now be one epoch behind originalHead
require.Greater(t, originalHead.Height(), newHead.Height())
// next, we create a new tipset with only one block after many null rounds
headAfterNulls, err := cg.NextTipSetFromMiners(newHead, []address.Address{newHead.Blocks()[0].Miner}, 15)
require.NoError(t, err)
require.Equal(t, 1, len(headAfterNulls.TipSet.Blocks))
// now, we disqualify the block in this tipset because of equivocation
blkAfterNulls := headAfterNulls.TipSet.TipSet().Blocks()[0]
equivocatedBlkAfterNulls := *blkAfterNulls
equivocatedBlkAfterNulls.Timestamp = blkAfterNulls.Timestamp + 1
addBlockToTracker(t, cg.ChainStore(), &equivocatedBlkAfterNulls)
// try to form a tipset at this height -- it should be empty
tryTs2, tryTsWeight2, err := cg.ChainStore().FormHeaviestTipSetForHeight(ctx, blkAfterNulls.Height)
require.NoError(t, err)
require.Nil(t, tryTs2)
require.True(t, tryTsWeight2.IsZero())
// now we "notify" at this height -- it should lead to no head change because there's no formable head in near epochs
require.NoError(t, cg.ChainStore().RefreshHeaviestTipSet(ctx, blkAfterNulls.Height))
require.True(t, headAfterNulls.TipSet.TipSet().Equals(cg.ChainStore().GetHeaviestTipSet()))
}
func addBlockToTracker(t *testing.T, cs *store.ChainStore, blk *types.BlockHeader) {
blk2Ts, err := types.NewTipSet([]*types.BlockHeader{blk})
require.NoError(t, err)
require.NoError(t, cs.PersistTipsets(context.TODO(), []*types.TipSet{blk2Ts}))
require.NoError(t, cs.AddToTipSetTracker(context.TODO(), blk))
}
+20 -8
View File
@@ -350,6 +350,7 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
)
recordFailure(ctx, metrics.MessageValidationFailure, "add")
switch {
case xerrors.Is(err, messagepool.ErrSoftValidationFailure):
fallthrough
case xerrors.Is(err, messagepool.ErrRBFTooLowPremium):
@@ -362,8 +363,17 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
fallthrough
case xerrors.Is(err, messagepool.ErrNonceTooLow):
fallthrough
case xerrors.Is(err, messagepool.ErrNotEnoughFunds):
fallthrough
case xerrors.Is(err, messagepool.ErrExistingNonce):
return pubsub.ValidationIgnore
case xerrors.Is(err, messagepool.ErrMessageTooBig):
fallthrough
case xerrors.Is(err, messagepool.ErrMessageValueTooHigh):
fallthrough
case xerrors.Is(err, messagepool.ErrInvalidToAddr):
fallthrough
default:
return pubsub.ValidationReject
}
@@ -519,9 +529,8 @@ func (v *IndexerMessageValidator) Validate(ctx context.Context, pid peer.ID, msg
msgCid := idxrMsg.Cid
var msgInfo *peerMsgInfo
msgInfo, ok := v.peerCache.Get(minerAddr)
if !ok {
msgInfo, cached := v.peerCache.Get(minerAddr)
if !cached {
msgInfo = &peerMsgInfo{}
}
@@ -529,17 +538,17 @@ func (v *IndexerMessageValidator) Validate(ctx context.Context, pid peer.ID, msg
msgInfo.mutex.Lock()
defer msgInfo.mutex.Unlock()
if ok {
var seqno uint64
if cached {
// Reject replayed messages.
seqno := binary.BigEndian.Uint64(msg.Message.GetSeqno())
seqno = binary.BigEndian.Uint64(msg.Message.GetSeqno())
if seqno <= msgInfo.lastSeqno {
log.Debugf("ignoring replayed indexer message")
return pubsub.ValidationIgnore
}
msgInfo.lastSeqno = seqno
}
if !ok || originPeer != msgInfo.peerID {
if !cached || originPeer != msgInfo.peerID {
// Check that the miner ID maps to the peer that sent the message.
err = v.authenticateMessage(ctx, minerAddr, originPeer)
if err != nil {
@@ -548,7 +557,7 @@ func (v *IndexerMessageValidator) Validate(ctx context.Context, pid peer.ID, msg
return pubsub.ValidationReject
}
msgInfo.peerID = originPeer
if !ok {
if !cached {
// Add msgInfo to cache only after being authenticated. If two
// messages from the same peer are handled concurrently, there is a
// small chance that one msgInfo could replace the other here when
@@ -557,6 +566,9 @@ func (v *IndexerMessageValidator) Validate(ctx context.Context, pid peer.ID, msg
}
}
// Update message info cache with the latest message's sequence number.
msgInfo.lastSeqno = seqno
// See if message needs to be ignored due to rate limiting.
if v.rateLimitPeer(msgInfo, msgCid) {
return pubsub.ValidationIgnore
+122
View File
@@ -12,10 +12,12 @@ import (
"github.com/ipni/go-libipni/announce/message"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/mocks"
"github.com/filecoin-project/lotus/chain/types"
)
@@ -134,3 +136,123 @@ func TestIndexerMessageValidator_Validate(t *testing.T) {
})
}
}
func TestIdxValidator(t *testing.T) {
validCid, err := cid.Decode("QmbpDgg5kRLDgMxS8vPKNFXEcA6D5MC4CkuUdSWDVtHPGK")
if err != nil {
t.Fatal(err)
}
addr, err := address.NewFromString("f01024")
if err != nil {
t.Fatal(err)
}
buf1, err := addr.MarshalBinary()
if err != nil {
t.Fatal(err)
}
selfPID := "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW"
senderPID := "12D3KooWE8yt84RVwW3sFcd6WMjbUdWrZer2YtT4dmtj3dHdahSZ"
extraData := buf1
mc := gomock.NewController(t)
node := mocks.NewMockFullNode(mc)
node.EXPECT().ChainHead(gomock.Any()).Return(nil, nil).AnyTimes()
subject := NewIndexerMessageValidator(peer.ID(selfPID), node, node)
message := message.Message{
Cid: validCid,
Addrs: nil,
ExtraData: extraData,
}
buf := bytes.NewBuffer(nil)
if err := message.MarshalCBOR(buf); err != nil {
t.Fatal(err)
}
topic := "topic"
privk, _, err := crypto.GenerateKeyPair(crypto.RSA, 2048)
if err != nil {
t.Fatal(err)
}
id, err := peer.IDFromPublicKey(privk.GetPublic())
if err != nil {
t.Fatal(err)
}
node.EXPECT().StateMinerInfo(gomock.Any(), gomock.Any(), gomock.Any()).Return(api.MinerInfo{PeerId: &id}, nil).AnyTimes()
pbm := &pb.Message{
Data: buf.Bytes(),
Topic: &topic,
From: []byte(id),
Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 2},
}
validate := subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
Message: pbm,
ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID),
ValidatorData: nil,
})
if validate != pubsub.ValidationAccept {
t.Error("Expected to receive ValidationAccept")
}
msgInfo, cached := subject.peerCache.Get(addr)
if !cached {
t.Fatal("Message info should be in cache")
}
seqno := msgInfo.lastSeqno
msgInfo.rateLimit = nil // prevent interference from rate limiting
t.Log("Sending DoS msg")
privk, _, err = crypto.GenerateKeyPair(crypto.RSA, 2048)
if err != nil {
t.Fatal(err)
}
id2, err := peer.IDFromPublicKey(privk.GetPublic())
if err != nil {
t.Fatal(err)
}
pbm = &pb.Message{
Data: buf.Bytes(),
Topic: &topic,
From: []byte(id2),
Seqno: []byte{255, 255, 255, 255, 255, 255, 255, 255},
}
validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
Message: pbm,
ReceivedFrom: peer.ID(senderPID),
ValidatorData: nil,
})
if validate != pubsub.ValidationReject {
t.Error("Expected to get ValidationReject")
}
msgInfo, cached = subject.peerCache.Get(addr)
if !cached {
t.Fatal("Message info should be in cache")
}
msgInfo.rateLimit = nil // prevent interference from rate limiting
// Check if DoS is possible.
if msgInfo.lastSeqno != seqno {
t.Fatal("Sequence number should not have been updated")
}
t.Log("Sending another valid message from miner...")
pbm = &pb.Message{
Data: buf.Bytes(),
Topic: &topic,
From: []byte(id),
Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 3},
}
validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
Message: pbm,
ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID),
ValidatorData: nil,
})
if validate != pubsub.ValidationAccept {
t.Fatal("Did not receive ValidationAccept")
}
}
+61
View File
@@ -0,0 +1,61 @@
package ratelimit
import (
"testing"
)
func TestQueue(t *testing.T) {
const size = 3
q := &queue{buf: make([]int64, size)}
if q.len() != 0 {
t.Fatalf("q.len() = %d, expect 0", q.len())
}
if q.cap() != size {
t.Fatalf("q.cap() = %d, expect %d", q.cap(), size)
}
for i := int64(0); i < int64(size); i++ {
err := q.push(i)
if err != nil {
t.Fatalf("cannot push element %d", i)
}
}
if q.len() != size {
t.Fatalf("q.len() = %d, expect %d", q.len(), size)
}
err := q.push(int64(size))
if err != ErrRateLimitExceeded {
t.Fatalf("pushing element beyond capacity should have failed with err: %s, got %s", ErrRateLimitExceeded, err)
}
if q.front() != 0 {
t.Fatalf("q.front() = %d, expect 0", q.front())
}
if q.back() != int64(size-1) {
t.Fatalf("q.back() = %d, expect %d", q.back(), size-1)
}
popVal := q.pop()
if popVal != 0 {
t.Fatalf("q.pop() = %d, expect 0", popVal)
}
if q.len() != size-1 {
t.Fatalf("q.len() = %d, expect %d", q.len(), size-1)
}
// Testing truncation.
threshold := int64(1)
q.truncate(threshold)
if q.len() != 1 {
t.Fatalf("q.len() after truncate = %d, expect 1", q.len())
}
if q.front() != 2 {
t.Fatalf("q.front() after truncate = %d, expect 2", q.front())
}
}
+1 -1
View File
@@ -536,7 +536,7 @@ func (syncer *Syncer) Sync(ctx context.Context, maybeHead *types.TipSet) error {
// At this point we have accepted and synced to the new `maybeHead`
// (`StageSyncComplete`).
if err := syncer.store.PutTipSet(ctx, maybeHead); err != nil {
if err := syncer.store.RefreshHeaviestTipSet(ctx, maybeHead.Height()); err != nil {
span.AddAttributes(trace.StringAttribute("put_error", err.Error()))
span.SetStatus(trace.Status{
Code: 13,
+1
View File
@@ -92,6 +92,7 @@ type syncManager struct {
var _ SyncManager = (*syncManager)(nil)
type peerHead struct {
// Note: this doesn't _necessarily_ mean that p's head is ts, just that ts is a tipset that p sent to us
p peer.ID
ts *types.TipSet
}
+1 -9
View File
@@ -11,7 +11,6 @@ import (
"github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p/core/peer"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
@@ -311,7 +310,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
for _, lastB := range lastTs.Blocks {
require.NoError(tu.t, cs.AddToTipSetTracker(context.Background(), lastB.Header))
}
err = cs.PutTipSet(tu.ctx, lastTs.TipSet())
err = cs.RefreshHeaviestTipSet(tu.ctx, lastTs.TipSet().Height())
require.NoError(tu.t, err)
tu.genesis = genesis
@@ -344,13 +343,6 @@ func (tu *syncTestUtil) addClientNode() int {
return len(tu.nds) - 1
}
func (tu *syncTestUtil) pid(n int) peer.ID {
nal, err := tu.nds[n].NetAddrsListen(tu.ctx)
require.NoError(tu.t, err)
return nal.ID
}
func (tu *syncTestUtil) connect(from, to int) {
toPI, err := tu.nds[to].NetAddrsListen(tu.ctx)
require.NoError(tu.t, err)
-3
View File
@@ -7,9 +7,6 @@ import (
)
func TestDecodeBlockMsg(t *testing.T) {
type args struct {
b []byte
}
tests := []struct {
name string
data []byte
+55
View File
@@ -18,6 +18,7 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
@@ -929,3 +930,57 @@ func (e *EthBlockNumberOrHash) UnmarshalJSON(b []byte) error {
return errors.New("invalid block param")
}
type EthTrace struct {
Action EthTraceAction `json:"action"`
Result EthTraceResult `json:"result"`
Subtraces int `json:"subtraces"`
TraceAddress []int `json:"traceAddress"`
Type string `json:"Type"`
Parent *EthTrace `json:"-"`
// if a subtrace makes a call to GetBytecode, we store a pointer to that subtrace here
// which we then lookup when checking for delegatecall (InvokeContractDelegate)
LastByteCode *EthTrace `json:"-"`
}
func (t *EthTrace) SetCallType(callType string) {
t.Action.CallType = callType
t.Type = callType
}
type EthTraceBlock struct {
*EthTrace
BlockHash EthHash `json:"blockHash"`
BlockNumber int64 `json:"blockNumber"`
TransactionHash EthHash `json:"transactionHash"`
TransactionPosition int `json:"transactionPosition"`
}
type EthTraceReplayBlockTransaction struct {
Output EthBytes `json:"output"`
StateDiff *string `json:"stateDiff"`
Trace []*EthTrace `json:"trace"`
TransactionHash EthHash `json:"transactionHash"`
VmTrace *string `json:"vmTrace"`
}
type EthTraceAction struct {
CallType string `json:"callType"`
From EthAddress `json:"from"`
To EthAddress `json:"to"`
Gas EthUint64 `json:"gas"`
Input EthBytes `json:"input"`
Value EthBigInt `json:"value"`
FilecoinMethod abi.MethodNum `json:"-"`
FilecoinCodeCid cid.Cid `json:"-"`
FilecoinFrom address.Address `json:"-"`
FilecoinTo address.Address `json:"-"`
}
type EthTraceResult struct {
GasUsed EthUint64 `json:"gasUsed"`
Output EthBytes `json:"output"`
}
+7 -2
View File
@@ -134,7 +134,7 @@ func decodeRLP(data []byte) (res interface{}, consumed int, err error) {
return nil, 0, err
}
totalLen := 1 + strLenInBytes + strLen
if totalLen > len(data) {
if totalLen > len(data) || totalLen < 0 {
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
}
return data[1+strLenInBytes : totalLen], totalLen, nil
@@ -157,7 +157,12 @@ func decodeLength(data []byte, lenInBytes int) (length int, err error) {
if err := binary.Read(r, binary.BigEndian, &decodedLength); err != nil {
return 0, xerrors.Errorf("invalid rlp data: cannot parse string length: %w", err)
}
if lenInBytes+int(decodedLength) > len(data) {
if decodedLength < 0 {
return 0, xerrors.Errorf("invalid rlp data: negative string length")
}
totalLength := lenInBytes + int(decodedLength)
if totalLength < 0 || totalLength > len(data) {
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
}
return int(decodedLength), nil
+14
View File
@@ -143,6 +143,20 @@ func TestDecodeList(t *testing.T) {
}
}
func TestDecodeNegativeLength(t *testing.T) {
testcases := [][]byte{
mustDecodeHex("0xbfffffffffffffff0041424344"),
mustDecodeHex("0xc1bFFF1111111111111111"),
mustDecodeHex("0xbFFF11111111111111"),
mustDecodeHex("0xbf7fffffffffffffff41424344"),
}
for _, tc := range testcases {
_, err := DecodeRLP(tc)
require.ErrorContains(t, err, "invalid rlp data")
}
}
func TestDecodeEncodeTx(t *testing.T) {
testcases := [][]byte{
mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000c0"),
-26
View File
@@ -1,11 +1,6 @@
package types
import (
"bytes"
"fmt"
cbg "github.com/whyrusleeping/cbor-gen"
"github.com/filecoin-project/go-state-types/abi"
)
@@ -38,24 +33,3 @@ type EventEntry struct {
}
type FilterID [32]byte // compatible with EthHash
// DecodeEvents decodes a CBOR list of CBOR-encoded events.
func DecodeEvents(input []byte) ([]Event, error) {
r := bytes.NewReader(input)
typ, len, err := cbg.NewCborReader(r).ReadHeader()
if err != nil {
return nil, fmt.Errorf("failed to read events: %w", err)
}
if typ != cbg.MajArray {
return nil, fmt.Errorf("expected a CBOR list, was major type %d", typ)
}
events := make([]Event, 0, len)
for i := 0; i < int(len); i++ {
var evt Event
if err := evt.UnmarshalCBOR(r); err != nil {
return nil, fmt.Errorf("failed to parse event: %w", err)
}
events = append(events, evt)
}
return events, nil
}
-21
View File
@@ -27,24 +27,3 @@ type StateTree interface {
Version() StateTreeVersion
}
type storageWrapper struct {
s Storage
}
func (sw *storageWrapper) Put(i cbg.CBORMarshaler) (cid.Cid, error) {
c, err := sw.s.Put(i)
if err != nil {
return cid.Undef, err
}
return c, nil
}
func (sw *storageWrapper) Get(c cid.Cid, out cbg.CBORUnmarshaler) error {
if err := sw.s.Get(c, out); err != nil {
return err
}
return nil
}
+2 -2
View File
@@ -459,7 +459,7 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet
}
if vm.returnEvents && len(ret.EventsBytes) > 0 {
applyRet.Events, err = types.DecodeEvents(ret.EventsBytes)
applyRet.Events, err = decodeEvents(ret.EventsBytes)
if err != nil {
return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err)
}
@@ -515,7 +515,7 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*
}
if vm.returnEvents && len(ret.EventsBytes) > 0 {
applyRet.Events, err = types.DecodeEvents(ret.EventsBytes)
applyRet.Events, err = decodeEvents(ret.EventsBytes)
if err != nil {
return nil, fmt.Errorf("failed to decode events returned by the FVM: %w", err)
}
+39
View File
@@ -0,0 +1,39 @@
package vm
import (
"bytes"
"fmt"
cbg "github.com/whyrusleeping/cbor-gen"
"github.com/filecoin-project/lotus/chain/types"
)
const MaxEventSliceLength = 6_000_000
// DecodeEvents decodes a CBOR list of CBOR-encoded events.
func decodeEvents(input []byte) ([]types.Event, error) {
r := bytes.NewReader(input)
typ, length, err := cbg.NewCborReader(r).ReadHeader()
if err != nil {
return nil, fmt.Errorf("failed to read events: %w", err)
}
if length > MaxEventSliceLength {
log.Errorf("extremely long event slice (len %d) returned, not decoding", length)
return nil, nil
}
if typ != cbg.MajArray {
return nil, fmt.Errorf("expected a CBOR list, was major type %d", typ)
}
events := make([]types.Event, 0, length)
for i := 0; i < int(length); i++ {
var evt types.Event
if err := evt.UnmarshalCBOR(r); err != nil {
return nil, fmt.Errorf("failed to parse event: %w", err)
}
events = append(events, evt)
}
return events, nil
}
-5
View File
@@ -70,11 +70,6 @@ type syscallShim struct {
}
func (ss *syscallShim) ComputeUnsealedSectorCID(st abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) {
var sum abi.PaddedPieceSize
for _, p := range pieces {
sum += p.Size
}
commd, err := ffiwrapper.GenerateUnsealedCID(st, pieces)
if err != nil {
log.Errorf("generate data commitment failed: %s", err)
+13 -11
View File
@@ -11,7 +11,7 @@ import (
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2"
mh "github.com/multiformats/go-multihash"
"github.com/multiformats/go-multicodec"
cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats"
"go.opencensus.io/trace"
@@ -38,7 +38,6 @@ import (
)
const MaxCallDepth = 4096
const CborCodec = 0x51
var (
log = logging.Logger("vm")
@@ -128,7 +127,7 @@ func (bs *gasChargingBlocks) Put(ctx context.Context, blk block.Block) error {
func (vm *LegacyVM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runtime) *Runtime {
paramsCodec := uint64(0)
if len(msg.Params) > 0 {
paramsCodec = CborCodec
paramsCodec = uint64(multicodec.Cbor)
}
rt := &Runtime{
ctx: ctx,
@@ -380,7 +379,7 @@ func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtim
retCodec := uint64(0)
if len(ret) > 0 {
retCodec = CborCodec
retCodec = uint64(multicodec.Cbor)
}
rt.executionTrace.MsgRct = types.ReturnTrace{
ExitCode: aerrors.RetCode(err),
@@ -695,15 +694,15 @@ func (vm *LegacyVM) ActorStore(ctx context.Context) adt.Store {
}
func linksForObj(blk block.Block, cb func(cid.Cid)) error {
switch blk.Cid().Prefix().Codec {
case cid.DagCBOR:
switch multicodec.Code(blk.Cid().Prefix().Codec) {
case multicodec.DagCbor:
err := cbg.ScanForLinks(bytes.NewReader(blk.RawData()), cb)
if err != nil {
return xerrors.Errorf("cbg.ScanForLinks: %w", err)
}
return nil
case cid.Raw:
// We implicitly have all children of raw blocks.
case multicodec.Raw, multicodec.Cbor:
// We implicitly have all children of raw/cbor blocks.
return nil
default:
return xerrors.Errorf("vm flush copy method only supports dag cbor")
@@ -803,14 +802,17 @@ func copyRec(ctx context.Context, from, to blockstore.Blockstore, root cid.Cid,
}
prefix := link.Prefix()
if prefix.Codec == cid.FilCommitmentSealed || prefix.Codec == cid.FilCommitmentUnsealed {
codec := multicodec.Code(prefix.Codec)
switch codec {
case multicodec.FilCommitmentSealed, cid.FilCommitmentUnsealed:
return
}
// We always have blocks inlined into CIDs, but we may not have their children.
if prefix.MhType == mh.IDENTITY {
if multicodec.Code(prefix.MhType) == multicodec.Identity {
// Unless the inlined block has no children.
if prefix.Codec == cid.Raw {
switch codec {
case multicodec.Raw, multicodec.Cbor:
return
}
} else {
+2 -2
View File
@@ -282,7 +282,7 @@ var NetDisconnect = &cli.Command{
fmt.Println("failure")
return err
}
fmt.Printf("disconnect %s: ", pid.Pretty())
fmt.Printf("disconnect %s: ", pid)
err = api.NetDisconnect(ctx, pid)
if err != nil {
fmt.Println("failure")
@@ -312,7 +312,7 @@ var NetConnect = &cli.Command{
}
for _, pi := range pis {
fmt.Printf("connect %s: ", pi.ID.Pretty())
fmt.Printf("connect %s: ", pi.ID)
err := api.NetConnect(ctx, pi)
if err != nil {
fmt.Println("failure")
+20 -7
View File
@@ -14,6 +14,7 @@ import (
"github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
cliutil "github.com/filecoin-project/lotus/cli/util"
)
var SyncCmd = &cli.Command{
@@ -262,6 +263,9 @@ func SyncWait(ctx context.Context, napi v0api.FullNode, watch bool) error {
}
firstApp = state.VMApplied
// eta computes the ETA for the sync to complete (with a lookback of 10 processed items)
eta := cliutil.NewETA(10)
for {
state, err := napi.SyncState(ctx)
if err != nil {
@@ -273,11 +277,6 @@ func SyncWait(ctx context.Context, napi v0api.FullNode, watch bool) error {
continue
}
head, err := napi.ChainHead(ctx)
if err != nil {
return err
}
working := -1
for i, ss := range state.ActiveSyncs {
switch ss.Stage {
@@ -317,8 +316,10 @@ func SyncWait(ctx context.Context, napi v0api.FullNode, watch bool) error {
fmt.Print("\r\x1b[2K\x1b[A")
}
todo := theight - ss.Height
fmt.Printf("Worker: %d; Base: %d; Target: %d (diff: %d)\n", workerID, baseHeight, theight, heightDiff)
fmt.Printf("State: %s; Current Epoch: %d; Todo: %d\n", ss.Stage, ss.Height, theight-ss.Height)
fmt.Printf("State: %s; Current Epoch: %d; Todo: %d, ETA: %s\n", ss.Stage, ss.Height, todo, eta.Update(int64(todo)))
lastLines = 2
if i%samples == 0 {
@@ -332,7 +333,11 @@ func SyncWait(ctx context.Context, napi v0api.FullNode, watch bool) error {
_ = target // todo: maybe print? (creates a bunch of line wrapping issues with most tipsets)
if !watch && time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) {
isDone, err := IsSyncDone(ctx, napi)
if err != nil {
return err
}
if !watch && isDone {
fmt.Println("\nDone!")
return nil
}
@@ -347,3 +352,11 @@ func SyncWait(ctx context.Context, napi v0api.FullNode, watch bool) error {
i++
}
}
func IsSyncDone(ctx context.Context, napi v0api.FullNode) (bool, error) {
head, err := napi.ChainHead(ctx)
if err != nil {
return false, err
}
return time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs), nil
}
+94
View File
@@ -0,0 +1,94 @@
package cliutil
import (
"fmt"
"math"
"time"
)
// ETA implements a very simple eta calculator based on the number of remaining items. It does not
// require knowing the work size in advance and is therefore suitable for streaming workloads and
// also does not require that consecutive updates have a monotonically decreasing remaining value.
type ETA struct {
// max number of items to keep in memory
maxItems int
// a queue of most recently updated items
items []item
// we store the last calculated ETA which we reuse if there was not change in remaining items
lastETA string
}
type item struct {
timestamp time.Time
remaining int64
}
// NewETA creates a new ETA calculator of the given size
func NewETA(maxItems int) *ETA {
return &ETA{
maxItems: maxItems,
items: make([]item, 0),
}
}
// Update updates the ETA calculator with the remaining number of items and returns the ETA
func (e *ETA) Update(remaining int64) string {
item := item{
timestamp: time.Now(),
remaining: remaining,
}
if len(e.items) == 0 {
e.items = append(e.items, item)
return ""
}
if e.items[len(e.items)-1].remaining == remaining {
// we ignore updates with the same remaining value and just return the previous ETA
return e.lastETA
} else if e.items[len(e.items)-1].remaining < remaining {
// remaining went up from previous update, lets estimate how many items were processed using the
// average number processed items in the queue.
var avgProcessedPerItem int64 = 1
if len(e.items) > 1 {
diffRemaining := e.items[0].remaining - e.items[len(e.items)-1].remaining
avgProcessedPerItem = int64(math.Round(float64(diffRemaining) / float64(len(e.items))))
}
// diff is the difference in increase in remaining since last update plus the average number of processed
// items we estimate that were processed this round
diff := remaining - e.items[len(e.items)-1].remaining + avgProcessedPerItem
// we update all items in the queue by shifting their remaining value accordingly. This means that we
// always have strictly decreasing remaining values in the queue
for i := range e.items {
e.items[i].remaining += diff
}
}
// append the item to the queue and remove the oldest item if needed
if len(e.items) >= e.maxItems {
e.items = e.items[1:]
}
e.items = append(e.items, item)
// calculate the average processing time per item in the queue
diffMs := e.items[len(e.items)-1].timestamp.Sub(e.items[0].timestamp).Milliseconds()
nrItemsProcessed := e.items[0].remaining - e.items[len(e.items)-1].remaining
avg := diffMs / nrItemsProcessed
// use that average processing time to estimate how long the remaining items will take
// and cache that ETA so we don't have to recalculate it on every update unless the
// remaining value changes
e.lastETA = msToETA(avg * remaining)
return e.lastETA
}
func msToETA(ms int64) string {
seconds := ms / 1000
minutes := seconds / 60
hours := minutes / 60
return fmt.Sprintf("%02dh:%02dm:%02ds", hours, minutes%60, seconds%60)
}
+26 -2
View File
@@ -7,7 +7,9 @@ import (
"encoding/json"
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"github.com/urfave/cli/v2"
"golang.org/x/term"
@@ -20,6 +22,7 @@ import (
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/tablewriter"
)
@@ -206,7 +209,12 @@ var walletBalance = &cli.Command{
return err
}
if balance.Equals(types.NewInt(0)) {
inSync, err := IsSyncDone(ctx, api)
if err != nil {
return err
}
if balance.Equals(types.NewInt(0)) && !inSync {
afmt.Printf("%s (warning: may display 0 if chain sync in progress)\n", types.FIL(balance))
} else {
afmt.Printf("%s\n", types.FIL(balance))
@@ -330,6 +338,17 @@ var walletImport = &cli.Command{
if !cctx.Args().Present() || cctx.Args().First() == "-" {
if term.IsTerminal(int(os.Stdin.Fd())) {
fmt.Print("Enter private key(not display in the terminal): ")
sigCh := make(chan os.Signal, 1)
// Notify the channel when SIGINT is received
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigCh
fmt.Println("\nInterrupt signal received. Exiting...")
os.Exit(1)
}()
inpdata, err = term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return err
@@ -441,7 +460,12 @@ var walletSign = &cli.Command{
sig, err := api.WalletSign(ctx, addr, msg)
if err != nil {
return err
// Check if the address is a multisig address
act, actErr := api.StateGetActor(ctx, addr, types.EmptyTSK)
if actErr == nil && builtin.IsMultisigActor(act.Code) {
return xerrors.Errorf("specified signer address is a multisig actor, it doesnt have keys to sign transactions. To send a message with a multisig, signers of the multisig need to propose and approve transactions.")
}
return xerrors.Errorf("failed to sign message: %w", err)
}
sigBytes := append([]byte{byte(sig.Type)}, sig.Data...)
+6
View File
@@ -21,6 +21,7 @@ import (
"github.com/filecoin-project/lotus/api"
apitypes "github.com/filecoin-project/lotus/api/types"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/mock"
)
func TestWalletNew(t *testing.T) {
@@ -133,6 +134,11 @@ func TestWalletBalance(t *testing.T) {
balance := big.NewInt(1234)
// add blocks to the chain
first := mock.TipSet(mock.MkBlock(nil, 5, 4))
head := mock.TipSet(mock.MkBlock(first, 15, 7))
mockApi.EXPECT().ChainHead(ctx).Return(head, nil)
mockApi.EXPECT().WalletBalance(ctx, addr).Return(balance, nil)
//stm: @CLI_WALLET_BALANCE_001
+312
View File
@@ -0,0 +1,312 @@
// Copied from go-amt-ipld https://github.com/filecoin-project/go-amt-ipld/tree/master/internal
// which for some reason is a go internal package and therefore cannot be imported
package main
import (
"fmt"
"io"
"math"
"sort"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
)
type AMTRoot struct {
BitWidth uint64
Height uint64
Count uint64
AMTNode AMTNode
}
type AMTNode struct {
Bmap []byte
Links []cid.Cid
Values []*cbg.Deferred
}
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
var _ = xerrors.Errorf
var _ = cid.Undef
var _ = math.E
var _ = sort.Sort
var lengthBufAMTRoot = []byte{132}
func (t *AMTRoot) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufAMTRoot); err != nil {
return err
}
// t.BitWidth (uint64) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, t.BitWidth); err != nil {
return err
}
// t.Height (uint64) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, t.Height); err != nil {
return err
}
// t.Count (uint64) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, t.Count); err != nil {
return err
}
// t.AMTNode (internal.AMTNode) (struct)
if err := t.AMTNode.MarshalCBOR(cw); err != nil {
return err
}
return nil
}
func (t *AMTRoot) UnmarshalCBOR(r io.Reader) (err error) {
*t = AMTRoot{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 4 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.BitWidth (uint64) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.BitWidth = extra
}
// t.Height (uint64) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Height = extra
}
// t.Count (uint64) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Count = extra
}
// t.AMTNode (internal.AMTNode) (struct)
{
if err := t.AMTNode.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.AMTNode: %w", err)
}
}
return nil
}
var lengthBufAMTNode = []byte{131}
func (t *AMTNode) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufAMTNode); err != nil {
return err
}
// t.Bmap ([]uint8) (slice)
if len(t.Bmap) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.Bmap was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Bmap))); err != nil {
return err
}
if _, err := cw.Write(t.Bmap[:]); err != nil {
return err
}
// t.Links ([]cid.Cid) (slice)
if len(t.Links) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Links was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Links))); err != nil {
return err
}
for _, v := range t.Links {
if err := cbg.WriteCid(w, v); err != nil {
return xerrors.Errorf("failed writing cid field t.Links: %w", err)
}
}
// t.Values ([]*typegen.Deferred) (slice)
if len(t.Values) > cbg.MaxLength {
return xerrors.Errorf("Slice value in field t.Values was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Values))); err != nil {
return err
}
for _, v := range t.Values {
if err := v.MarshalCBOR(cw); err != nil {
return err
}
}
return nil
}
func (t *AMTNode) UnmarshalCBOR(r io.Reader) (err error) {
*t = AMTNode{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 3 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Bmap ([]uint8) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.Bmap: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.Bmap = make([]uint8, extra)
}
if _, err := io.ReadFull(cr, t.Bmap[:]); err != nil {
return err
}
// t.Links ([]cid.Cid) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Links: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Links = make([]cid.Cid, extra)
}
for i := 0; i < int(extra); i++ {
c, err := cbg.ReadCid(cr)
if err != nil {
return xerrors.Errorf("reading cid field t.Links failed: %w", err)
}
t.Links[i] = c
}
// t.Values ([]*typegen.Deferred) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > cbg.MaxLength {
return fmt.Errorf("t.Values: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Values = make([]*cbg.Deferred, extra)
}
for i := 0; i < int(extra); i++ {
var v cbg.Deferred
if err := v.UnmarshalCBOR(cr); err != nil {
return err
}
t.Values[i] = &v
}
return nil
}
+312
View File
@@ -0,0 +1,312 @@
package main
import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"strconv"
"strings"
"sync"
"time"
"github.com/urfave/cli/v2"
)
var cliCmd = &cli.Command{
Name: "cli",
Usage: "Runs a concurrent stress test on one or more binaries commands and prints the performance metrics including latency distribution and histogram",
Description: `This benchmark has the following features:
* Can query each command both sequentially and concurrently
* Supports rate limiting
* Can query multiple different commands at once (supporting different concurrency level and rate limiting for each command)
* Gives a nice reporting summary of the stress testing of each command (including latency distribution, histogram and more)
* Easy to use
To use this benchmark you must specify the commands you want to test using the --cmd options, the format of it is:
--cmd=CMD[:CONCURRENCY][:QPS] where only NAME is required.
Here are some real examples:
lotus-bench cli --cmd='lotus-shed mpool miner-select-messages' // runs the command with default concurrency and qps
lotus-bench cli --cmd='lotus-shed mpool miner-select-messages:3' // override concurrency to 3
lotus-bench cli --cmd='lotus-shed mpool miner-select-messages::100' // override to 100 qps while using default concurrency
lotus-bench cli --cmd='lotus-shed mpool miner-select-messages:3:100' // run using 3 workers but limit to 100 qps
lotus-bench cli --cmd='lotus-shed mpool miner-select-messages' --cmd='lotus sync wait' // run two commands at once
`,
Flags: []cli.Flag{
&cli.DurationFlag{
Name: "duration",
Value: 60 * time.Second,
Usage: "Duration of benchmark in seconds",
},
&cli.IntFlag{
Name: "concurrency",
Value: 10,
Usage: "How many workers should be used per command (can be overridden per command)",
},
&cli.IntFlag{
Name: "qps",
Value: 0,
Usage: "How many requests per second should be sent per command (can be overridden per command), a value of 0 means no limit",
},
&cli.StringSliceFlag{
Name: "cmd",
Usage: `Command to benchmark, you can specify multiple commands by repeating this flag. You can also specify command specific options to set the concurrency and qps for each command (see usage).`,
},
&cli.DurationFlag{
Name: "watch",
Value: 0 * time.Second,
Usage: "If >0 then generates reports every N seconds (only supports linux/unix)",
},
&cli.BoolFlag{
Name: "print-response",
Value: false,
Usage: "print the response of each request",
},
},
Action: func(cctx *cli.Context) error {
if len(cctx.StringSlice("cmd")) == 0 {
return errors.New("you must specify and least one cmd to benchmark")
}
var cmds []*CMD
for _, str := range cctx.StringSlice("cmd") {
entries := strings.SplitN(str, ":", 3)
if len(entries) == 0 {
return errors.New("invalid cmd format")
}
// check if concurrency was specified
concurrency := cctx.Int("concurrency")
if len(entries) > 1 {
if len(entries[1]) > 0 {
var err error
concurrency, err = strconv.Atoi(entries[1])
if err != nil {
return fmt.Errorf("could not parse concurrency value from command %s: %v", entries[0], err)
}
}
}
// check if qps was specified
qps := cctx.Int("qps")
if len(entries) > 2 {
if len(entries[2]) > 0 {
var err error
qps, err = strconv.Atoi(entries[2])
if err != nil {
return fmt.Errorf("could not parse qps value from command %s: %v", entries[0], err)
}
}
}
cmds = append(cmds, &CMD{
w: os.Stdout,
cmd: entries[0],
concurrency: concurrency,
qps: qps,
printResp: cctx.Bool("print-response"),
})
}
// terminate early on ctrl+c
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
fmt.Println("Received interrupt, stopping...")
for _, cmd := range cmds {
cmd.Stop()
}
}()
// stop all threads after duration
go func() {
time.Sleep(cctx.Duration("duration"))
for _, cmd := range cmds {
cmd.Stop()
}
}()
// start all threads
var wg sync.WaitGroup
wg.Add(len(cmds))
for _, cmd := range cmds {
go func(cmd *CMD) {
defer wg.Done()
err := cmd.Run()
if err != nil {
fmt.Printf("error running cmd: %v\n", err)
}
}(cmd)
}
// if watch is set then print a report every N seconds
var progressCh chan struct{}
if cctx.Duration("watch") > 0 {
progressCh = make(chan struct{}, 1)
go func(progressCh chan struct{}) {
ticker := time.NewTicker(cctx.Duration("watch"))
for {
clearAndPrintReport := func() {
// clear the screen move the cursor to the top left
fmt.Print("\033[2J")
fmt.Printf("\033[%d;%dH", 1, 1)
for i, cmd := range cmds {
cmd.Report()
if i < len(cmds)-1 {
fmt.Println()
}
}
}
select {
case <-ticker.C:
clearAndPrintReport()
case <-progressCh:
clearAndPrintReport()
return
}
}
}(progressCh)
}
wg.Wait()
if progressCh != nil {
// wait for the watch go routine to return
progressCh <- struct{}{}
// no need to print the report again
return nil
}
// print the report for each command
for i, cmd := range cmds {
cmd.Report()
if i < len(cmds)-1 {
fmt.Println()
}
}
return nil
},
}
// CMD handles the benchmarking of a single command.
type CMD struct {
w io.Writer
// the cmd we want to benchmark
cmd string
// the number of concurrent requests to make to this command
concurrency int
// if >0 then limit to qps is the max number of requests per second to make to this command (0 = no limit)
qps int
// whether or not to print the response of each request (useful for debugging)
printResp bool
// instruct the worker go routines to stop
stopCh chan struct{}
// when the command bencharking started
start time.Time
// results channel is used by the workers to send results to the reporter
results chan *result
// reporter handles reading the results from workers and printing the report statistics
reporter *Reporter
}
func (c *CMD) Run() error {
var wg sync.WaitGroup
wg.Add(c.concurrency)
c.results = make(chan *result, c.concurrency*1_000)
c.stopCh = make(chan struct{}, c.concurrency)
go func() {
c.reporter = NewReporter(c.results, c.w)
c.reporter.Run()
}()
c.start = time.Now()
// throttle the number of requests per second
var qpsTicker *time.Ticker
if c.qps > 0 {
qpsTicker = time.NewTicker(time.Second / time.Duration(c.qps))
}
for i := 0; i < c.concurrency; i++ {
go func() {
c.startWorker(qpsTicker)
wg.Done()
}()
}
wg.Wait()
// close the results channel so reporter will stop
close(c.results)
// wait until the reporter is done
<-c.reporter.doneCh
return nil
}
func (c *CMD) startWorker(qpsTicker *time.Ticker) {
for {
// check if we should stop
select {
case <-c.stopCh:
return
default:
}
// wait for the next tick if we are rate limiting this command
if qpsTicker != nil {
<-qpsTicker.C
}
start := time.Now()
var statusCode int = 0
arr := strings.Fields(c.cmd)
data, err := exec.Command(arr[0], arr[1:]...).Output()
if err != nil {
fmt.Println("1")
if exitError, ok := err.(*exec.ExitError); ok {
statusCode = exitError.ExitCode()
} else {
statusCode = 1
}
} else {
if c.printResp {
fmt.Printf("[%s] %s", c.cmd, string(data))
}
}
c.results <- &result{
statusCode: &statusCode,
err: err,
duration: time.Since(start),
}
}
}
func (c *CMD) Stop() {
for i := 0; i < c.concurrency; i++ {
c.stopCh <- struct{}{}
}
}
func (c *CMD) Report() {
total := time.Since(c.start)
fmt.Fprintf(c.w, "[%s]:\n", c.cmd)
fmt.Fprintf(c.w, "- Options:\n")
fmt.Fprintf(c.w, " - concurrency: %d\n", c.concurrency)
fmt.Fprintf(c.w, " - qps: %d\n", c.qps)
c.reporter.Print(total, c.w)
}
-15
View File
@@ -497,21 +497,6 @@ type Invocation struct {
const GasPerNs = 10
func countGasCosts(et *types.ExecutionTrace) int64 {
var cgas int64
for _, gc := range et.GasCharges {
cgas += gc.ComputeGas
}
for _, sub := range et.Subcalls {
c := countGasCosts(&sub) //nolint
cgas += c
}
return cgas
}
type stats struct {
timeTaken meanVar
gasRatio meanVar
+219
View File
@@ -1,6 +1,7 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
@@ -8,9 +9,16 @@ import (
"math/rand"
"os"
"path/filepath"
"sync"
"time"
"github.com/docker/go-units"
"github.com/ipfs/boxo/blockservice"
"github.com/ipfs/boxo/ipld/merkledag"
"github.com/ipfs/go-cid"
offline "github.com/ipfs/go-ipfs-exchange-offline"
cbor "github.com/ipfs/go-ipld-cbor"
format "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log/v2"
"github.com/minio/blake2b-simd"
"github.com/mitchellh/go-homedir"
@@ -20,10 +28,14 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-paramfetch"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
prooftypes "github.com/filecoin-project/go-state-types/proof"
adt "github.com/filecoin-project/specs-actors/v6/actors/util/adt"
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
@@ -104,9 +116,11 @@ func main() {
DisableSliceFlagSeparator: true,
Commands: []*cli.Command{
proveCmd,
amtBenchCmd,
sealBenchCmd,
simpleCmd,
importBenchCmd,
cliCmd,
rpcCmd,
},
}
@@ -117,6 +131,211 @@ func main() {
}
}
type amtStatCollector struct {
ds format.NodeGetter
walk func(format.Node) ([]*format.Link, error)
statsLk sync.Mutex
totalAMTLinks int
totalAMTValues int
totalAMTLinkNodes int
totalAMTValueNodes int
totalAMTLinkNodeSize int
totalAMTValueNodeSize int
}
func (asc *amtStatCollector) String() string {
asc.statsLk.Lock()
defer asc.statsLk.Unlock()
str := "\n------------\n"
str += fmt.Sprintf("Link Count: %d\n", asc.totalAMTLinks)
str += fmt.Sprintf("Value Count: %d\n", asc.totalAMTValues)
str += fmt.Sprintf("%d link nodes %d bytes\n", asc.totalAMTLinkNodes, asc.totalAMTLinkNodeSize)
str += fmt.Sprintf("%d value nodes %d bytes\n", asc.totalAMTValueNodes, asc.totalAMTValueNodeSize)
str += fmt.Sprintf("Total bytes: %d\n------------\n", asc.totalAMTLinkNodeSize+asc.totalAMTValueNodeSize)
return str
}
func (asc *amtStatCollector) record(ctx context.Context, nd format.Node) error {
size, err := nd.Size()
if err != nil {
return err
}
var node AMTNode
if err := node.UnmarshalCBOR(bytes.NewReader(nd.RawData())); err != nil {
// try to deserialize root
var root AMTRoot
if err := root.UnmarshalCBOR(bytes.NewReader(nd.RawData())); err != nil {
return err
}
node = root.AMTNode
}
asc.statsLk.Lock()
defer asc.statsLk.Unlock()
link := len(node.Links) > 0
value := len(node.Values) > 0
if link {
asc.totalAMTLinks += len(node.Links)
asc.totalAMTLinkNodes++
asc.totalAMTLinkNodeSize += int(size)
} else if value {
asc.totalAMTValues += len(node.Values)
asc.totalAMTValueNodes++
asc.totalAMTValueNodeSize += int(size)
} else {
return xerrors.Errorf("unexpected AMT node %x: neither link nor value", nd.RawData())
}
return nil
}
func (asc *amtStatCollector) walkLinks(ctx context.Context, c cid.Cid) ([]*format.Link, error) {
nd, err := asc.ds.Get(ctx, c)
if err != nil {
return nil, err
}
if err := asc.record(ctx, nd); err != nil {
return nil, err
}
return asc.walk(nd)
}
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 {
continue
}
out = append(out, link)
}
return out, nil
}
var amtBenchCmd = &cli.Command{
Name: "amt",
Usage: "Benchmark AMT churn",
Flags: []cli.Flag{
&cli.IntFlag{
Name: "rounds",
Usage: "rounds of churn to measure",
Value: 1,
},
&cli.IntFlag{
Name: "interval",
Usage: "AMT idx interval for churning values",
Value: 2880,
},
&cli.IntFlag{
Name: "bitwidth",
Usage: "AMT bitwidth",
Value: 6,
},
},
Action: func(c *cli.Context) error {
bs := blockstore.NewMemory()
ctx := c.Context
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
// Setup in memory blockstore
bitwidth := c.Int("bitwidth")
array, err := adt.MakeEmptyArray(store, bitwidth)
if err != nil {
return err
}
// Using motivating empirical example: market actor states AMT
// Create 40,000,000 states for realistic workload
fmt.Printf("Populating AMT\n")
for i := 0; i < 40000000; i++ {
if err := array.Set(uint64(i), &market.DealState{
SectorStartEpoch: abi.ChainEpoch(2000000 + i),
LastUpdatedEpoch: abi.ChainEpoch(-1),
SlashEpoch: -1,
VerifiedClaim: verifreg.AllocationId(i),
}); err != nil {
return err
}
}
r, err := array.Root()
if err != nil {
return err
}
// Measure ratio of internal / leaf nodes / sizes
dag := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
asc := &amtStatCollector{
ds: dag,
walk: carWalkFunc,
}
fmt.Printf("Measuring AMT\n")
seen := cid.NewSet()
if err := merkledag.Walk(ctx, asc.walkLinks, r, seen.Visit, merkledag.Concurrent()); err != nil {
return err
}
fmt.Printf("%s\n", asc)
// Overwrite ids with idx % interval: one epoch of market cron
rounds := c.Int("rounds")
interval := c.Int("interval")
fmt.Printf("Overwrite 1 out of %d values for %d rounds\n", interval, rounds)
array, err = adt.AsArray(store, r, bitwidth)
if err != nil {
return err
}
roots := make([]cid.Cid, rounds)
for j := 0; j < rounds; j++ {
if j%10 == 0 {
fmt.Printf("round: %d\n", j)
}
for i := j; i < 40000000; i += interval {
if i%interval == j {
if err := array.Set(uint64(i), &market.DealState{
SectorStartEpoch: abi.ChainEpoch(2000000 + i),
LastUpdatedEpoch: abi.ChainEpoch(1),
SlashEpoch: -1,
VerifiedClaim: verifreg.AllocationId(i),
}); err != nil {
return err
}
}
}
roots[j], err = array.Root()
if err != nil {
return err
}
}
// Measure churn
dag = merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
asc = &amtStatCollector{
ds: dag,
walk: carWalkFunc,
}
fmt.Printf("Measuring %d rounds of churn\n", rounds)
for _, r := range roots {
if err := merkledag.Walk(ctx, asc.walkLinks, r, seen.Visit, merkledag.Concurrent()); err != nil {
return err
}
}
fmt.Printf("%s\n", asc)
return nil
},
}
var sealBenchCmd = &cli.Command{
Name: "sealing",
Usage: "Benchmark seal and winning post and window post",
+181
View File
@@ -0,0 +1,181 @@
package main
import (
"fmt"
"io"
"sort"
"strings"
"sync"
"text/tabwriter"
"time"
)
// result is the result of a single rpc method request.
type result struct {
err error
statusCode *int
duration time.Duration
}
// Reporter reads the results from the workers through the results channel and aggregates the results.
type Reporter struct {
// write the report to this writer
w io.Writer
// the reporter read the results from this channel
results chan *result
// doneCh is used to signal that the reporter has finished reading the results (channel has closed)
doneCh chan bool
// lock protect the following fields during critical sections (if --watch was specified)
lock sync.Mutex
// the latencies of all requests
latencies []int64
// the number of requests that returned each status code
statusCodes map[int]int
// the number of errors that occurred
errors map[string]int
}
func NewReporter(results chan *result, w io.Writer) *Reporter {
return &Reporter{
w: w,
results: results,
doneCh: make(chan bool, 1),
statusCodes: make(map[int]int),
errors: make(map[string]int),
}
}
func (r *Reporter) Run() {
for res := range r.results {
r.lock.Lock()
r.latencies = append(r.latencies, res.duration.Milliseconds())
if res.statusCode != nil {
r.statusCodes[*res.statusCode]++
}
if res.err != nil {
if len(r.errors) < 1_000_000 {
r.errors[res.err.Error()]++
} else {
// we don't want to store too many errors in memory
r.errors["hidden"]++
}
} else {
r.errors["nil"]++
}
r.lock.Unlock()
}
r.doneCh <- true
}
func (r *Reporter) Print(elapsed time.Duration, w io.Writer) {
r.lock.Lock()
defer r.lock.Unlock()
nrReq := int64(len(r.latencies))
if nrReq == 0 {
fmt.Println("No requests were made")
return
}
// we need to sort the latencies slice to calculate the percentiles
sort.Slice(r.latencies, func(i, j int) bool {
return r.latencies[i] < r.latencies[j]
})
var totalLatency int64 = 0
for _, latency := range r.latencies {
totalLatency += latency
}
fmt.Fprintf(w, "- Total Requests: %d\n", nrReq)
fmt.Fprintf(w, "- Total Duration: %dms\n", elapsed.Milliseconds())
fmt.Fprintf(w, "- Requests/sec: %f\n", float64(nrReq)/elapsed.Seconds())
fmt.Fprintf(w, "- Avg latency: %dms\n", totalLatency/nrReq)
fmt.Fprintf(w, "- Median latency: %dms\n", r.latencies[nrReq/2])
fmt.Fprintf(w, "- Latency distribution:\n")
percentiles := []float64{0.1, 0.5, 0.9, 0.95, 0.99, 0.999}
for _, p := range percentiles {
idx := int64(p * float64(nrReq))
fmt.Fprintf(w, " %s%% in %dms\n", fmt.Sprintf("%.2f", p*100.0), r.latencies[idx])
}
// create a simple histogram with 10 buckets spanning the range of latency
// into equal ranges
//
nrBucket := 10
buckets := make([]Bucket, nrBucket)
latencyRange := r.latencies[len(r.latencies)-1]
bucketRange := latencyRange / int64(nrBucket)
// mark the end of each bucket
for i := 0; i < nrBucket; i++ {
buckets[i].start = int64(i) * bucketRange
buckets[i].end = buckets[i].start + bucketRange
// extend the last bucked by any remaning range caused by the integer division
if i == nrBucket-1 {
buckets[i].end = latencyRange
}
}
// count the number of requests in each bucket
currBucket := 0
for i := 0; i < len(r.latencies); {
if r.latencies[i] <= buckets[currBucket].end {
buckets[currBucket].cnt++
i++
} else {
currBucket++
}
}
// print the histogram using a tabwriter which will align the columns nicely
fmt.Fprintf(w, "- Histogram:\n")
const padding = 2
tabWriter := tabwriter.NewWriter(w, 0, 0, padding, ' ', tabwriter.AlignRight|tabwriter.Debug)
for i := 0; i < nrBucket; i++ {
ratio := float64(buckets[i].cnt) / float64(nrReq)
bars := strings.Repeat("#", int(ratio*100))
fmt.Fprintf(tabWriter, " %d-%dms\t%d\t%s (%s%%)\n", buckets[i].start, buckets[i].end, buckets[i].cnt, bars, fmt.Sprintf("%.2f", ratio*100))
}
tabWriter.Flush() //nolint:errcheck
fmt.Fprintf(w, "- Status codes:\n")
for code, cnt := range r.statusCodes {
fmt.Fprintf(w, " [%d]: %d\n", code, cnt)
}
// print the 10 most occurring errors (in case error values are not unique)
//
type kv struct {
err string
cnt int
}
var sortedErrors []kv
for err, cnt := range r.errors {
sortedErrors = append(sortedErrors, kv{err, cnt})
}
sort.Slice(sortedErrors, func(i, j int) bool {
return sortedErrors[i].cnt > sortedErrors[j].cnt
})
fmt.Fprintf(w, "- Errors (top 10):\n")
for i, se := range sortedErrors {
if i > 10 {
break
}
fmt.Fprintf(w, " [%s]: %d\n", se.err, se.cnt)
}
}
type Bucket struct {
start int64
// the end value of the bucket
end int64
// how many entries are in the bucket
cnt int
}
-172
View File
@@ -9,11 +9,9 @@ import (
"net/http"
"os"
"os/signal"
"sort"
"strconv"
"strings"
"sync"
"text/tabwriter"
"time"
"github.com/urfave/cli/v2"
@@ -243,13 +241,6 @@ type RPCMethod struct {
reporter *Reporter
}
// result is the result of a single rpc method request.
type result struct {
err error
statusCode *int
duration time.Duration
}
func (rpc *RPCMethod) Run() error {
client := &http.Client{
Timeout: 0,
@@ -411,166 +402,3 @@ func (rpc *RPCMethod) Report() {
fmt.Fprintf(rpc.w, " - qps: %d\n", rpc.qps)
rpc.reporter.Print(total, rpc.w)
}
// Reporter reads the results from the workers through the results channel and aggregates the results.
type Reporter struct {
// write the report to this writer
w io.Writer
// the reporter read the results from this channel
results chan *result
// doneCh is used to signal that the reporter has finished reading the results (channel has closed)
doneCh chan bool
// lock protect the following fields during critical sections (if --watch was specified)
lock sync.Mutex
// the latencies of all requests
latencies []int64
// the number of requests that returned each status code
statusCodes map[int]int
// the number of errors that occurred
errors map[string]int
}
func NewReporter(results chan *result, w io.Writer) *Reporter {
return &Reporter{
w: w,
results: results,
doneCh: make(chan bool, 1),
statusCodes: make(map[int]int),
errors: make(map[string]int),
}
}
func (r *Reporter) Run() {
for res := range r.results {
r.lock.Lock()
r.latencies = append(r.latencies, res.duration.Milliseconds())
if res.statusCode != nil {
r.statusCodes[*res.statusCode]++
}
if res.err != nil {
if len(r.errors) < 1_000_000 {
r.errors[res.err.Error()]++
} else {
// we don't want to store too many errors in memory
r.errors["hidden"]++
}
} else {
r.errors["nil"]++
}
r.lock.Unlock()
}
r.doneCh <- true
}
func (r *Reporter) Print(elapsed time.Duration, w io.Writer) {
r.lock.Lock()
defer r.lock.Unlock()
nrReq := int64(len(r.latencies))
if nrReq == 0 {
fmt.Println("No requests were made")
return
}
// we need to sort the latencies slice to calculate the percentiles
sort.Slice(r.latencies, func(i, j int) bool {
return r.latencies[i] < r.latencies[j]
})
var totalLatency int64 = 0
for _, latency := range r.latencies {
totalLatency += latency
}
fmt.Fprintf(w, "- Total Requests: %d\n", nrReq)
fmt.Fprintf(w, "- Total Duration: %dms\n", elapsed.Milliseconds())
fmt.Fprintf(w, "- Requests/sec: %f\n", float64(nrReq)/elapsed.Seconds())
fmt.Fprintf(w, "- Avg latency: %dms\n", totalLatency/nrReq)
fmt.Fprintf(w, "- Median latency: %dms\n", r.latencies[nrReq/2])
fmt.Fprintf(w, "- Latency distribution:\n")
percentiles := []float64{0.1, 0.5, 0.9, 0.95, 0.99, 0.999}
for _, p := range percentiles {
idx := int64(p * float64(nrReq))
fmt.Fprintf(w, " %s%% in %dms\n", fmt.Sprintf("%.2f", p*100.0), r.latencies[idx])
}
// create a simple histogram with 10 buckets spanning the range of latency
// into equal ranges
//
nrBucket := 10
buckets := make([]Bucket, nrBucket)
latencyRange := r.latencies[len(r.latencies)-1]
bucketRange := latencyRange / int64(nrBucket)
// mark the end of each bucket
for i := 0; i < nrBucket; i++ {
buckets[i].start = int64(i) * bucketRange
buckets[i].end = buckets[i].start + bucketRange
// extend the last bucked by any remaning range caused by the integer division
if i == nrBucket-1 {
buckets[i].end = latencyRange
}
}
// count the number of requests in each bucket
currBucket := 0
for i := 0; i < len(r.latencies); {
if r.latencies[i] <= buckets[currBucket].end {
buckets[currBucket].cnt++
i++
} else {
currBucket++
}
}
// print the histogram using a tabwriter which will align the columns nicely
fmt.Fprintf(w, "- Histogram:\n")
const padding = 2
tabWriter := tabwriter.NewWriter(w, 0, 0, padding, ' ', tabwriter.AlignRight|tabwriter.Debug)
for i := 0; i < nrBucket; i++ {
ratio := float64(buckets[i].cnt) / float64(nrReq)
bars := strings.Repeat("#", int(ratio*100))
fmt.Fprintf(tabWriter, " %d-%dms\t%d\t%s (%s%%)\n", buckets[i].start, buckets[i].end, buckets[i].cnt, bars, fmt.Sprintf("%.2f", ratio*100))
}
tabWriter.Flush() //nolint:errcheck
fmt.Fprintf(w, "- Status codes:\n")
for code, cnt := range r.statusCodes {
fmt.Fprintf(w, " [%d]: %d\n", code, cnt)
}
// print the 10 most occurring errors (in case error values are not unique)
//
type kv struct {
err string
cnt int
}
var sortedErrors []kv
for err, cnt := range r.errors {
sortedErrors = append(sortedErrors, kv{err, cnt})
}
sort.Slice(sortedErrors, func(i, j int) bool {
return sortedErrors[i].cnt > sortedErrors[j].cnt
})
fmt.Fprintf(w, "- Errors (top 10):\n")
for i, se := range sortedErrors {
if i > 10 {
break
}
fmt.Fprintf(w, " [%s]: %d\n", se.err, se.cnt)
}
}
type Bucket struct {
start int64
// the end value of the bucket
end int64
// how many entries are in the bucket
cnt int
}
+5
View File
@@ -120,6 +120,11 @@ p: pvC0JBrEyUqtIIUvB2UUx/2a24c3Cvnu6AZ0D3IMBYAu...
type benchSectorProvider map[storiface.SectorFileType]string
func (b benchSectorProvider) AcquireSectorCopy(ctx context.Context, id storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, ptype storiface.PathType) (storiface.SectorPaths, func(), error) {
// there's no copying in this context
return b.AcquireSector(ctx, id, existing, allocate, ptype)
}
func (b benchSectorProvider) AcquireSector(ctx context.Context, id storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, ptype storiface.PathType) (storiface.SectorPaths, func(), error) {
out := storiface.SectorPaths{
ID: id.ID,
+2
View File
@@ -2566,6 +2566,8 @@ var sectorsUnsealCmd = &cli.Command{
return xerrors.Errorf("could not parse sector number: %w", err)
}
fmt.Printf("Unsealing sector %d\n", sectorNum)
return minerAPI.SectorUnseal(ctx, abi.SectorNumber(sectorNum))
},
}
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/urfave/cli/v2"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
var blockCmd = &cli.Command{
Name: "block",
Usage: "Output decoded block header in readeble form",
ArgsUsage: "[block header hex]",
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
}
b, err := hex.DecodeString(cctx.Args().First())
if err != nil {
return err
}
var blk types.BlockHeader
if err := blk.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
return err
}
jb, err := json.MarshalIndent(blk, "", " ")
if err != nil {
return err
}
fmt.Println(string(jb))
return nil
},
}
+249
View File
@@ -1,14 +1,24 @@
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/ipfs/go-cid"
ipldcbor "github.com/ipfs/go-ipld-cbor"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-bitfield"
"github.com/filecoin-project/go-state-types/abi"
miner11 "github.com/filecoin-project/go-state-types/builtin/v11/miner"
"github.com/filecoin-project/go-state-types/builtin/v11/util/adt"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
lcli "github.com/filecoin-project/lotus/cli"
)
@@ -17,6 +27,245 @@ var cronWcCmd = &cli.Command{
Description: "cron stats",
Subcommands: []*cli.Command{
minerDeadlineCronCountCmd,
minerDeadlinePartitionMeasurementCmd,
},
}
type DeadlineRef struct {
To string
Height abi.ChainEpoch
Gas json.RawMessage
}
type DeadlineSummary struct {
Partitions []PartitionSummary
PreCommitExpiry PreCommitExpiry
VestingDiff VestingDiff
}
type PreCommitExpiry struct {
Expired []uint64
}
type VestingDiff struct {
PrevTableSize int
NewTableSize int
}
type PartitionSummary struct {
Live int
Dead int
Faulty int
Diff PartitionDiff
}
type PartitionDiff struct {
Faulted int
Recovered int
Killed int
}
var minerDeadlinePartitionMeasurementCmd = &cli.Command{
Name: "deadline-summary",
Description: "",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "json",
Usage: "read input as json",
Value: true,
},
&cli.StringFlag{
Name: "tipset",
Usage: "specify tipset state to search on (pass comma separated array of cids)",
},
},
Action: func(c *cli.Context) error {
// read in values to process
if !c.Bool("json") {
return xerrors.Errorf("unsupported non json input format")
}
var refStream []DeadlineRef
if err := json.NewDecoder(os.Stdin).Decode(&refStream); err != nil {
return xerrors.Errorf("failed to parse input: %w", err)
}
// go from height and sp addr to deadline partition data
n, acloser, err := lcli.GetFullNodeAPI(c)
if err != nil {
return err
}
defer acloser()
ctx := lcli.ReqContext(c)
bs := ReadOnlyAPIBlockstore{n}
adtStore := adt.WrapStore(ctx, ipldcbor.NewCborStore(&bs))
dSummaries := make([]DeadlineSummary, len(refStream))
for j, ref := range refStream {
// get miner's deadline
tsBefore, err := n.ChainGetTipSetByHeight(ctx, ref.Height, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("failed to get tipset at epoch: %d: %w", ref.Height, err)
}
tsAfter, err := n.ChainGetTipSetByHeight(ctx, ref.Height+1, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("failed to get tipset at epoch %d: %w", ref.Height, err)
}
addr, err := address.NewFromString(ref.To)
if err != nil {
return xerrors.Errorf("faield to get address from input string: %w", err)
}
dline, err := n.StateMinerProvingDeadline(ctx, addr, tsBefore.Key())
if err != nil {
return xerrors.Errorf("failed to read proving deadline: %w", err)
}
// iterate through all partitions at epoch of processing
var pSummaries []PartitionSummary
psBefore, err := n.StateMinerPartitions(ctx, addr, dline.Index, tsBefore.Key())
if err != nil {
return xerrors.Errorf("failed to get partitions: %w", err)
}
psAfter, err := n.StateMinerPartitions(ctx, addr, dline.Index, tsAfter.Key())
if err != nil {
return xerrors.Errorf("failed to get partitions: %w", err)
}
if len(psBefore) != len(psAfter) {
return xerrors.Errorf("faield")
}
type partitionCount struct {
live int
dead int
faulty int
recovering int
}
countPartition := func(p api.Partition) (partitionCount, error) {
liveSectors, err := p.LiveSectors.All(abi.MaxSectorNumber)
if err != nil {
return partitionCount{}, xerrors.Errorf("failed to count live sectors in partition: %w", err)
}
allSectors, err := p.AllSectors.All(abi.MaxSectorNumber)
if err != nil {
return partitionCount{}, xerrors.Errorf("failed to count all sectors in partition: %w", err)
}
faultySectors, err := p.FaultySectors.All(abi.MaxSectorNumber)
if err != nil {
return partitionCount{}, xerrors.Errorf("failed to count faulty sectors in partition: %w", err)
}
recoveringSectors, err := p.RecoveringSectors.All(abi.MaxSectorNumber)
if err != nil {
return partitionCount{}, xerrors.Errorf("failed to count recovering sectors in partition: %w", err)
}
return partitionCount{
live: len(liveSectors),
dead: len(allSectors) - len(liveSectors),
faulty: len(faultySectors),
recovering: len(recoveringSectors),
}, nil
}
countVestingTable := func(table cid.Cid) (int, error) {
var vestingTable miner11.VestingFunds
if err := adtStore.Get(ctx, table, &vestingTable); err != nil {
return 0, err
}
return len(vestingTable.Funds), nil
}
for i := 0; i < len(psBefore); i++ {
cntBefore, err := countPartition(psBefore[i])
if err != nil {
return err
}
cntAfter, err := countPartition(psAfter[i])
if err != nil {
return err
}
pSummaries = append(pSummaries, PartitionSummary{
Live: cntBefore.live,
Dead: cntBefore.dead,
Faulty: cntBefore.faulty,
Diff: PartitionDiff{
Faulted: cntAfter.faulty - cntBefore.faulty,
Recovered: cntBefore.recovering - cntAfter.recovering,
Killed: cntAfter.dead - cntBefore.dead,
},
})
}
// Precommit and vesting table data
// Before
aBefore, err := n.StateGetActor(ctx, addr, tsBefore.Key())
if err != nil {
return err
}
var st miner11.State
err = adtStore.Get(ctx, aBefore.Head, &st)
if err != nil {
return err
}
expiryQArray, err := adt.AsArray(adtStore, st.PreCommittedSectorsCleanUp, miner11.PrecommitCleanUpAmtBitwidth)
if err != nil {
return err
}
var sectorsBf bitfield.BitField
var accumulator []uint64
h := ref.Height
if err := expiryQArray.ForEach(&sectorsBf, func(i int64) error {
if abi.ChainEpoch(i) > h {
return nil
}
sns, err := sectorsBf.All(abi.MaxSectorNumber)
if err != nil {
return err
}
accumulator = append(accumulator, sns...)
return nil
}); err != nil {
return err
}
vestingBefore, err := countVestingTable(st.VestingFunds)
if err != nil {
return err
}
// After
aAfter, err := n.StateGetActor(ctx, addr, tsAfter.Key())
if err != nil {
return err
}
var stAfter miner11.State
err = adtStore.Get(ctx, aAfter.Head, &stAfter)
if err != nil {
return err
}
vestingAfter, err := countVestingTable(stAfter.VestingFunds)
if err != nil {
return err
}
dSummaries[j] = DeadlineSummary{
Partitions: pSummaries,
PreCommitExpiry: PreCommitExpiry{
Expired: accumulator,
},
VestingDiff: VestingDiff{
PrevTableSize: vestingBefore,
NewTableSize: vestingAfter,
},
}
}
// output partition info
if err := json.NewEncoder(os.Stdout).Encode(dSummaries); err != nil {
return err
}
return nil
},
}
+1 -1
View File
@@ -219,7 +219,7 @@ func backTestWinner(ctx context.Context, miner address.Address, round abi.ChainE
brand = bvals[len(bvals)-1]
}
winner, err := gen.IsRoundWinner(ctx, ts, round, miner, brand, mbi, api)
winner, err := gen.IsRoundWinner(ctx, round, miner, brand, mbi, api)
if err != nil {
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
}
+7 -17
View File
@@ -16,7 +16,6 @@ import (
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/beacon/drand"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
@@ -100,15 +99,11 @@ var gasTraceCmd = &cli.Command{
return err
}
dcs := build.DrandConfigSchedule()
shd := beacon.Schedule{}
for _, dc := range dcs {
bc, err := drand.NewDrandBeacon(MAINNET_GENESIS_TIME, build.BlockDelaySecs, nil, dc.Config)
if err != nil {
return xerrors.Errorf("creating drand beacon: %w", err)
}
shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc})
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), MAINNET_GENESIS_TIME, nil)
if err != nil {
return err
}
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck
@@ -200,14 +195,9 @@ var replayOfflineCmd = &cli.Command{
return err
}
dcs := build.DrandConfigSchedule()
shd := beacon.Schedule{}
for _, dc := range dcs {
bc, err := drand.NewDrandBeacon(MAINNET_GENESIS_TIME, build.BlockDelaySecs, nil, dc.Config)
if err != nil {
return xerrors.Errorf("creating drand beacon: %w", err)
}
shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc})
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), MAINNET_GENESIS_TIME, nil)
if err != nil {
return err
}
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
+292
View File
@@ -1,6 +1,7 @@
package main
import (
"context"
"database/sql"
"fmt"
"path"
@@ -8,12 +9,18 @@ import (
"strings"
"github.com/mitchellh/go-homedir"
"github.com/multiformats/go-varint"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/exitcode"
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
lcli "github.com/filecoin-project/lotus/cli"
)
@@ -31,6 +38,291 @@ var indexesCmd = &cli.Command{
withCategory("msgindex", backfillMsgIndexCmd),
withCategory("msgindex", pruneMsgIndexCmd),
withCategory("txhash", backfillTxHashCmd),
withCategory("events", backfillEventsCmd),
},
}
var backfillEventsCmd = &cli.Command{
Name: "backfill-events",
Usage: "Backfill the events.db for a number of epochs starting from a specified height",
Flags: []cli.Flag{
&cli.UintFlag{
Name: "from",
Value: 0,
Usage: "the tipset height to start backfilling from (0 is head of chain)",
},
&cli.IntFlag{
Name: "epochs",
Value: 2000,
Usage: "the number of epochs to backfill",
},
},
Action: func(cctx *cli.Context) error {
srv, err := lcli.GetFullNodeServices(cctx)
if err != nil {
return err
}
defer srv.Close() //nolint:errcheck
api := srv.FullNodeAPI()
ctx := lcli.ReqContext(cctx)
// currTs will be the tipset where we start backfilling from
currTs, err := api.ChainHead(ctx)
if err != nil {
return err
}
if cctx.IsSet("from") {
// we need to fetch the tipset after the epoch being specified since we will need to advance currTs
currTs, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int("from")+1), currTs.Key())
if err != nil {
return err
}
}
// advance currTs by one epoch and maintain prevTs as the previous tipset (this allows us to easily use the ChainGetParentMessages/Receipt API)
prevTs := currTs
currTs, err = api.ChainGetTipSet(ctx, currTs.Parents())
if err != nil {
return fmt.Errorf("failed to load tipset %s: %w", prevTs.Parents(), err)
}
epochs := cctx.Int("epochs")
basePath, err := homedir.Expand(cctx.String("repo"))
if err != nil {
return err
}
dbPath := path.Join(basePath, "sqlite", "events.db")
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
return err
}
defer func() {
err := db.Close()
if err != nil {
fmt.Printf("ERROR: closing db: %s", err)
}
}()
addressLookups := make(map[abi.ActorID]address.Address)
resolveFn := func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
// we only want to match using f4 addresses
idAddr, err := address.NewIDAddress(uint64(emitter))
if err != nil {
return address.Undef, false
}
actor, err := api.StateGetActor(ctx, idAddr, ts.Key())
if err != nil || actor.Address == nil {
return address.Undef, false
}
// if robust address is not f4 then we won't match against it so bail early
if actor.Address.Protocol() != address.Delegated {
return address.Undef, false
}
// we have an f4 address, make sure it's assigned by the EAM
if namespace, _, err := varint.FromUvarint(actor.Address.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID {
return address.Undef, false
}
return *actor.Address, true
}
isIndexedValue := func(b uint8) bool {
// currently we mark the full entry as indexed if either the key
// or the value are indexed; in the future we will need finer-grained
// management of indices
return b&(types.EventFlagIndexedKey|types.EventFlagIndexedValue) > 0
}
var totalEventsAffected int64
var totalEntriesAffected int64
processHeight := func(ctx context.Context, cnt int, msgs []lapi.Message, receipts []*types.MessageReceipt) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to start transaction: %w", err)
}
defer tx.Rollback() //nolint:errcheck
stmtSelectEvent, err := tx.Prepare("SELECT MAX(id) from event WHERE height=? AND tipset_key=? and tipset_key_cid=? and emitter_addr=? and event_index=? and message_cid=? and message_index=? and reverted=false")
if err != nil {
return err
}
stmtEvent, err := tx.Prepare("INSERT INTO event (height, tipset_key, tipset_key_cid, emitter_addr, event_index, message_cid, message_index, reverted) VALUES(?, ?, ?, ?, ?, ?, ?, ?)")
if err != nil {
return err
}
stmtEntry, err := tx.Prepare("INSERT INTO event_entry(event_id, indexed, flags, key, codec, value) VALUES(?, ?, ?, ?, ?, ?)")
if err != nil {
return err
}
var eventsAffected int64
var entriesAffected int64
// loop over each message receipt and backfill the events
for idx, receipt := range receipts {
msg := msgs[idx]
if receipt.ExitCode != exitcode.Ok {
continue
}
if receipt.EventsRoot == nil {
continue
}
events, err := api.ChainGetEvents(ctx, *receipt.EventsRoot)
if err != nil {
return fmt.Errorf("failed to load events for tipset %s: %w", currTs, err)
}
for eventIdx, event := range events {
addr, found := addressLookups[event.Emitter]
if !found {
var ok bool
addr, ok = resolveFn(ctx, event.Emitter, currTs)
if !ok {
// not an address we will be able to match against
continue
}
addressLookups[event.Emitter] = addr
}
tsKeyCid, err := currTs.Key().Cid()
if err != nil {
return fmt.Errorf("failed to get tipset key cid: %w", err)
}
// select the highest event id that exists in database, or null if none exists
var entryID sql.NullInt64
err = stmtSelectEvent.QueryRow(
currTs.Height(),
currTs.Key().Bytes(),
tsKeyCid.Bytes(),
addr.Bytes(),
eventIdx,
msg.Cid.Bytes(),
idx,
).Scan(&entryID)
if err != nil {
return fmt.Errorf("error checking if event exists: %w", err)
}
// we already have this event
if entryID.Valid {
continue
}
// event does not exist, lets backfill it
res, err := tx.Stmt(stmtEvent).Exec(
currTs.Height(), // height
currTs.Key().Bytes(), // tipset_key
tsKeyCid.Bytes(), // tipset_key_cid
addr.Bytes(), // emitter_addr
eventIdx, // event_index
msg.Cid.Bytes(), // message_cid
idx, // message_index
false, // reverted
)
if err != nil {
return fmt.Errorf("error inserting event: %w", err)
}
entryID.Int64, err = res.LastInsertId()
if err != nil {
return fmt.Errorf("could not get last insert id: %w", err)
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return fmt.Errorf("could not get rows affected: %w", err)
}
eventsAffected += rowsAffected
// backfill the event entries
for _, entry := range event.Entries {
_, err := tx.Stmt(stmtEntry).Exec(
entryID.Int64, // event_id
isIndexedValue(entry.Flags), // indexed
[]byte{entry.Flags}, // flags
entry.Key, // key
entry.Codec, // codec
entry.Value, // value
)
if err != nil {
return fmt.Errorf("error inserting entry: %w", err)
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return fmt.Errorf("could not get rows affected: %w", err)
}
entriesAffected += rowsAffected
}
}
}
err = tx.Commit()
if err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
log.Infof("[%d] backfilling actor events epoch:%d, eventsAffected:%d, entriesAffected:%d", cnt, currTs.Height(), eventsAffected, entriesAffected)
totalEventsAffected += eventsAffected
totalEntriesAffected += entriesAffected
return nil
}
for i := 0; i < epochs; i++ {
select {
case <-ctx.Done():
return nil
default:
}
blockCid := prevTs.Blocks()[0].Cid()
// get messages for the parent of the previous tipset (which will be currTs)
msgs, err := api.ChainGetParentMessages(ctx, blockCid)
if err != nil {
return fmt.Errorf("failed to get parent messages for block %s: %w", blockCid, err)
}
// get receipts for the parent of the previous tipset (which will be currTs)
receipts, err := api.ChainGetParentReceipts(ctx, blockCid)
if err != nil {
return fmt.Errorf("failed to get parent receipts for block %s: %w", blockCid, err)
}
if len(msgs) != len(receipts) {
return fmt.Errorf("mismatched in message and receipt count: %d != %d", len(msgs), len(receipts))
}
err = processHeight(ctx, i, msgs, receipts)
if err != nil {
return err
}
// advance prevTs and currTs up the chain
prevTs = currTs
currTs, err = api.ChainGetTipSet(ctx, currTs.Parents())
if err != nil {
return fmt.Errorf("failed to load tipset %s: %w", currTs, err)
}
}
log.Infof("backfilling events complete, totalEventsAffected:%d, totalEntriesAffected:%d", totalEventsAffected, totalEntriesAffected)
return nil
},
}
+2
View File
@@ -24,6 +24,7 @@ func main() {
local := []*cli.Command{
addressCmd,
statActorCmd,
statSnapshotCmd,
statObjCmd,
base64Cmd,
base32Cmd,
@@ -90,6 +91,7 @@ func main() {
indexesCmd,
FevmAnalyticsCmd,
mismatchesCmd,
blockCmd,
}
app := &cli.App{
+14
View File
@@ -2,6 +2,7 @@ package main
import (
"fmt"
"time"
"github.com/urfave/cli/v2"
@@ -43,10 +44,20 @@ var minerSelectMsgsCmd = &cli.Command{
return err
}
// Get the size of the mempool
pendingMsgs, err := api.MpoolPending(ctx, types.EmptyTSK)
if err != nil {
return err
}
mpoolSize := len(pendingMsgs)
// Measure the time taken by MpoolSelect
startTime := time.Now()
msgs, err := api.MpoolSelect(ctx, head.Key(), cctx.Float64("ticket-quality"))
if err != nil {
return err
}
duration := time.Since(startTime)
var totalGas int64
for i, f := range msgs {
@@ -64,6 +75,9 @@ var minerSelectMsgsCmd = &cli.Command{
totalGas += f.Message.GasLimit
}
// Log the duration, size of the mempool, selected messages and total gas limit of selected messages
fmt.Printf("Message selection took %s\n", duration)
fmt.Printf("Size of the mempool: %d\n", mpoolSize)
fmt.Println("selected messages: ", len(msgs))
fmt.Printf("total gas limit of selected messages: %d / %d (%0.2f%%)\n", totalGas, build.BlockGasLimit, 100*float64(totalGas)/float64(build.BlockGasLimit))
return nil
+48
View File
@@ -26,6 +26,12 @@ var msgCmd = &cli.Command{
Aliases: []string{"msg"},
Usage: "Translate message between various formats",
ArgsUsage: "Message in any form",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "exec-trace",
Usage: "Print the execution trace",
},
},
Action: func(cctx *cli.Context) error {
if cctx.NArg() != 1 {
return lcli.IncorrectNumArgs(cctx)
@@ -36,6 +42,48 @@ var msgCmd = &cli.Command{
return err
}
api, closer, err := lcli.GetFullNodeAPI(cctx)
if err != nil {
return err
}
defer closer()
ctx := lcli.ReqContext(cctx)
// Get the CID of the message
mcid := msg.Cid()
// Search for the message on-chain
lookup, err := api.StateSearchMsg(ctx, mcid)
if err != nil {
return err
}
if lookup == nil {
fmt.Println("Message not found on-chain. Continuing...")
} else {
// Replay the message to get the execution trace
res, err := api.StateReplay(ctx, types.EmptyTSK, mcid)
if err != nil {
return xerrors.Errorf("replay call failed: %w", err)
}
if cctx.Bool("exec-trace") {
// Print the execution trace
color.Green("Execution trace:")
trace, err := json.MarshalIndent(res.ExecutionTrace, "", " ")
if err != nil {
return xerrors.Errorf("marshaling execution trace: %w", err)
}
fmt.Println(string(trace))
fmt.Println()
color.Green("Receipt:")
fmt.Printf("Exit code: %d\n", res.MsgRct.ExitCode)
fmt.Printf("Return: %x\n", res.MsgRct.Return)
fmt.Printf("Gas Used: %d\n", res.MsgRct.GasUsed)
}
}
switch msg := msg.(type) {
case *types.SignedMessage:
return printSignedMessage(cctx, msg)
+503 -79
View File
@@ -1,11 +1,14 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"path"
"reflect"
"sort"
"sync"
"github.com/docker/go-units"
@@ -21,8 +24,12 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
gstactors "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
@@ -49,6 +56,19 @@ type fieldItem struct {
Stats api.ObjStat
}
type job struct {
c cid.Cid
key string // prefix path for the region being recorded i.e. "/state/mineractor"
}
type cidCall struct {
c cid.Cid
resp chan bool
}
type result struct {
key string
stats api.ObjStat
}
type cacheNodeGetter struct {
ds format.NodeGetter
cache *lru.TwoQueueCache[cid.Cid, format.Node]
@@ -166,39 +186,13 @@ var statObjCmd = &cli.Command{
return err
}
r, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return xerrors.Errorf("opening fs repo: %w", err)
}
exists, err := r.Exists()
h, err := loadChainStore(ctx, cctx.String("repo"))
if err != nil {
return err
}
if !exists {
return xerrors.Errorf("lotus repo doesn't exist")
}
defer h.closer()
lr, err := r.Lock(repo.FullNode)
if err != nil {
return err
}
defer lr.Close() //nolint:errcheck
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return fmt.Errorf("failed to open blockstore: %w", err)
}
defer func() {
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}()
dag := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
dag := merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs)))
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
@@ -212,6 +206,376 @@ var statObjCmd = &cli.Command{
},
}
type StoreHandle struct {
bs blockstore.Blockstore
cs *store.ChainStore
sm *stmgr.StateManager
closer func()
}
func loadChainStore(ctx context.Context, repoPath string) (*StoreHandle, error) {
r, err := repo.NewFS(repoPath)
if err != nil {
return nil, xerrors.Errorf("opening fs repo: %w", err)
}
exists, err := r.Exists()
if err != nil {
return nil, err
}
if !exists {
return nil, xerrors.Errorf("lotus repo doesn't exist")
}
lr, err := r.Lock(repo.FullNode)
if err != nil {
return nil, err
}
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return nil, fmt.Errorf("failed to open blockstore: %w", err)
}
closer := func() {
if err := lr.Close(); err != nil {
log.Warnf("failed to close locked repo: %s", err)
}
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}
mds, err := lr.Datastore(context.Background(), "/metadata")
if err != nil {
return nil, err
}
cs := store.NewChainStore(bs, bs, mds, nil, nil)
if err := cs.Load(ctx); err != nil {
return nil, fmt.Errorf("failed to load chain store: %w", err)
}
tsExec := consensus.NewTipSetExecutor(filcns.RewardFunc)
sm, err := stmgr.NewStateManager(cs, tsExec, vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil, mds, index.DummyMsgIndex)
if err != nil {
return nil, fmt.Errorf("failed to open state manager: %w", err)
}
handle := StoreHandle{
bs: bs,
sm: sm,
cs: cs,
closer: closer,
}
return &handle, nil
}
func pipeline(ctx context.Context, name string, numWorkers int, createJobs func(ctx context.Context, jobCh chan job, resultCh chan result) error,
worker func(ctx context.Context, id int, jobCh chan job, resultCh chan result) error,
processResults func(ctx context.Context, resultCh chan result) error) error {
eg, egctx := errgroup.WithContext(ctx)
jobCh := make(chan job, numWorkers)
resultCh := make(chan result)
var resultWriterWg sync.WaitGroup
resultWriterWg.Add(1)
eg.Go(func() error {
defer resultWriterWg.Done()
defer func() {
close(jobCh)
}()
return createJobs(ctx, jobCh, resultCh)
})
var id int
for w := 0; w < numWorkers; w++ {
id = w
resultWriterWg.Add(1)
eg.Go(func() error {
defer resultWriterWg.Done()
return worker(egctx, id, jobCh, resultCh)
})
}
eg.Go(func() error {
return processResults(ctx, resultCh)
})
// close result channel when workers are done sending to it.
eg.Go(func() error {
resultWriterWg.Wait()
close(resultCh)
return nil
})
if err := eg.Wait(); err != nil {
return fmt.Errorf("failed pipeline %s: %w", name, err)
}
return nil
}
var statSnapshotCmd = &cli.Command{
Name: "stat-snapshot",
Usage: "calculates the space usage of a snapshot taken from the given tipset",
Description: `Walk the chain back to lightweight snapshot size and break down space usage into high level
categories: headers, messages, receipts, latest state root, and churn from earlier state roots.
State root and churn space is further broken down by actor type and immediate top level fields
`,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "tipset",
Usage: "specify tipset to call method on (pass comma separated array of cids)",
},
&cli.IntFlag{
Name: "workers",
Usage: "number of workers to use when processing",
Value: 10,
},
&cli.IntFlag{
Name: "dag-cache-size",
Usage: "cache size per worker (setting to 0 disables)",
Value: 8092,
},
&cli.BoolFlag{
Name: "pretty",
Usage: "print formated output instead of ldjson",
Value: false,
},
},
Action: func(cctx *cli.Context) error {
ctx := lcli.ReqContext(cctx)
h, err := loadChainStore(ctx, cctx.String("repo"))
if err != nil {
return err
}
defer h.closer()
tsr := &ChainStoreTipSetResolver{
Chain: h.cs,
}
ts, err := lcli.LoadTipSet(ctx, cctx, tsr)
if err != nil {
return err
}
numWorkers := cctx.Int("workers")
dagCacheSize := cctx.Int("dag-cache-size")
cidCh := make(chan cidCall, numWorkers)
summary := make(map[string]api.ObjStat)
// snapshot root objects with no additional bytes or links
summary["/"] = api.ObjStat{Size: 0, Links: 0}
summary["/statetree"] = api.ObjStat{Size: 0, Links: 0}
combine := func(statsA, statsB api.ObjStat) api.ObjStat {
return api.ObjStat{
Size: statsA.Size + statsB.Size,
Links: statsA.Links + statsB.Links,
}
}
// Threadsafe cid set lives across different pipelines so not part of error group
go func() {
seen := cid.NewSet()
for {
select {
case call := <-cidCh:
call.resp <- seen.Visit(call.c)
case <-ctx.Done():
log.Infof("shutting down cid set goroutine: %s", ctx.Err())
return
}
}
}()
visit := func(c cid.Cid) bool {
ch := make(chan bool)
cidCh <- cidCall{c: c, resp: ch}
out := <-ch
return out
}
// Stage 1 walk all actors in latest state root
createJobsStage1 := func(ctx context.Context, jobCh chan job, _ chan result) error {
st, err := h.sm.StateTree(ts.ParentState())
if err != nil {
return err
}
return st.ForEach(func(_ address.Address, act *types.Actor) error {
actType := builtin.ActorNameByCode(act.Code)
actType = path.Base(actType) // strip away fil/<nv>
if actType == "<unknown>" {
actType = act.Code.String()
}
jobCh <- job{c: act.Head, key: fmt.Sprintf("/statetree/latest/%s", actType)}
return nil
})
}
worker := func(ctx context.Context, id int, jobCh chan job, resultCh chan result) error {
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs)))
if dagCacheSize != 0 {
var err error
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs))), dagCacheSize)
if err != nil {
return err
}
}
for job := range jobCh {
stats, err := collectSnapshotJobStats(ctx, job, dag, visit)
if err != nil {
return err
}
for _, stat := range stats {
select {
case resultCh <- stat:
case <-ctx.Done():
return ctx.Err()
}
}
}
return nil
}
processResults := func(ctx context.Context, resultCh chan result) error {
for result := range resultCh {
if stat, ok := summary[result.key]; ok {
summary[result.key] = combine(stat, result.stats)
} else {
summary[result.key] = result.stats
}
}
return nil
}
if err := pipeline(ctx, "Latest State Actors", numWorkers, createJobsStage1, worker, processResults); err != nil {
return err
}
// Stage 2: walk the top of the latest state root
createJobsStage2 := func(ctx context.Context, jobCh chan job, _ chan result) error {
jobCh <- job{c: ts.ParentState(), key: "/statetree/latest"}
return nil
}
if err := pipeline(ctx, "Latest State HAMT", numWorkers, createJobsStage2, worker, processResults); err != nil {
return err
}
// Stage 3 walk the rest of the chain: headers, messages, churn
// ordering:
// for each header send jobs for messages, receipts, state tree churn
// don't walk header directly as it would just walk everything including parent tipsets
churnStateRoots := cid.NewSet()
createJobsStage3 := func(ctx context.Context, jobCh chan job, resultCh chan result) error {
// walk chain
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs)))
if dagCacheSize != 0 {
var err error
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs))), dagCacheSize)
if err != nil {
return err
}
}
blocksToWalk := ts.Cids()
startHeight := ts.Height()
snapshotStateLimit := abi.ChainEpoch(2000)
churnActorCache := cid.NewSet()
blocksTracked := cid.NewSet()
for len(blocksToWalk) > 0 {
blkCid := blocksToWalk[0]
blocksToWalk = blocksToWalk[1:]
nd, err := dag.Get(ctx, blkCid)
if err != nil {
return xerrors.Errorf("getting block: %w", err)
}
var b types.BlockHeader
if err := b.UnmarshalCBOR(bytes.NewBuffer(nd.RawData())); err != nil {
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blkCid, err)
}
// header directly to result channel
resultCh <- result{key: "/headers", stats: api.ObjStat{Size: uint64(len(nd.RawData())), Links: uint64(len(nd.Links()))}}
// message job
if b.Height > startHeight-snapshotStateLimit {
jobCh <- job{key: "/messages", c: b.Messages}
}
// state churn job
if b.Height > startHeight-snapshotStateLimit {
if churnStateRoots.Visit(b.ParentStateRoot) {
st, err := h.sm.StateTree(b.ParentStateRoot)
if err != nil {
return err
}
err = st.ForEach(func(_ address.Address, act *types.Actor) error {
if churnActorCache.Visit(act.Head) {
actType := builtin.ActorNameByCode(act.Code)
actType = path.Base(actType) // strip away fil/<nv>
if actType == "<unknown>" {
actType = act.Code.String()
}
jobCh <- job{c: act.Head, key: fmt.Sprintf("/statetree/churn/%s", actType)}
}
return nil
})
if err != nil {
return err
}
}
}
for _, blkCid := range b.Parents {
if blocksTracked.Visit(blkCid) && b.Height != 0 {
blocksToWalk = append(blocksToWalk, blkCid)
}
}
}
return nil
}
if err := pipeline(ctx, "Churn, Headers, Messages", numWorkers, createJobsStage3, worker, processResults); err != nil {
return err
}
// step 1 clean things up and get a nice abstraction to reuse
// Stage 4 walk all actor HAMTs for churn
createJobsStage4 := func(ctx context.Context, jobCh chan job, _ chan result) error {
return churnStateRoots.ForEach(func(c cid.Cid) error {
jobCh <- job{c: c, key: "/statetree/churn"}
return nil
})
}
if err := pipeline(ctx, "Churn HAMT", numWorkers, createJobsStage4, worker, processResults); err != nil {
return err
}
if cctx.Bool("pretty") {
DumpSnapshotStats(summary)
} else {
if err := DumpJSON(summary); err != nil {
return err
}
}
return nil
},
}
var statActorCmd = &cli.Command{
Name: "stat-actor",
Usage: "calculates the size of actors and their immeidate structures",
@@ -265,57 +629,14 @@ to reduce the number of decode operations performed by caching the decoded objec
addrs = append(addrs, addr)
}
}
r, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return xerrors.Errorf("opening fs repo: %w", err)
}
exists, err := r.Exists()
if err != nil {
return err
}
if !exists {
return xerrors.Errorf("lotus repo doesn't exist")
}
lr, err := r.Lock(repo.FullNode)
if err != nil {
return err
}
defer lr.Close() //nolint:errcheck
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
if err != nil {
return fmt.Errorf("failed to open blockstore: %w", err)
}
defer func() {
if c, ok := bs.(io.Closer); ok {
if err := c.Close(); err != nil {
log.Warnf("failed to close blockstore: %s", err)
}
}
}()
mds, err := lr.Datastore(context.Background(), "/metadata")
if err != nil {
return err
}
cs := store.NewChainStore(bs, bs, mds, nil, nil)
if err := cs.Load(ctx); err != nil {
return nil
}
tsExec := consensus.NewTipSetExecutor(filcns.RewardFunc)
sm, err := stmgr.NewStateManager(cs, tsExec, vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil, mds, index.DummyMsgIndex)
h, err := loadChainStore(ctx, cctx.String("repo"))
if err != nil {
return err
}
defer h.closer()
tsr := &ChainStoreTipSetResolver{
Chain: cs,
Chain: h.cs,
}
ts, err := lcli.LoadTipSet(ctx, cctx, tsr)
@@ -327,7 +648,7 @@ to reduce the number of decode operations performed by caching the decoded objec
if len(addrs) == 0 && cctx.Bool("all") {
var err error
addrs, err = sm.ListAllActors(ctx, ts)
addrs, err = h.sm.ListAllActors(ctx, ts)
if err != nil {
return err
}
@@ -354,15 +675,15 @@ to reduce the number of decode operations performed by caching the decoded objec
return nil
}
actor, err := sm.LoadActor(ctx, addr, ts)
actor, err := h.sm.LoadActor(ctx, addr, ts)
if err != nil {
return err
}
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs)))
if dagCacheSize != 0 {
var err error
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs))), dagCacheSize)
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(h.bs, offline.Exchange(h.bs))), dagCacheSize)
if err != nil {
return err
}
@@ -427,6 +748,93 @@ to reduce the number of decode operations performed by caching the decoded objec
},
}
func collectSnapshotJobStats(ctx context.Context, in job, dag format.NodeGetter, visit func(c cid.Cid) bool) ([]result, error) {
// "state" and "churn" attempt further breakdown by actor type
if !(path.Dir(in.key) == "/statetree/latest") && !(path.Dir(in.key) == "/statetree/churn") {
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, in.c, visit, merkledag.Concurrent()); err != nil {
return nil, err
}
return []result{{key: in.key, stats: dsc.stats}}, nil
}
// in.c is an actor head cid, try to unmarshal and create sub keys for different regions of state
nd, err := dag.Get(ctx, in.c)
if err != nil {
return nil, err
}
subjobs := make([]job, 0)
results := make([]result, 0)
// reconstruct actor for state parsing from key
av, err := gstactors.VersionForNetwork(network.Version20)
if err != nil {
return nil, fmt.Errorf("failed to get actors version for network: %w", err)
}
code, ok := actors.GetActorCodeID(av, path.Base(in.key))
if !ok { // try parsing key directly
code, err = cid.Parse(path.Base(in.key))
if err != nil {
log.Debugf("failing to parse actor string: %s", path.Base(in.key))
}
}
actor := types.ActorV5{Head: in.c, Code: code}
oif, err := vm.DumpActorState(consensus.NewTipSetExecutor(filcns.RewardFunc).NewActorRegistry(), &actor, nd.RawData())
if err != nil {
oif = nil
}
// Account actors return nil from DumpActorState as they have no state
if oif != nil {
v := reflect.Indirect(reflect.ValueOf(oif))
for i := 0; i < v.NumField(); i++ {
varName := v.Type().Field(i).Name
varType := v.Type().Field(i).Type
varValue := v.Field(i).Interface()
if varType == reflect.TypeOf(cid.Cid{}) {
subjobs = append(subjobs, job{
key: fmt.Sprintf("%s/%s", in.key, varName),
c: varValue.(cid.Cid),
})
}
}
}
// Walk subfields
for _, job := range subjobs {
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, job.c, visit, merkledag.Concurrent()); err != nil {
return nil, err
}
var res result
res.key = job.key
res.stats = dsc.stats
results = append(results, res)
}
// now walk the top level object of actor state
dsc := &dagStatCollector{
ds: dag,
walk: carWalkFunc,
}
if err := merkledag.Walk(ctx, dsc.walkLinks, in.c, visit, merkledag.Concurrent()); err != nil {
return nil, err
}
results = append(results, result{key: in.key, stats: dsc.stats})
return results, nil
}
func collectStats(ctx context.Context, addr address.Address, actor *types.Actor, dag format.NodeGetter) (actorStats, error) {
log.Infow("actor", "addr", addr, "code", actor.Code, "name", builtin.ActorNameByCode(actor.Code))
@@ -532,3 +940,19 @@ func DumpStats(actStats actorStats) {
fmt.Println("--------------------------------------------------------------------------")
}
func DumpSnapshotStats(stats map[string]api.ObjStat) {
// sort keys so we get subkey locality
keys := make([]string, 0, len(stats))
for k := range stats {
keys = append(keys, k)
}
sort.Strings(keys)
fmt.Printf("%-*s%-*s%-*s\n", 32, "Path", 24, "Size", 24, "\"Blocks\"")
for _, k := range keys {
stat := stats[k]
sizeStr := units.BytesSize(float64(stat.Size))
fmt.Printf("%-*s%-*s%-*s%-*d\n", 32, k, 10, sizeStr, 14, fmt.Sprintf("(%d)", stat.Size), 24, stat.Links)
}
}
+1 -1
View File
@@ -197,7 +197,7 @@ var staterootStatCmd = &cli.Command{
return err
}
fmt.Printf("%s\t%s\t%d\n", inf.Addr, string(cmh.Digest), inf.Stat.Size)
fmt.Printf("%s\t%x\t%d\n", inf.Addr, cmh.Digest, inf.Stat.Size)
}
return nil
},
+79 -14
View File
@@ -8,12 +8,14 @@ import (
"net/http"
"os"
"path/filepath"
"reflect"
"strings"
"time"
"github.com/google/uuid"
"github.com/ipfs/go-datastore/namespace"
logging "github.com/ipfs/go-log/v2"
"github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/urfave/cli/v2"
"go.opencensus.io/stats/view"
@@ -320,6 +322,29 @@ var runCmd = &cli.Command{
}
}
// Check DC-environment variable
sectorSizes := []string{"2KiB", "8MiB", "512MiB", "32GiB", "64GiB"}
resourcesType := reflect.TypeOf(storiface.Resources{})
for _, sectorSize := range sectorSizes {
for i := 0; i < resourcesType.NumField(); i++ {
field := resourcesType.Field(i)
envName := field.Tag.Get("envname")
if envName != "" {
// Check if DC_[SectorSize]_[ResourceRestriction] is set
envVar, ok := os.LookupEnv("DC_" + sectorSize + "_" + envName)
if ok {
// If it is set, convert it to DC_[ResourceRestriction]
err := os.Setenv("DC_"+envName, envVar)
if err != nil {
log.Fatalf("Error setting environment variable: %v", err)
}
log.Warnf("Converted DC_%s_%s to DC_%s, because DC is a sector-size independent job", sectorSize, envName, envName)
}
}
}
}
// Connect to storage-miner
ctx := lcli.ReqContext(cctx)
@@ -530,9 +555,14 @@ var runCmd = &cli.Command{
log.Info("Opening local storage; connecting to master")
const unspecifiedAddress = "0.0.0.0"
address := cctx.String("listen")
addressSlice := strings.Split(address, ":")
if ip := net.ParseIP(addressSlice[0]); ip != nil {
host, port, err := net.SplitHostPort(address)
if err != nil {
return err
}
if ip := net.ParseIP(host); ip != nil {
if ip.String() == unspecifiedAddress {
timeout, err := time.ParseDuration(cctx.String("timeout"))
if err != nil {
@@ -542,11 +572,21 @@ var runCmd = &cli.Command{
if err != nil {
return err
}
address = rip + ":" + addressSlice[1]
host = rip
}
}
localStore, err := paths.NewLocal(ctx, lr, nodeApi, []string{"http://" + address + "/remote"})
var newAddress string
// Check if the IP address is IPv6
ip := net.ParseIP(host)
if ip.To4() == nil && ip.To16() != nil {
newAddress = "[" + host + "]:" + port
} else {
newAddress = host + ":" + port
}
localStore, err := paths.NewLocal(ctx, lr, nodeApi, []string{"http://" + newAddress + "/remote"})
if err != nil {
return err
}
@@ -587,7 +627,7 @@ var runCmd = &cli.Command{
Storage: lr,
}
log.Info("Setting up control endpoint at " + address)
log.Info("Setting up control endpoint at " + newAddress)
timeout, err := time.ParseDuration(cctx.String("http-server-timeout"))
if err != nil {
@@ -612,13 +652,13 @@ var runCmd = &cli.Command{
log.Warn("Graceful shutdown successful")
}()
nl, err := net.Listen("tcp", address)
nl, err := net.Listen("tcp", newAddress)
if err != nil {
return err
}
{
a, err := net.ResolveTCPAddr("tcp", address)
a, err := net.ResolveTCPAddr("tcp", newAddress)
if err != nil {
return xerrors.Errorf("parsing address: %w", err)
}
@@ -699,7 +739,7 @@ var runCmd = &cli.Command{
select {
case <-readyCh:
if err := nodeApi.WorkerConnect(ctx, "http://"+address+"/rpc/v0"); err != nil {
if err := nodeApi.WorkerConnect(ctx, "http://"+newAddress+"/rpc/v0"); err != nil {
log.Errorf("Registering worker failed: %+v", err)
cancel()
return
@@ -740,21 +780,46 @@ func extractRoutableIP(timeout time.Duration) (string, error) {
deprecatedMinerMultiAddrKey := "STORAGE_API_INFO"
env, ok := os.LookupEnv(minerMultiAddrKey)
if !ok {
// TODO remove after deprecation period
_, ok = os.LookupEnv(deprecatedMinerMultiAddrKey)
if ok {
log.Warnf("Using a deprecated env(%s) value, please use env(%s) instead.", deprecatedMinerMultiAddrKey, minerMultiAddrKey)
}
return "", xerrors.New("MINER_API_INFO environment variable required to extract IP")
}
minerAddr := strings.Split(env, "/")
conn, err := net.DialTimeout("tcp", minerAddr[2]+":"+minerAddr[4], timeout)
// Splitting the env to separate the JWT from the multiaddress
splitEnv := strings.SplitN(env, ":", 2)
if len(splitEnv) < 2 {
return "", xerrors.Errorf("invalid MINER_API_INFO format")
}
// Only take the multiaddress part
maddrStr := splitEnv[1]
maddr, err := multiaddr.NewMultiaddr(maddrStr)
if err != nil {
return "", err
}
defer conn.Close() //nolint:errcheck
minerIP, _ := maddr.ValueForProtocol(multiaddr.P_IP6)
if minerIP == "" {
minerIP, _ = maddr.ValueForProtocol(multiaddr.P_IP4)
}
minerPort, _ := maddr.ValueForProtocol(multiaddr.P_TCP)
// Format the address appropriately
addressToDial := net.JoinHostPort(minerIP, minerPort)
conn, err := net.DialTimeout("tcp", addressToDial, timeout)
if err != nil {
return "", err
}
defer func() {
if cerr := conn.Close(); cerr != nil {
log.Errorf("Error closing connection: %v", cerr)
}
}()
localAddr := conn.LocalAddr().(*net.TCPAddr)
return strings.Split(localAddr.IP.String(), ":")[0], nil
return localAddr.IP.String(), nil
}
+117 -7
View File
@@ -12,6 +12,7 @@ import (
"io"
"os"
"path"
"path/filepath"
"runtime/pprof"
"strings"
@@ -32,6 +33,7 @@ import (
lapi "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/beacon/drand"
"github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/index"
@@ -119,6 +121,10 @@ var DaemonCmd = &cli.Command{
Name: "import-snapshot",
Usage: "import chain state from a given chain export file or url",
},
&cli.BoolFlag{
Name: "remove-existing-chain",
Usage: "remove existing chain and splitstore data on a snapshot-import",
},
&cli.BoolFlag{
Name: "halt-after-import",
Usage: "halt the process after importing chain from file",
@@ -265,10 +271,55 @@ var DaemonCmd = &cli.Command{
chainfile := cctx.String("import-chain")
snapshot := cctx.String("import-snapshot")
willImportChain := false
if chainfile != "" || snapshot != "" {
if chainfile != "" && snapshot != "" {
return fmt.Errorf("cannot specify both 'import-snapshot' and 'import-chain'")
}
willImportChain = true
}
willRemoveChain := cctx.Bool("remove-existing-chain")
if willImportChain && !willRemoveChain {
// Confirm with the user about the intention to remove chain data.
reader := bufio.NewReader(os.Stdin)
fmt.Print("Importing chain or snapshot will by default delete existing local chain data. Do you want to proceed and delete? (yes/no): ")
userInput, err := reader.ReadString('\n')
if err != nil {
return xerrors.Errorf("reading user input: %w", err)
}
userInput = strings.ToLower(strings.TrimSpace(userInput))
if userInput == "yes" {
willRemoveChain = true
} else if userInput == "no" {
willRemoveChain = false
} else {
return fmt.Errorf("invalid input. please answer with 'yes' or 'no'")
}
}
if willRemoveChain {
lr, err := repo.NewFS(cctx.String("repo"))
if err != nil {
return xerrors.Errorf("error opening fs repo: %w", err)
}
exists, err := lr.Exists()
if err != nil {
return err
}
if !exists {
return xerrors.Errorf("lotus repo doesn't exist")
}
err = removeExistingChain(cctx, lr)
if err != nil {
return err
}
}
if willImportChain {
var issnapshot bool
if chainfile == "" {
chainfile = snapshot
@@ -380,7 +431,6 @@ var DaemonCmd = &cli.Command{
if err != nil {
return fmt.Errorf("failed to start json-rpc endpoint: %s", err)
}
// Monitor for shutdown.
finishCh := node.MonitorShutdown(shutdownChan,
node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper},
@@ -536,13 +586,17 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
return err
}
// TODO: We need to supply the actual beacon after v14
stm, err := stmgr.NewStateManager(cst, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil, mds, index.DummyMsgIndex)
if err != nil {
return err
}
if !snapshot {
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), gb.MinTimestamp(), nil)
if err != nil {
return xerrors.Errorf("failed to construct beacon schedule: %w", err)
}
stm, err := stmgr.NewStateManager(cst, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd, mds, index.DummyMsgIndex)
if err != nil {
return err
}
log.Infof("validating imported chain...")
if err := stm.ValidateChain(ctx, ts); err != nil {
return xerrors.Errorf("chain validation failed: %w", err)
@@ -574,3 +628,59 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
return nil
}
func removeExistingChain(cctx *cli.Context, lr repo.Repo) error {
lockedRepo, err := lr.Lock(repo.FullNode)
if err != nil {
return xerrors.Errorf("error locking repo: %w", err)
}
// Ensure that lockedRepo is closed when this function exits
defer func() {
if closeErr := lockedRepo.Close(); closeErr != nil {
log.Errorf("Error closing the lockedRepo: %v", closeErr)
}
}()
cfg, err := lockedRepo.Config()
if err != nil {
return xerrors.Errorf("error getting config: %w", err)
}
fullNodeConfig, ok := cfg.(*config.FullNode)
if !ok {
return xerrors.Errorf("wrong config type: %T", cfg)
}
if fullNodeConfig.Chainstore.EnableSplitstore {
log.Info("removing splitstore directory...")
err = deleteSplitstoreDir(lockedRepo)
if err != nil {
return xerrors.Errorf("error removing splitstore directory: %w", err)
}
}
// Get the base repo path
repoPath := lockedRepo.Path()
// Construct the path to the chain directory
chainPath := filepath.Join(repoPath, "datastore", "chain")
log.Info("removing chain directory:", chainPath)
err = os.RemoveAll(chainPath)
if err != nil {
return xerrors.Errorf("error removing chain directory: %w", err)
}
log.Info("chain and splitstore data have been removed")
return nil
}
func deleteSplitstoreDir(lr repo.LockedRepo) error {
path, err := lr.SplitstorePath()
if err != nil {
return xerrors.Errorf("error getting splitstore path: %w", err)
}
return os.RemoveAll(path)
}
+8 -4
View File
@@ -2289,7 +2289,8 @@ Inputs:
},
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
},
[
{
@@ -2766,7 +2767,8 @@ Inputs:
],
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
}
]
```
@@ -3025,7 +3027,8 @@ Inputs:
},
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
}
]
```
@@ -5467,7 +5470,8 @@ Response:
"UpgradeLightningHeight": 10101,
"UpgradeThunderHeight": 10101,
"UpgradeWatermelonHeight": 10101
}
},
"Eip155ChainID": 123
}
```
+103 -4
View File
@@ -104,6 +104,8 @@
* [EthSendRawTransaction](#EthSendRawTransaction)
* [EthSubscribe](#EthSubscribe)
* [EthSyncing](#EthSyncing)
* [EthTraceBlock](#EthTraceBlock)
* [EthTraceReplayBlockTransactions](#EthTraceReplayBlockTransactions)
* [EthUninstallFilter](#EthUninstallFilter)
* [EthUnsubscribe](#EthUnsubscribe)
* [Filecoin](#Filecoin)
@@ -3083,6 +3085,99 @@ Inputs: `null`
Response: `false`
### EthTraceBlock
TraceAPI related methods
Returns traces created at given block
Perms: read
Inputs:
```json
[
"string value"
]
```
Response:
```json
[
{
"action": {
"callType": "string value",
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"gas": "0x5",
"input": "0x07",
"value": "0x0"
},
"result": {
"gasUsed": "0x5",
"output": "0x07"
},
"subtraces": 123,
"traceAddress": [
123
],
"Type": "string value",
"blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
"blockNumber": 9,
"transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
"transactionPosition": 123
}
]
```
### EthTraceReplayBlockTransactions
Replays all transactions in a block returning the requested traces for each transaction
Perms: read
Inputs:
```json
[
"string value",
[
"string value"
]
]
```
Response:
```json
[
{
"output": "0x07",
"stateDiff": "string value",
"trace": [
{
"action": {
"callType": "string value",
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"gas": "0x5",
"input": "0x07",
"value": "0x0"
},
"result": {
"gasUsed": "0x5",
"output": "0x07"
},
"subtraces": 123,
"traceAddress": [
123
],
"Type": "string value"
}
],
"transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
"vmTrace": "string value"
}
]
```
### EthUninstallFilter
Uninstalls a filter with given id.
@@ -3262,7 +3357,8 @@ Inputs:
},
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
},
[
{
@@ -3739,7 +3835,8 @@ Inputs:
],
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
}
]
```
@@ -4131,7 +4228,8 @@ Inputs:
},
{
"MaxFee": "0",
"MsgUuid": "07070707-0707-0707-0707-070707070707"
"MsgUuid": "07070707-0707-0707-0707-070707070707",
"MaximizeFeeCap": true
}
]
```
@@ -6981,7 +7079,8 @@ Response:
"UpgradeLightningHeight": 10101,
"UpgradeThunderHeight": 10101,
"UpgradeWatermelonHeight": 10101
}
},
"Eip155ChainID": 123
}
```
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
lotus-miner [global options] command [command options] [arguments...]
VERSION:
1.23.3
1.23.5-dev
COMMANDS:
init Initialize a lotus miner repo
+1 -1
View File
@@ -7,7 +7,7 @@ USAGE:
lotus-worker [global options] command [command options] [arguments...]
VERSION:
1.23.3
1.23.5-dev
COMMANDS:
run Start lotus worker
+2 -1
View File
@@ -7,7 +7,7 @@ USAGE:
lotus [global options] command [command options] [arguments...]
VERSION:
1.23.3
1.23.5-dev
COMMANDS:
daemon Start a lotus daemon process
@@ -65,6 +65,7 @@ OPTIONS:
--bootstrap (default: true)
--import-chain value on first run, load chain from given file or url and validate
--import-snapshot value import chain state from a given chain export file or url
--remove-existing-chain remove existing chain and splitstore data on a snapshot-import (default: false)
--halt-after-import halt the process after importing chain from file (default: false)
--lite start lotus in lite mode (default: false)
--pprof value specify name of file for writing cpu profile to
+16 -1
View File
@@ -195,7 +195,7 @@
[Chainstore.Splitstore]
# ColdStoreType specifies the type of the coldstore.
# It can be "messages" (default) to store only messages, "universal" to store all chain state or "discard" for discarding cold blocks.
# It can be "discard" (default) for discarding cold blocks, "messages" to store only messages or "universal" to store all chain state..
#
# type: string
# env var: LOTUS_CHAINSTORE_SPLITSTORE_COLDSTORETYPE
@@ -380,6 +380,21 @@
# env var: LOTUS_FEVM_EVENTS_MAXFILTERHEIGHTRANGE
#MaxFilterHeightRange = 2880
# FilterThresholdSet signals whether a FilterThresholdEpoch is set. If it is it will be used instead of
# MaxFilterHeightRange to define the supported range.
#
# type: bool
# env var: LOTUS_FEVM_EVENTS_FILTERTHRESHOLDSET
#FilterThresholdSet = false
# FilterThresholdEpoch specifies an epoch above which the node will support returning filtered logs.
# This is useful for setting a static start epoch for support, rather than a static window size with a start epoch
# that shifts as the chain progresses.
#
# type: uint64
# env var: LOTUS_FEVM_EVENTS_FILTERTHRESHOLDEPOCH
#FilterThresholdEpoch = 2683348
# DatabasePath is the full path to a sqlite database that will be used to index actor events to
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as

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