Compare commits
183
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
570773259a | ||
|
|
19f1ad2762 | ||
|
|
9a2b83064b | ||
|
|
544af751cb | ||
|
|
807610131a | ||
|
|
8142aaa9c8 | ||
|
|
4c7d9ad30e | ||
|
|
dd0c4a0a34 | ||
|
|
9aba7dc17a | ||
|
|
0c9f697bf6 | ||
|
|
aa7b5c40b8 | ||
|
|
abaa53c6a3 | ||
|
|
ea57a1aec3 | ||
|
|
ab6aaf5013 | ||
|
|
bf2ac13609 | ||
|
|
392d3d4b8a | ||
|
|
51aecb6b17 | ||
|
|
d2c0603717 | ||
|
|
3841e5444f | ||
|
|
2dcaddf61d | ||
|
|
e51f3e9b15 | ||
|
|
73102e9432 | ||
|
|
984b4c78cb | ||
|
|
8f1c23296e | ||
|
|
12656b05fe | ||
|
|
285dfed338 | ||
|
|
6028d7ba18 | ||
|
|
29a82cdf0f | ||
|
|
75c744a438 | ||
|
|
7ecc00090e | ||
|
|
a2475bca94 | ||
|
|
be1614a042 | ||
|
|
ec01036871 | ||
|
|
1bb698619c | ||
|
|
fa93c23813 | ||
|
|
21efd481d8 | ||
|
|
61f29a84b5 | ||
|
|
d108565ea2 | ||
|
|
7486227c27 | ||
|
|
4d20011b78 | ||
|
|
e6b0ee7e4a | ||
|
|
8ff55c027e | ||
|
|
e73a038fe8 | ||
|
|
94063ea4d1 | ||
|
|
63b03a48d0 | ||
|
|
7aa6663127 | ||
|
|
ec1b2b959a | ||
|
|
9848e0467e | ||
|
|
17adcb77c3 | ||
|
|
81e056be1a | ||
|
|
25babace8f | ||
|
|
0e7cf61888 | ||
|
|
cb8e2836bb | ||
|
|
b78cbcbb99 | ||
|
|
bd4dc217af | ||
|
|
662fc37976 | ||
|
|
4823322154 | ||
|
|
b217eec84d | ||
|
|
d75f77b4c5 | ||
|
|
693f230fbb | ||
|
|
21d6020179 | ||
|
|
3fc1346d5b | ||
|
|
58c7c514c6 | ||
|
|
cf0997b434 | ||
|
|
8066833b3a | ||
|
|
e0d92a13a7 | ||
|
|
6a268cfb63 | ||
|
|
f291572b4a | ||
|
|
9b071bc96b | ||
|
|
e1c00bdbba | ||
|
|
f88fc0719f | ||
|
|
818b3b8daf | ||
|
|
7060150bdc | ||
|
|
0a35e9659b | ||
|
|
28101be1b7 | ||
|
|
7d5c7f5fec | ||
|
|
ed63798082 | ||
|
|
05c5e18899 | ||
|
|
0c17d78356 | ||
|
|
fa97016573 | ||
|
|
37d41f3f83 | ||
|
|
45ceb5d297 | ||
|
|
a8dace0f23 | ||
|
|
b8e7262b14 | ||
|
|
b334b2055f | ||
|
|
13fc5b688f | ||
|
|
beb70a3db1 | ||
|
|
482e13706f | ||
|
|
d060df2fb9 | ||
|
|
62326b243f | ||
|
|
a0771b12eb | ||
|
|
f572852d06 | ||
|
|
db9c516429 | ||
|
|
0f6003fd68 | ||
|
|
17d220524c | ||
|
|
98a9c8310b | ||
|
|
7cfb2529ac | ||
|
|
5740f17037 | ||
|
|
c45df789ea | ||
|
|
aa0d47078f | ||
|
|
fc6721cff7 | ||
|
|
a0b25b9136 | ||
|
|
0cc63f6896 | ||
|
|
291deaa017 | ||
|
|
38dc034499 | ||
|
|
128bdc63db | ||
|
|
34f376eb23 | ||
|
|
4682e8f326 | ||
|
|
f03c7a8880 | ||
|
|
4fd81e0c58 | ||
|
|
65ac5669a9 | ||
|
|
e9f665214a | ||
|
|
807a60b4e4 | ||
|
|
dd12cad1ef | ||
|
|
53015dc3ee | ||
|
|
c8a692046f | ||
|
|
c8156d0f46 | ||
|
|
9d967b084a | ||
|
|
4f199ada40 | ||
|
|
6d53d0d533 | ||
|
|
d1fa22244f | ||
|
|
91a6eabab5 | ||
|
|
1dfd08a0dd | ||
|
|
901bb153d0 | ||
|
|
a0c58b5582 | ||
|
|
70db738bff | ||
|
|
0934cf034d | ||
|
|
72baa3d916 | ||
|
|
14d921f64f | ||
|
|
2d3f1e0365 | ||
|
|
51d2a883f0 | ||
|
|
d35818293a | ||
|
|
7383a761f6 | ||
|
|
39ae4b04be | ||
|
|
34576d0c64 | ||
|
|
b60aeccfdc | ||
|
|
e715384173 | ||
|
|
67023886c8 | ||
|
|
00a73fd88f | ||
|
|
fc82aab74b | ||
|
|
bb800fd78d | ||
|
|
287d410fe8 | ||
|
|
923d4128bb | ||
|
|
787470c2b4 | ||
|
|
7a509cf0d8 | ||
|
|
12a06defd1 | ||
|
|
0ebdbed30b | ||
|
|
9a46682d9d | ||
|
|
fd1e0ad7a3 | ||
|
|
3bae3a3bea | ||
|
|
f9404aa55e | ||
|
|
7c448afda8 | ||
|
|
8519bc21f9 | ||
|
|
a02c783f0e | ||
|
|
fea879088c | ||
|
|
45667b7391 | ||
|
|
a4a4e04c5e | ||
|
|
f8195deb54 | ||
|
|
6ca975e83a | ||
|
|
754f294992 | ||
|
|
25edb23c3f | ||
|
|
075216d9da | ||
|
|
db6532c9d7 | ||
|
|
985a4bd730 | ||
|
|
0b9b89bf2b | ||
|
|
f5b027eda3 | ||
|
|
0f92bced9d | ||
|
|
c65ab1b277 | ||
|
|
5c2949b59d | ||
|
|
ef2200c28e | ||
|
|
fe675b6fa1 | ||
|
|
fa71ed607b | ||
|
|
3105596c9e | ||
|
|
9bfb73211e | ||
|
|
88d3de7afc | ||
|
|
95c0afb99b | ||
|
|
653af01235 | ||
|
|
9d1208c9ff | ||
|
|
c3ee957cc6 | ||
|
|
536600c95c | ||
|
|
627d6e70a6 | ||
|
|
43d557e0f4 | ||
|
|
5626c69ce5 |
+276
-145
@@ -5,6 +5,11 @@ orbs:
|
||||
|
||||
executors:
|
||||
golang:
|
||||
docker:
|
||||
# Must match GO_VERSION_MIN in project root
|
||||
- image: cimg/go:1.18.8
|
||||
resource_class: medium+
|
||||
golang-2xl:
|
||||
docker:
|
||||
# Must match GO_VERSION_MIN in project root
|
||||
- image: cimg/go:1.18.8
|
||||
@@ -14,7 +19,7 @@ executors:
|
||||
- image: ubuntu:20.04
|
||||
|
||||
commands:
|
||||
prepare:
|
||||
build-platform-specific:
|
||||
parameters:
|
||||
linux:
|
||||
default: true
|
||||
@@ -31,22 +36,13 @@ commands:
|
||||
steps:
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- when:
|
||||
condition: <<parameters.linux>>
|
||||
steps:
|
||||
- run:
|
||||
name: Check Go Version
|
||||
command: |
|
||||
v=`go version | { read _ _ v _; echo ${v#go}; }`
|
||||
if [[ $v != `cat GO_VERSION_MIN` ]]; then
|
||||
echo "GO_VERSION_MIN file does not match the go version being used."
|
||||
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
|
||||
exit 1
|
||||
fi
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
|
||||
- run: sudo apt-get install python-is-python3
|
||||
|
||||
- install-ubuntu-deps
|
||||
- check-go-version
|
||||
- when:
|
||||
condition: <<parameters.darwin>>
|
||||
steps:
|
||||
@@ -67,8 +63,7 @@ commands:
|
||||
name: Install Rust
|
||||
command: |
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- run: make deps lotus
|
||||
download-params:
|
||||
steps:
|
||||
- restore_cache:
|
||||
@@ -77,7 +72,7 @@ commands:
|
||||
- 'v26-2k-lotus-params'
|
||||
paths:
|
||||
- /var/tmp/filecoin-proof-parameters/
|
||||
- run: ./lotus fetch-params 2048
|
||||
- run: ./lotus fetch-params 2048
|
||||
- save_cache:
|
||||
name: Save parameters cache
|
||||
key: 'v26-2k-lotus-params'
|
||||
@@ -99,12 +94,43 @@ commands:
|
||||
name: fetch all tags
|
||||
command: |
|
||||
git fetch --all
|
||||
install-ubuntu-deps:
|
||||
steps:
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
|
||||
check-go-version:
|
||||
steps:
|
||||
- run: |
|
||||
v=`go version | { read _ _ v _; echo ${v#go}; }`
|
||||
if [[ $v != `cat GO_VERSION_MIN` ]]; then
|
||||
echo "GO_VERSION_MIN file does not match the go version being used."
|
||||
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- install-ubuntu-deps
|
||||
- check-go-version
|
||||
- run: make deps lotus
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- "lotus"
|
||||
mod-tidy-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go mod tidy -v
|
||||
- run:
|
||||
name: Check git diff
|
||||
@@ -115,13 +141,14 @@ jobs:
|
||||
test:
|
||||
description: |
|
||||
Run tests with gotestsum.
|
||||
working_directory: ~/lotus
|
||||
parameters: &test-params
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
go-test-flags:
|
||||
type: string
|
||||
default: "-timeout 30m"
|
||||
default: "-timeout 20m"
|
||||
description: Flags passed to go test.
|
||||
target:
|
||||
type: string
|
||||
@@ -130,21 +157,22 @@ jobs:
|
||||
proofs-log-test:
|
||||
type: string
|
||||
default: "0"
|
||||
get-params:
|
||||
type: boolean
|
||||
default: false
|
||||
suite:
|
||||
type: string
|
||||
default: unit
|
||||
description: Test suite name to report to CircleCI.
|
||||
gotestsum-format:
|
||||
type: string
|
||||
default: standard-verbose
|
||||
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
- download-params
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- when:
|
||||
condition: << parameters.get-params >>
|
||||
steps:
|
||||
- download-params
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
@@ -155,12 +183,11 @@ jobs:
|
||||
mkdir -p /tmp/test-reports/<< parameters.suite >>
|
||||
mkdir -p /tmp/test-artifacts
|
||||
gotestsum \
|
||||
--format << parameters.gotestsum-format >> \
|
||||
--format standard-verbose \
|
||||
--junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \
|
||||
--jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \
|
||||
-- \
|
||||
<< parameters.go-test-flags >> \
|
||||
<< parameters.target >>
|
||||
--packages="<< parameters.target >>" \
|
||||
-- << parameters.go-test-flags >>
|
||||
no_output_timeout: 30m
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
@@ -168,6 +195,7 @@ jobs:
|
||||
path: /tmp/test-artifacts/<< parameters.suite >>.json
|
||||
|
||||
test-conformance:
|
||||
working_directory: ~/lotus
|
||||
description: |
|
||||
Run tests using a corpus of interoperable test vectors for Filecoin
|
||||
implementations to test their correctness and compliance with the Filecoin
|
||||
@@ -183,10 +211,9 @@ jobs:
|
||||
submodule is used.
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- download-params
|
||||
- when:
|
||||
condition:
|
||||
@@ -229,7 +256,7 @@ jobs:
|
||||
build-linux-amd64:
|
||||
executor: golang
|
||||
steps:
|
||||
- prepare
|
||||
- build-platform-specific
|
||||
- run: make lotus lotus-miner lotus-worker
|
||||
- run:
|
||||
name: check tag and version output match
|
||||
@@ -248,7 +275,7 @@ jobs:
|
||||
macos:
|
||||
xcode: "13.4.1"
|
||||
steps:
|
||||
- prepare:
|
||||
- build-platform-specific:
|
||||
linux: false
|
||||
darwin: true
|
||||
darwin-architecture: amd64
|
||||
@@ -272,7 +299,7 @@ jobs:
|
||||
resource_class: filecoin-project/self-hosted-m1
|
||||
steps:
|
||||
- run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV"
|
||||
- prepare:
|
||||
- build-platform-specific:
|
||||
linux: false
|
||||
darwin: true
|
||||
darwin-architecture: arm64
|
||||
@@ -330,16 +357,18 @@ jobs:
|
||||
|
||||
gofmt:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: "! go fmt ./... 2>&1 | read"
|
||||
|
||||
gen-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- run: make deps
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: go install github.com/hannahhoward/cbor-gen-for
|
||||
- run: make gen
|
||||
@@ -349,32 +378,29 @@ jobs:
|
||||
|
||||
docs-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full
|
||||
- run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner
|
||||
- run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker
|
||||
- run: make deps
|
||||
- run: make docsgen
|
||||
- run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full
|
||||
- run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner
|
||||
- run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker
|
||||
- run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet
|
||||
|
||||
lint: &lint
|
||||
lint-all:
|
||||
description: |
|
||||
Run golangci-lint.
|
||||
working_directory: ~/lotus
|
||||
parameters:
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
concurrency:
|
||||
type: string
|
||||
default: '2'
|
||||
description: |
|
||||
Concurrency used to run linters. Defaults to 2 because NumCPU is not
|
||||
aware of container CPU limits.
|
||||
args:
|
||||
type: string
|
||||
default: ''
|
||||
@@ -382,17 +408,14 @@ jobs:
|
||||
Arguments to pass to golangci-lint
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps
|
||||
no_output_timeout: 30m
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Lint
|
||||
command: |
|
||||
golangci-lint run -v --timeout 2m \
|
||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||
lint-all:
|
||||
<<: *lint
|
||||
golangci-lint run -v --timeout 10m \
|
||||
--concurrency 4 << parameters.args >>
|
||||
|
||||
build-docker:
|
||||
description: >
|
||||
@@ -494,437 +517,545 @@ jobs:
|
||||
extra_build_args: --target <<parameters.image>> --build-arg GOFLAGS=-tags=<<parameters.network>>
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- build
|
||||
- lint-all:
|
||||
concurrency: "16" # expend all docker 2xlarge CPUs.
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- gen-check
|
||||
- docs-check
|
||||
requires:
|
||||
- build
|
||||
- mod-tidy-check:
|
||||
requires:
|
||||
- build
|
||||
- gofmt:
|
||||
requires:
|
||||
- build
|
||||
- gen-check:
|
||||
requires:
|
||||
- build
|
||||
- docs-check:
|
||||
requires:
|
||||
- build
|
||||
- test:
|
||||
name: test-itest-api
|
||||
requires:
|
||||
- build
|
||||
suite: itest-api
|
||||
target: "./itests/api_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-batch_deal
|
||||
requires:
|
||||
- build
|
||||
suite: itest-batch_deal
|
||||
target: "./itests/batch_deal_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-ccupgrade
|
||||
requires:
|
||||
- build
|
||||
suite: itest-ccupgrade
|
||||
target: "./itests/ccupgrade_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-cli
|
||||
requires:
|
||||
- build
|
||||
suite: itest-cli
|
||||
target: "./itests/cli_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deadlines
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deadlines
|
||||
target: "./itests/deadlines_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_512mb
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_512mb
|
||||
target: "./itests/deals_512mb_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_anycid
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_anycid
|
||||
target: "./itests/deals_anycid_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_concurrent
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_concurrent
|
||||
target: "./itests/deals_concurrent_test.go"
|
||||
|
||||
executor: golang-2xl
|
||||
- test:
|
||||
name: test-itest-deals_invalid_utf8_label
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_invalid_utf8_label
|
||||
target: "./itests/deals_invalid_utf8_label_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_max_staging_deals
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_max_staging_deals
|
||||
target: "./itests/deals_max_staging_deals_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_offline
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_offline
|
||||
target: "./itests/deals_offline_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_padding
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_padding
|
||||
target: "./itests/deals_padding_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_partial_retrieval_dm-level
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_partial_retrieval_dm-level
|
||||
target: "./itests/deals_partial_retrieval_dm-level_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_partial_retrieval
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_partial_retrieval
|
||||
target: "./itests/deals_partial_retrieval_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_power
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_power
|
||||
target: "./itests/deals_power_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_pricing
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_pricing
|
||||
target: "./itests/deals_pricing_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_publish
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_publish
|
||||
target: "./itests/deals_publish_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_remote_retrieval
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_remote_retrieval
|
||||
target: "./itests/deals_remote_retrieval_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals_retry_deal_no_funds
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals_retry_deal_no_funds
|
||||
target: "./itests/deals_retry_deal_no_funds_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-deals
|
||||
requires:
|
||||
- build
|
||||
suite: itest-deals
|
||||
target: "./itests/deals_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-decode_params
|
||||
requires:
|
||||
- build
|
||||
suite: itest-decode_params
|
||||
target: "./itests/decode_params_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-dup_mpool_messages
|
||||
requires:
|
||||
- build
|
||||
suite: itest-dup_mpool_messages
|
||||
target: "./itests/dup_mpool_messages_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_account_abstraction
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_account_abstraction
|
||||
target: "./itests/eth_account_abstraction_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_api
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_api
|
||||
target: "./itests/eth_api_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_balance
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_balance
|
||||
target: "./itests/eth_balance_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_block_hash
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_block_hash
|
||||
target: "./itests/eth_block_hash_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_bytecode
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_bytecode
|
||||
target: "./itests/eth_bytecode_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_config
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_config
|
||||
target: "./itests/eth_config_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_conformance
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_conformance
|
||||
target: "./itests/eth_conformance_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_deploy
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_deploy
|
||||
target: "./itests/eth_deploy_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_fee_history
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_fee_history
|
||||
target: "./itests/eth_fee_history_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_filter
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_filter
|
||||
target: "./itests/eth_filter_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_hash_lookup
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_hash_lookup
|
||||
target: "./itests/eth_hash_lookup_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_transactions
|
||||
requires:
|
||||
- build
|
||||
suite: itest-eth_transactions
|
||||
target: "./itests/eth_transactions_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm_address
|
||||
requires:
|
||||
- build
|
||||
suite: itest-fevm_address
|
||||
target: "./itests/fevm_address_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm_events
|
||||
requires:
|
||||
- build
|
||||
suite: itest-fevm_events
|
||||
target: "./itests/fevm_events_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm
|
||||
requires:
|
||||
- build
|
||||
suite: itest-fevm
|
||||
target: "./itests/fevm_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-gas_estimation
|
||||
requires:
|
||||
- build
|
||||
suite: itest-gas_estimation
|
||||
target: "./itests/gas_estimation_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-gateway
|
||||
requires:
|
||||
- build
|
||||
suite: itest-gateway
|
||||
target: "./itests/gateway_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-get_messages_in_ts
|
||||
requires:
|
||||
- build
|
||||
suite: itest-get_messages_in_ts
|
||||
target: "./itests/get_messages_in_ts_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-lite_migration
|
||||
requires:
|
||||
- build
|
||||
suite: itest-lite_migration
|
||||
target: "./itests/lite_migration_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-lookup_robust_address
|
||||
requires:
|
||||
- build
|
||||
suite: itest-lookup_robust_address
|
||||
target: "./itests/lookup_robust_address_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-mempool
|
||||
requires:
|
||||
- build
|
||||
suite: itest-mempool
|
||||
target: "./itests/mempool_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-migration_nv17
|
||||
requires:
|
||||
- build
|
||||
suite: itest-migration_nv17
|
||||
target: "./itests/migration_nv17_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-migration_nv18
|
||||
requires:
|
||||
- build
|
||||
suite: itest-migration_nv18
|
||||
target: "./itests/migration_nv18_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-mpool_msg_uuid
|
||||
requires:
|
||||
- build
|
||||
suite: itest-mpool_msg_uuid
|
||||
target: "./itests/mpool_msg_uuid_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-mpool_push_with_uuid
|
||||
requires:
|
||||
- build
|
||||
suite: itest-mpool_push_with_uuid
|
||||
target: "./itests/mpool_push_with_uuid_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-multisig
|
||||
requires:
|
||||
- build
|
||||
suite: itest-multisig
|
||||
target: "./itests/multisig_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-net
|
||||
requires:
|
||||
- build
|
||||
suite: itest-net
|
||||
target: "./itests/net_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-nonce
|
||||
requires:
|
||||
- build
|
||||
suite: itest-nonce
|
||||
target: "./itests/nonce_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-path_detach_redeclare
|
||||
requires:
|
||||
- build
|
||||
suite: itest-path_detach_redeclare
|
||||
target: "./itests/path_detach_redeclare_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-path_type_filters
|
||||
requires:
|
||||
- build
|
||||
suite: itest-path_type_filters
|
||||
target: "./itests/path_type_filters_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-paych_api
|
||||
requires:
|
||||
- build
|
||||
suite: itest-paych_api
|
||||
target: "./itests/paych_api_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-paych_cli
|
||||
requires:
|
||||
- build
|
||||
suite: itest-paych_cli
|
||||
target: "./itests/paych_cli_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-pending_deal_allocation
|
||||
requires:
|
||||
- build
|
||||
suite: itest-pending_deal_allocation
|
||||
target: "./itests/pending_deal_allocation_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-raft_messagesigner
|
||||
requires:
|
||||
- build
|
||||
suite: itest-raft_messagesigner
|
||||
target: "./itests/raft_messagesigner_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-remove_verifreg_datacap
|
||||
requires:
|
||||
- build
|
||||
suite: itest-remove_verifreg_datacap
|
||||
target: "./itests/remove_verifreg_datacap_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sdr_upgrade
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sdr_upgrade
|
||||
target: "./itests/sdr_upgrade_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_finalize_early
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_finalize_early
|
||||
target: "./itests/sector_finalize_early_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_import_full
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_import_full
|
||||
target: "./itests/sector_import_full_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_import_simple
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_import_simple
|
||||
target: "./itests/sector_import_simple_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_make_cc_avail
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_make_cc_avail
|
||||
target: "./itests/sector_make_cc_avail_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_miner_collateral
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_miner_collateral
|
||||
target: "./itests/sector_miner_collateral_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_numassign
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_numassign
|
||||
target: "./itests/sector_numassign_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_pledge
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_pledge
|
||||
target: "./itests/sector_pledge_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_prefer_no_upgrade
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_prefer_no_upgrade
|
||||
target: "./itests/sector_prefer_no_upgrade_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_revert_available
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_revert_available
|
||||
target: "./itests/sector_revert_available_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_terminate
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_terminate
|
||||
target: "./itests/sector_terminate_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_unseal
|
||||
requires:
|
||||
- build
|
||||
suite: itest-sector_unseal
|
||||
target: "./itests/sector_unseal_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-self_sent_txn
|
||||
requires:
|
||||
- build
|
||||
suite: itest-self_sent_txn
|
||||
target: "./itests/self_sent_txn_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-splitstore
|
||||
requires:
|
||||
- build
|
||||
suite: itest-splitstore
|
||||
target: "./itests/splitstore_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-tape
|
||||
requires:
|
||||
- build
|
||||
suite: itest-tape
|
||||
target: "./itests/tape_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-verifreg
|
||||
requires:
|
||||
- build
|
||||
suite: itest-verifreg
|
||||
target: "./itests/verifreg_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-wdpost_config
|
||||
requires:
|
||||
- build
|
||||
suite: itest-wdpost_config
|
||||
target: "./itests/wdpost_config_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-wdpost_dispute
|
||||
requires:
|
||||
- build
|
||||
suite: itest-wdpost_dispute
|
||||
target: "./itests/wdpost_dispute_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-wdpost_no_miner_storage
|
||||
requires:
|
||||
- build
|
||||
suite: itest-wdpost_no_miner_storage
|
||||
target: "./itests/wdpost_no_miner_storage_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-wdpost
|
||||
requires:
|
||||
- build
|
||||
suite: itest-wdpost
|
||||
target: "./itests/wdpost_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-wdpost_worker_config
|
||||
requires:
|
||||
- build
|
||||
suite: itest-wdpost_worker_config
|
||||
target: "./itests/wdpost_worker_config_test.go"
|
||||
|
||||
executor: golang-2xl
|
||||
- test:
|
||||
name: test-itest-worker
|
||||
requires:
|
||||
- build
|
||||
suite: itest-worker
|
||||
target: "./itests/worker_test.go"
|
||||
|
||||
executor: golang-2xl
|
||||
- test:
|
||||
name: test-itest-worker_upgrade
|
||||
requires:
|
||||
- build
|
||||
suite: itest-worker_upgrade
|
||||
target: "./itests/worker_upgrade_test.go"
|
||||
|
||||
- test:
|
||||
name: test-unit-cli
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-cli
|
||||
target: "./cli/... ./cmd/... ./api/..."
|
||||
get-params: true
|
||||
- test:
|
||||
name: test-unit-node
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-node
|
||||
target: "./node/..."
|
||||
|
||||
- test:
|
||||
name: test-unit-rest
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-rest
|
||||
target: "./api/... ./blockstore/... ./build/... ./chain/... ./cli/... ./cmd/... ./conformance/... ./extern/... ./gateway/... ./journal/... ./lib/... ./markets/... ./node/... ./paychmgr/... ./storage/... ./tools/..."
|
||||
executor: golang-2xl
|
||||
- test:
|
||||
name: test-unit-storage
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-storage
|
||||
target: "./storage/... ./extern/..."
|
||||
|
||||
- test:
|
||||
go-test-flags: "-run=TestMulticoreSDR"
|
||||
requires:
|
||||
- build
|
||||
suite: multicore-sdr-check
|
||||
target: "./storage/sealer/ffiwrapper"
|
||||
proofs-log-test: "1"
|
||||
- test-conformance:
|
||||
requires:
|
||||
- build
|
||||
suite: conformance
|
||||
target: "./conformance"
|
||||
|
||||
|
||||
+112
-68
@@ -5,6 +5,11 @@ orbs:
|
||||
|
||||
executors:
|
||||
golang:
|
||||
docker:
|
||||
# Must match GO_VERSION_MIN in project root
|
||||
- image: cimg/go:1.18.8
|
||||
resource_class: medium+
|
||||
golang-2xl:
|
||||
docker:
|
||||
# Must match GO_VERSION_MIN in project root
|
||||
- image: cimg/go:1.18.8
|
||||
@@ -14,7 +19,7 @@ executors:
|
||||
- image: ubuntu:20.04
|
||||
|
||||
commands:
|
||||
prepare:
|
||||
build-platform-specific:
|
||||
parameters:
|
||||
linux:
|
||||
default: true
|
||||
@@ -31,22 +36,13 @@ commands:
|
||||
steps:
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- when:
|
||||
condition: <<parameters.linux>>
|
||||
steps:
|
||||
- run:
|
||||
name: Check Go Version
|
||||
command: |
|
||||
v=`go version | { read _ _ v _; echo ${v#go}; }`
|
||||
if [["[[ $v != `cat GO_VERSION_MIN` ]]"]]; then
|
||||
echo "GO_VERSION_MIN file does not match the go version being used."
|
||||
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
|
||||
exit 1
|
||||
fi
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
|
||||
- run: sudo apt-get install python-is-python3
|
||||
|
||||
- install-ubuntu-deps
|
||||
- check-go-version
|
||||
- when:
|
||||
condition: <<parameters.darwin>>
|
||||
steps:
|
||||
@@ -67,8 +63,7 @@ commands:
|
||||
name: Install Rust
|
||||
command: |
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- run: make deps lotus
|
||||
download-params:
|
||||
steps:
|
||||
- restore_cache:
|
||||
@@ -77,7 +72,7 @@ commands:
|
||||
- 'v26-2k-lotus-params'
|
||||
paths:
|
||||
- /var/tmp/filecoin-proof-parameters/
|
||||
- run: ./lotus fetch-params 2048
|
||||
- run: ./lotus fetch-params 2048
|
||||
- save_cache:
|
||||
name: Save parameters cache
|
||||
key: 'v26-2k-lotus-params'
|
||||
@@ -99,12 +94,43 @@ commands:
|
||||
name: fetch all tags
|
||||
command: |
|
||||
git fetch --all
|
||||
install-ubuntu-deps:
|
||||
steps:
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev
|
||||
check-go-version:
|
||||
steps:
|
||||
- run: |
|
||||
v=`go version | { read _ _ v _; echo ${v#go}; }`
|
||||
if [["[[ $v != `cat GO_VERSION_MIN` ]]"]]; then
|
||||
echo "GO_VERSION_MIN file does not match the go version being used."
|
||||
echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- run: git submodule sync
|
||||
- run: git submodule update --init
|
||||
- install-ubuntu-deps
|
||||
- check-go-version
|
||||
- run: make deps lotus
|
||||
- persist_to_workspace:
|
||||
root: ~/
|
||||
paths:
|
||||
- "lotus"
|
||||
mod-tidy-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go mod tidy -v
|
||||
- run:
|
||||
name: Check git diff
|
||||
@@ -115,13 +141,14 @@ jobs:
|
||||
test:
|
||||
description: |
|
||||
Run tests with gotestsum.
|
||||
working_directory: ~/lotus
|
||||
parameters: &test-params
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
go-test-flags:
|
||||
type: string
|
||||
default: "-timeout 30m"
|
||||
default: "-timeout 20m"
|
||||
description: Flags passed to go test.
|
||||
target:
|
||||
type: string
|
||||
@@ -130,21 +157,22 @@ jobs:
|
||||
proofs-log-test:
|
||||
type: string
|
||||
default: "0"
|
||||
get-params:
|
||||
type: boolean
|
||||
default: false
|
||||
suite:
|
||||
type: string
|
||||
default: unit
|
||||
description: Test suite name to report to CircleCI.
|
||||
gotestsum-format:
|
||||
type: string
|
||||
default: standard-verbose
|
||||
description: gotestsum format. https://github.com/gotestyourself/gotestsum#format
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
- download-params
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- when:
|
||||
condition: << parameters.get-params >>
|
||||
steps:
|
||||
- download-params
|
||||
- run:
|
||||
name: go test
|
||||
environment:
|
||||
@@ -155,12 +183,11 @@ jobs:
|
||||
mkdir -p /tmp/test-reports/<< parameters.suite >>
|
||||
mkdir -p /tmp/test-artifacts
|
||||
gotestsum \
|
||||
--format << parameters.gotestsum-format >> \
|
||||
--format standard-verbose \
|
||||
--junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \
|
||||
--jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \
|
||||
-- \
|
||||
<< parameters.go-test-flags >> \
|
||||
<< parameters.target >>
|
||||
--packages="<< parameters.target >>" \
|
||||
-- << parameters.go-test-flags >>
|
||||
no_output_timeout: 30m
|
||||
- store_test_results:
|
||||
path: /tmp/test-reports
|
||||
@@ -168,6 +195,7 @@ jobs:
|
||||
path: /tmp/test-artifacts/<< parameters.suite >>.json
|
||||
|
||||
test-conformance:
|
||||
working_directory: ~/lotus
|
||||
description: |
|
||||
Run tests using a corpus of interoperable test vectors for Filecoin
|
||||
implementations to test their correctness and compliance with the Filecoin
|
||||
@@ -183,10 +211,9 @@ jobs:
|
||||
submodule is used.
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- download-params
|
||||
- when:
|
||||
condition:
|
||||
@@ -229,7 +256,7 @@ jobs:
|
||||
build-linux-amd64:
|
||||
executor: golang
|
||||
steps:
|
||||
- prepare
|
||||
- build-platform-specific
|
||||
- run: make lotus lotus-miner lotus-worker
|
||||
- run:
|
||||
name: check tag and version output match
|
||||
@@ -248,7 +275,7 @@ jobs:
|
||||
macos:
|
||||
xcode: "13.4.1"
|
||||
steps:
|
||||
- prepare:
|
||||
- build-platform-specific:
|
||||
linux: false
|
||||
darwin: true
|
||||
darwin-architecture: amd64
|
||||
@@ -272,7 +299,7 @@ jobs:
|
||||
resource_class: filecoin-project/self-hosted-m1
|
||||
steps:
|
||||
- run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV"
|
||||
- prepare:
|
||||
- build-platform-specific:
|
||||
linux: false
|
||||
darwin: true
|
||||
darwin-architecture: arm64
|
||||
@@ -330,16 +357,18 @@ jobs:
|
||||
|
||||
gofmt:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: "! go fmt ./... 2>&1 | read"
|
||||
|
||||
gen-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- run: make deps
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: go install github.com/hannahhoward/cbor-gen-for
|
||||
- run: make gen
|
||||
@@ -349,32 +378,29 @@ jobs:
|
||||
|
||||
docs-check:
|
||||
executor: golang
|
||||
working_directory: ~/lotus
|
||||
steps:
|
||||
- prepare
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run: go install golang.org/x/tools/cmd/goimports
|
||||
- run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full
|
||||
- run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner
|
||||
- run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker
|
||||
- run: make deps
|
||||
- run: make docsgen
|
||||
- run: zcat build/openrpc/full.json.gz | jq > ../post-openrpc-full
|
||||
- run: zcat build/openrpc/miner.json.gz | jq > ../post-openrpc-miner
|
||||
- run: zcat build/openrpc/worker.json.gz | jq > ../post-openrpc-worker
|
||||
- run: diff ../pre-openrpc-full ../post-openrpc-full && diff ../pre-openrpc-miner ../post-openrpc-miner && diff ../pre-openrpc-worker ../post-openrpc-worker && git --no-pager diff && git --no-pager diff --quiet
|
||||
|
||||
lint: &lint
|
||||
lint-all:
|
||||
description: |
|
||||
Run golangci-lint.
|
||||
working_directory: ~/lotus
|
||||
parameters:
|
||||
executor:
|
||||
type: executor
|
||||
default: golang
|
||||
concurrency:
|
||||
type: string
|
||||
default: '2'
|
||||
description: |
|
||||
Concurrency used to run linters. Defaults to 2 because NumCPU is not
|
||||
aware of container CPU limits.
|
||||
args:
|
||||
type: string
|
||||
default: ''
|
||||
@@ -382,17 +408,14 @@ jobs:
|
||||
Arguments to pass to golangci-lint
|
||||
executor: << parameters.executor >>
|
||||
steps:
|
||||
- prepare
|
||||
- run:
|
||||
command: make deps
|
||||
no_output_timeout: 30m
|
||||
- install-ubuntu-deps
|
||||
- attach_workspace:
|
||||
at: ~/
|
||||
- run:
|
||||
name: Lint
|
||||
command: |
|
||||
golangci-lint run -v --timeout 2m \
|
||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||
lint-all:
|
||||
<<: *lint
|
||||
golangci-lint run -v --timeout 10m \
|
||||
--concurrency 4 << parameters.args >>
|
||||
|
||||
build-docker:
|
||||
description: >
|
||||
@@ -494,37 +517,58 @@ jobs:
|
||||
extra_build_args: --target <<parameters.image>> --build-arg GOFLAGS=-tags=<<parameters.network>>
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
ci:
|
||||
jobs:
|
||||
- build
|
||||
- lint-all:
|
||||
concurrency: "16" # expend all docker 2xlarge CPUs.
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- gen-check
|
||||
- docs-check
|
||||
requires:
|
||||
- build
|
||||
- mod-tidy-check:
|
||||
requires:
|
||||
- build
|
||||
- gofmt:
|
||||
requires:
|
||||
- build
|
||||
- gen-check:
|
||||
requires:
|
||||
- build
|
||||
- docs-check:
|
||||
requires:
|
||||
- build
|
||||
|
||||
[[- range $file := .ItestFiles -]]
|
||||
[[ with $name := $file | stripSuffix ]]
|
||||
- test:
|
||||
name: test-itest-[[ $name ]]
|
||||
requires:
|
||||
- build
|
||||
suite: itest-[[ $name ]]
|
||||
target: "./itests/[[ $file ]]"
|
||||
[[ end ]]
|
||||
[[- end -]]
|
||||
[[- if or (eq $name "worker") (eq $name "deals_concurrent") (eq $name "wdpost_worker_config")]]
|
||||
executor: golang-2xl
|
||||
[[- end]]
|
||||
[[- end ]][[- end]]
|
||||
|
||||
[[range $suite, $pkgs := .UnitSuites]]
|
||||
[[- range $suite, $pkgs := .UnitSuites]]
|
||||
- test:
|
||||
name: test-[[ $suite ]]
|
||||
requires:
|
||||
- build
|
||||
suite: utest-[[ $suite ]]
|
||||
target: "[[ $pkgs ]]"
|
||||
[[if eq $suite "unit-cli"]]get-params: true[[end]]
|
||||
[[- if eq $suite "unit-rest"]]executor: golang-2xl[[end]]
|
||||
[[- end]]
|
||||
- test:
|
||||
go-test-flags: "-run=TestMulticoreSDR"
|
||||
requires:
|
||||
- build
|
||||
suite: multicore-sdr-check
|
||||
target: "./storage/sealer/ffiwrapper"
|
||||
proofs-log-test: "1"
|
||||
- test-conformance:
|
||||
requires:
|
||||
- build
|
||||
suite: conformance
|
||||
target: "./conformance"
|
||||
|
||||
|
||||
@@ -173,6 +173,16 @@ type FullNode interface {
|
||||
// If oldmsgskip is set, messages from before the requested roots are also not included.
|
||||
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) //perm:read
|
||||
|
||||
// ChainExportRangeInternal triggers the export of a chain
|
||||
// CAR-snapshot directly to disk. It is similar to ChainExport,
|
||||
// except, depending on options, the snapshot can include receipts,
|
||||
// messages and stateroots for the length between the specified head
|
||||
// and tail, thus producing "archival-grade" snapshots that include
|
||||
// all the on-chain data. The header chain is included back to
|
||||
// genesis and these snapshots can be used to initialize Filecoin
|
||||
// nodes.
|
||||
ChainExportRangeInternal(ctx context.Context, head, tail types.TipSetKey, cfg ChainExportConfig) error //perm:admin
|
||||
|
||||
// ChainPrune prunes the stored chain state and garbage collects; only supported if you
|
||||
// are using the splitstore
|
||||
ChainPrune(ctx context.Context, opts PruneOpts) error //perm:admin
|
||||
|
||||
@@ -155,6 +155,20 @@ func (mr *MockFullNodeMockRecorder) ChainExport(arg0, arg1, arg2, arg3 interface
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainExport", reflect.TypeOf((*MockFullNode)(nil).ChainExport), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// ChainExportRangeInternal mocks base method.
|
||||
func (m *MockFullNode) ChainExportRangeInternal(arg0 context.Context, arg1, arg2 types.TipSetKey, arg3 api.ChainExportConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChainExportRangeInternal", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ChainExportRangeInternal indicates an expected call of ChainExportRangeInternal.
|
||||
func (mr *MockFullNodeMockRecorder) ChainExportRangeInternal(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainExportRangeInternal", reflect.TypeOf((*MockFullNode)(nil).ChainExportRangeInternal), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// ChainGetBlock mocks base method.
|
||||
func (m *MockFullNode) ChainGetBlock(arg0 context.Context, arg1 cid.Cid) (*types.BlockHeader, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
+14
-1
@@ -117,7 +117,7 @@ type EthSubscriberStruct struct {
|
||||
}
|
||||
|
||||
type EthSubscriberMethods struct {
|
||||
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"`
|
||||
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true" rpc_method:"eth_subscription"`
|
||||
}
|
||||
|
||||
type EthSubscriberStub struct {
|
||||
@@ -140,6 +140,8 @@ type FullNodeMethods struct {
|
||||
|
||||
ChainExport func(p0 context.Context, p1 abi.ChainEpoch, p2 bool, p3 types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
ChainExportRangeInternal func(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error `perm:"admin"`
|
||||
|
||||
ChainGetBlock func(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) `perm:"read"`
|
||||
|
||||
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `perm:"read"`
|
||||
@@ -1439,6 +1441,17 @@ func (s *FullNodeStub) ChainExport(p0 context.Context, p1 abi.ChainEpoch, p2 boo
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainExportRangeInternal(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error {
|
||||
if s.Internal.ChainExportRangeInternal == nil {
|
||||
return ErrNotSupported
|
||||
}
|
||||
return s.Internal.ChainExportRangeInternal(p0, p1, p2, p3)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ChainExportRangeInternal(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetBlock(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) {
|
||||
if s.Internal.ChainGetBlock == nil {
|
||||
return nil, ErrNotSupported
|
||||
|
||||
@@ -398,3 +398,12 @@ func (m *MsgUuidMapType) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChainExportConfig holds configuration for chain ranged exports.
|
||||
type ChainExportConfig struct {
|
||||
WriteBufferSize int
|
||||
NumWorkers int
|
||||
IncludeMessages bool
|
||||
IncludeReceipts bool
|
||||
IncludeStateRoots bool
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/system"
|
||||
)
|
||||
|
||||
type BadgerMarkSetEnv struct {
|
||||
@@ -349,7 +351,7 @@ func (s *BadgerMarkSet) write(seqno int) (err error) {
|
||||
persist := s.persist
|
||||
s.mx.RUnlock()
|
||||
|
||||
if persist {
|
||||
if persist && !system.BadgerFsyncDisable { // WARNING: disabling sync makes recovery from crash during critical section unsound
|
||||
return s.db.Sync()
|
||||
}
|
||||
|
||||
|
||||
@@ -115,8 +115,6 @@ func (s *SplitStore) HeadChange(_, apply []*types.TipSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prioritize hot store compaction over cold store prune
|
||||
|
||||
if epoch-s.baseEpoch > CompactionThreshold {
|
||||
// it's time to compact -- prepare the transaction and go!
|
||||
s.beginTxnProtect()
|
||||
@@ -176,6 +174,8 @@ func (s *SplitStore) protectTipSets(apply []*types.TipSet) {
|
||||
timestamp := time.Unix(int64(curTs.MinTimestamp()), 0)
|
||||
doSync := time.Since(timestamp) < SyncWaitTime
|
||||
go func() {
|
||||
// we are holding the txnLk while marking
|
||||
// so critical section cannot delete
|
||||
if doSync {
|
||||
defer func() {
|
||||
s.txnSyncMx.Lock()
|
||||
@@ -689,7 +689,7 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
|
||||
|
||||
log.Infow("cold collection done", "took", time.Since(startCollect))
|
||||
|
||||
log.Infow("compaction stats", "hot", hotCnt, "cold", coldCnt)
|
||||
log.Infow("compaction stats", "hot", hotCnt, "cold", coldCnt, "purge", purgeCnt)
|
||||
stats.Record(s.ctx, metrics.SplitstoreCompactionHot.M(int64(hotCnt)))
|
||||
stats.Record(s.ctx, metrics.SplitstoreCompactionCold.M(int64(coldCnt)))
|
||||
|
||||
@@ -788,6 +788,9 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
|
||||
if err := os.Remove(s.coldSetPath()); err != nil {
|
||||
log.Warnf("error removing coldset: %s", err)
|
||||
}
|
||||
if err := os.Remove(s.discardSetPath()); err != nil {
|
||||
log.Warnf("error removing discardset: %s", err)
|
||||
}
|
||||
|
||||
// we are done; do some housekeeping
|
||||
s.endTxnProtect()
|
||||
|
||||
@@ -329,9 +329,9 @@ func (s *SplitStore) doPrune(curTs *types.TipSet, retainStateP func(int64) bool,
|
||||
}
|
||||
|
||||
s.pruneIndex++
|
||||
err = s.ds.Put(s.ctx, pruneIndexKey, int64ToBytes(s.compactionIndex))
|
||||
err = s.ds.Put(s.ctx, pruneIndexKey, int64ToBytes(s.pruneIndex))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error saving compaction index: %w", err)
|
||||
return xerrors.Errorf("error saving prune index: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -37,7 +37,7 @@ func BuildTypeString() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version
|
||||
const BuildVersion = "1.20.0"
|
||||
const BuildVersion = "1.21.0-dev"
|
||||
|
||||
func UserVersion() string {
|
||||
if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" {
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/multiformats/go-varint"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/lib/async"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
)
|
||||
|
||||
// Common operations shared by all consensus algorithm implementations.
|
||||
var log = logging.Logger("consensus-common")
|
||||
|
||||
// RunAsyncChecks accepts a list of checks to perform in parallel.
|
||||
//
|
||||
// Each consensus algorithm may choose to perform a set of different
|
||||
// checks when a new blocks is received.
|
||||
func RunAsyncChecks(ctx context.Context, await []async.ErrorFuture) error {
|
||||
var merr error
|
||||
for _, fut := range await {
|
||||
if err := fut.AwaitContext(ctx); err != nil {
|
||||
merr = multierror.Append(merr, err)
|
||||
}
|
||||
}
|
||||
if merr != nil {
|
||||
mulErr := merr.(*multierror.Error)
|
||||
mulErr.ErrorFormat = func(es []error) string {
|
||||
if len(es) == 1 {
|
||||
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
|
||||
}
|
||||
|
||||
points := make([]string, len(es))
|
||||
for i, err := range es {
|
||||
points[i] = fmt.Sprintf("* %+v", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%d errors occurred:\n\t%s\n\n",
|
||||
len(es), strings.Join(points, "\n\t"))
|
||||
}
|
||||
return mulErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommonBlkChecks performed by all consensus implementations.
|
||||
func CommonBlkChecks(ctx context.Context, sm *stmgr.StateManager, cs *store.ChainStore,
|
||||
b *types.FullBlock, baseTs *types.TipSet) []async.ErrorFuture {
|
||||
h := b.Header
|
||||
msgsCheck := async.Err(func() error {
|
||||
if b.Cid() == build.WhitelistedBlock {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := checkBlockMessages(ctx, sm, cs, b, baseTs); err != nil {
|
||||
return xerrors.Errorf("block had invalid messages: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
baseFeeCheck := async.Err(func() error {
|
||||
baseFee, err := cs.ComputeBaseFee(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("computing base fee: %w", err)
|
||||
}
|
||||
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
|
||||
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
|
||||
b.Header.ParentBaseFee, baseFee)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
stateRootCheck := async.Err(func() error {
|
||||
stateroot, precp, err := sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||
}
|
||||
|
||||
if stateroot != h.ParentStateRoot {
|
||||
msgs, err := cs.MessagesForTipset(ctx, baseTs)
|
||||
if err != nil {
|
||||
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
||||
} else {
|
||||
log.Warn("Messages for tipset with mismatching state:")
|
||||
for i, m := range msgs {
|
||||
mm := m.VMMessage()
|
||||
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
||||
}
|
||||
}
|
||||
|
||||
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", h.ParentStateRoot, stateroot)
|
||||
}
|
||||
|
||||
if precp != h.ParentMessageReceipts {
|
||||
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return []async.ErrorFuture{
|
||||
msgsCheck,
|
||||
baseFeeCheck,
|
||||
stateRootCheck,
|
||||
}
|
||||
}
|
||||
|
||||
func IsValidForSending(nv network.Version, act *types.Actor) bool {
|
||||
// Before nv18 (Hygge), we only supported built-in account actors as senders.
|
||||
//
|
||||
// Note: this gate is probably superfluous, since:
|
||||
// 1. Placeholder actors cannot be created before nv18.
|
||||
// 2. EthAccount actors cannot be created before nv18.
|
||||
// 3. Delegated addresses cannot be created before nv18.
|
||||
//
|
||||
// But it's a safeguard.
|
||||
//
|
||||
// Note 2: ad-hoc checks for network versions like this across the codebase
|
||||
// will be problematic with networks with diverging version lineages
|
||||
// (e.g. Hyperspace). We need to revisit this strategy entirely.
|
||||
if nv < network.Version18 {
|
||||
return builtin.IsAccountActor(act.Code)
|
||||
}
|
||||
|
||||
// After nv18, we also support other kinds of senders.
|
||||
if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Allow placeholder actors with a delegated address and nonce 0 to send a message.
|
||||
// These will be converted to an EthAccount actor on first send.
|
||||
if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only allow such actors to send if their delegated address is in the EAM's namespace.
|
||||
id, _, err := varint.FromUvarint(act.Address.Payload())
|
||||
return err == nil && id == builtintypes.EthereumAddressManagerActorID
|
||||
}
|
||||
|
||||
func checkBlockMessages(ctx context.Context, sm *stmgr.StateManager, cs *store.ChainStore, b *types.FullBlock, baseTs *types.TipSet) error {
|
||||
{
|
||||
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
|
||||
var pubks [][]byte
|
||||
|
||||
for _, m := range b.BlsMessages {
|
||||
sigCids = append(sigCids, m.Cid())
|
||||
|
||||
pubk, err := sm.GetBlsPublicKey(ctx, m.From, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
|
||||
}
|
||||
|
||||
pubks = append(pubks, pubk)
|
||||
}
|
||||
|
||||
if err := VerifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
|
||||
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
nonces := make(map[address.Address]uint64)
|
||||
|
||||
stateroot, _, err := sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute tipsettate for %s: %w", baseTs.Key(), err)
|
||||
}
|
||||
|
||||
st, err := state.LoadStateTree(cs.ActorStore(ctx), stateroot)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||
}
|
||||
|
||||
nv := sm.GetNetworkVersion(ctx, b.Header.Height)
|
||||
pl := vm.PricelistByEpoch(b.Header.Height)
|
||||
var sumGasLimit int64
|
||||
checkMsg := func(msg types.ChainMsg) error {
|
||||
m := msg.VMMessage()
|
||||
|
||||
// Phase 1: syntactic validation, as defined in the spec
|
||||
minGas := pl.OnChainMessage(msg.ChainLength())
|
||||
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
|
||||
return xerrors.Errorf("msg %s invalid for block inclusion: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
|
||||
// So below is overflow safe
|
||||
sumGasLimit += m.GasLimit
|
||||
if sumGasLimit > build.BlockGasLimit {
|
||||
return xerrors.Errorf("block gas limit exceeded")
|
||||
}
|
||||
|
||||
// Phase 2: (Partial) semantic validation:
|
||||
// the sender exists and is an account actor, and the nonces make sense
|
||||
var sender address.Address
|
||||
if nv >= network.Version13 {
|
||||
sender, err = st.LookupID(m.From)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to lookup sender %s: %w", m.From, err)
|
||||
}
|
||||
} else {
|
||||
sender = m.From
|
||||
}
|
||||
|
||||
if _, ok := nonces[sender]; !ok {
|
||||
// `GetActor` does not validate that this is an account actor.
|
||||
act, err := st.GetActor(sender)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get actor: %w", err)
|
||||
}
|
||||
|
||||
if !IsValidForSending(nv, act) {
|
||||
return xerrors.New("Sender must be an account actor")
|
||||
}
|
||||
nonces[sender] = act.Nonce
|
||||
}
|
||||
|
||||
if nonces[sender] != m.Nonce {
|
||||
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
|
||||
}
|
||||
nonces[sender]++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate message arrays in a temporary blockstore.
|
||||
tmpbs := bstore.NewMemory()
|
||||
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
|
||||
|
||||
bmArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.BlsMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
c, err := store.PutMessage(ctx, tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
k := cbg.CborCid(c)
|
||||
if err := bmArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
smArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if nv >= network.Version14 && !IsValidSecpkSigType(nv, m.Signature.Type) {
|
||||
return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
// `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
|
||||
// in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
|
||||
kaddr, err := sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||
}
|
||||
|
||||
if err := AuthenticateMessage(m, kaddr); err != nil {
|
||||
return xerrors.Errorf("failed to validate signature: %w", err)
|
||||
}
|
||||
|
||||
c, err := store.PutMessage(ctx, tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
k := cbg.CborCid(c)
|
||||
if err := smArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
bmroot, err := bmArr.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to root bls msgs: %w", err)
|
||||
|
||||
}
|
||||
|
||||
smroot, err := smArr.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to root secp msgs: %w", err)
|
||||
}
|
||||
|
||||
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
|
||||
BlsMessages: bmroot,
|
||||
SecpkMessages: smroot,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to put msg meta: %w", err)
|
||||
}
|
||||
|
||||
if b.Header.Messages != mrcid {
|
||||
return fmt.Errorf("messages didnt match message root in header")
|
||||
}
|
||||
|
||||
// Finally, flush.
|
||||
err = vm.Copy(ctx, tmpbs, cs.ChainBlockstore(), mrcid)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to flush:%w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateBlockHeader generates the block header from the block template of
|
||||
// the block being proposed.
|
||||
func CreateBlockHeader(ctx context.Context, sm *stmgr.StateManager, pts *types.TipSet,
|
||||
bt *api.BlockTemplate) (*types.BlockHeader, []*types.Message, []*types.SignedMessage, error) {
|
||||
|
||||
st, recpts, err := sm.TipSetState(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("failed to load tipset state: %w", err)
|
||||
}
|
||||
next := &types.BlockHeader{
|
||||
Miner: bt.Miner,
|
||||
Parents: bt.Parents.Cids(),
|
||||
Ticket: bt.Ticket,
|
||||
ElectionProof: bt.Eproof,
|
||||
|
||||
BeaconEntries: bt.BeaconValues,
|
||||
Height: bt.Epoch,
|
||||
Timestamp: bt.Timestamp,
|
||||
WinPoStProof: bt.WinningPoStProof,
|
||||
ParentStateRoot: st,
|
||||
ParentMessageReceipts: recpts,
|
||||
}
|
||||
|
||||
var blsMessages []*types.Message
|
||||
var secpkMessages []*types.SignedMessage
|
||||
|
||||
var blsMsgCids, secpkMsgCids []cid.Cid
|
||||
var blsSigs []crypto.Signature
|
||||
nv := sm.GetNetworkVersion(ctx, bt.Epoch)
|
||||
for _, msg := range bt.Messages {
|
||||
if msg.Signature.Type == crypto.SigTypeBLS {
|
||||
blsSigs = append(blsSigs, msg.Signature)
|
||||
blsMessages = append(blsMessages, &msg.Message)
|
||||
|
||||
c, err := sm.ChainStore().PutMessage(ctx, &msg.Message)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
blsMsgCids = append(blsMsgCids, c)
|
||||
} else if IsValidSecpkSigType(nv, msg.Signature.Type) {
|
||||
c, err := sm.ChainStore().PutMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
secpkMsgCids = append(secpkMsgCids, c)
|
||||
secpkMessages = append(secpkMessages, msg)
|
||||
|
||||
} else {
|
||||
return nil, nil, nil, xerrors.Errorf("unknown sig type: %d", msg.Signature.Type)
|
||||
}
|
||||
}
|
||||
|
||||
store := sm.ChainStore().ActorStore(ctx)
|
||||
blsmsgroot, err := ToMessagesArray(store, blsMsgCids)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("building bls amt: %w", err)
|
||||
}
|
||||
secpkmsgroot, err := ToMessagesArray(store, secpkMsgCids)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("building secpk amt: %w", err)
|
||||
}
|
||||
|
||||
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||
BlsMessages: blsmsgroot,
|
||||
SecpkMessages: secpkmsgroot,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
next.Messages = mmcid
|
||||
|
||||
aggSig, err := AggregateSignatures(blsSigs)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
next.BLSAggregate = aggSig
|
||||
pweight, err := sm.ChainStore().Weight(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
next.ParentWeight = pweight
|
||||
|
||||
baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("computing base fee: %w", err)
|
||||
}
|
||||
next.ParentBaseFee = baseFee
|
||||
|
||||
return next, blsMessages, secpkMessages, err
|
||||
|
||||
}
|
||||
|
||||
// Basic sanity-checks performed when a block is proposed locally.
|
||||
func validateLocalBlock(ctx context.Context, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||
stats.Record(ctx, metrics.BlockPublished.M(1))
|
||||
|
||||
if size := msg.Size(); size > 1<<20-1<<15 {
|
||||
log.Errorf("ignoring oversize block (%dB)", size)
|
||||
return pubsub.ValidationIgnore, "oversize_block"
|
||||
}
|
||||
|
||||
blk, what, err := decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Errorf("got invalid local block: %s", err)
|
||||
return pubsub.ValidationIgnore, what
|
||||
}
|
||||
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept, ""
|
||||
}
|
||||
|
||||
func decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
|
||||
}
|
||||
|
||||
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
|
||||
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
|
||||
}
|
||||
|
||||
// make sure we have a signature
|
||||
if blk.Header.BlockSig == nil {
|
||||
return nil, "missing_signature", fmt.Errorf("block without a signature")
|
||||
}
|
||||
|
||||
return blk, "", nil
|
||||
}
|
||||
|
||||
func validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||
// block headers use adt0
|
||||
store := blockadt.WrapStore(ctx, cbor.NewCborStore(bstore.NewMemory()))
|
||||
bmArr := blockadt.MakeEmptyArray(store)
|
||||
smArr := blockadt.MakeEmptyArray(store)
|
||||
|
||||
for i, m := range msg.BlsMessages {
|
||||
c := cbg.CborCid(m)
|
||||
if err := bmArr.Set(uint64(i), &c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i, m := range msg.SecpkMessages {
|
||||
c := cbg.CborCid(m)
|
||||
if err := smArr.Set(uint64(i), &c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bmroot, err := bmArr.Root()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smroot, err := smArr.Root()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||
BlsMessages: bmroot,
|
||||
SecpkMessages: smroot,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.Header.Messages != mrcid {
|
||||
return fmt.Errorf("messages didn't match root cid in header")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package filcns
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/cron"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
@@ -55,10 +54,12 @@ func NewActorRegistry() *vm.ActorRegistry {
|
||||
return inv
|
||||
}
|
||||
|
||||
type TipSetExecutor struct{}
|
||||
type TipSetExecutor struct {
|
||||
reward RewardFunc
|
||||
}
|
||||
|
||||
func NewTipSetExecutor() *TipSetExecutor {
|
||||
return &TipSetExecutor{}
|
||||
func NewTipSetExecutor(r RewardFunc) *TipSetExecutor {
|
||||
return &TipSetExecutor{reward: r}
|
||||
}
|
||||
|
||||
func (t *TipSetExecutor) NewActorRegistry() *vm.ActorRegistry {
|
||||
@@ -226,39 +227,15 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
|
||||
processedMsgs[m.Cid()] = struct{}{}
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||
params := &reward.AwardBlockRewardParams{
|
||||
Miner: b.Miner,
|
||||
Penalty: penalty,
|
||||
GasReward: gasReward,
|
||||
WinCount: b.WinCount,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||
}
|
||||
|
||||
rwMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasLimit: 1 << 30,
|
||||
Method: reward.Methods.AwardBlockReward,
|
||||
Params: params,
|
||||
}
|
||||
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||
if actErr != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
|
||||
}
|
||||
if em != nil {
|
||||
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
|
||||
rErr := t.reward(ctx, vmi, em, epoch, ts, params)
|
||||
if rErr != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("error applying reward: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,46 +4,36 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/multiformats/go-varint"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/filecoin-project/specs-actors/v7/actors/runtime/proof"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/lib/async"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
||||
)
|
||||
@@ -69,6 +59,39 @@ type FilecoinEC struct {
|
||||
// the theoretical max height based on systime are quickly rejected
|
||||
const MaxHeightDrift = 5
|
||||
|
||||
var RewardFunc = func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonitor,
|
||||
epoch abi.ChainEpoch, ts *types.TipSet, params *reward.AwardBlockRewardParams) error {
|
||||
ser, err := actors.SerializeParams(params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to serialize award params: %w", err)
|
||||
}
|
||||
rwMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasLimit: 1 << 30,
|
||||
Method: reward.Methods.AwardBlockReward,
|
||||
Params: ser,
|
||||
}
|
||||
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||
if actErr != nil {
|
||||
return xerrors.Errorf("failed to apply reward message: %w", actErr)
|
||||
}
|
||||
if em != nil {
|
||||
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
|
||||
return xerrors.Errorf("callback failed on reward message: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFilecoinExpectedConsensus(sm *stmgr.StateManager, beacon beacon.Schedule, verifier storiface.Verifier, genesis chain.Genesis) consensus.Consensus {
|
||||
if build.InsecurePoStValidation {
|
||||
log.Warn("*********************************************************************************************")
|
||||
@@ -127,17 +150,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
|
||||
}
|
||||
|
||||
msgsCheck := async.Err(func() error {
|
||||
if b.Cid() == build.WhitelistedBlock {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := filec.checkBlockMessages(ctx, b, baseTs); err != nil {
|
||||
return xerrors.Errorf("block had invalid messages: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
minerCheck := async.Err(func() error {
|
||||
if err := filec.minerIsValid(ctx, h.Miner, baseTs); err != nil {
|
||||
return xerrors.Errorf("minerIsValid failed: %w", err)
|
||||
@@ -145,17 +157,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
return nil
|
||||
})
|
||||
|
||||
baseFeeCheck := async.Err(func() error {
|
||||
baseFee, err := filec.store.ComputeBaseFee(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("computing base fee: %w", err)
|
||||
}
|
||||
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
|
||||
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
|
||||
b.Header.ParentBaseFee, baseFee)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
pweight, err := filec.store.Weight(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting parent weight: %w", err)
|
||||
@@ -166,34 +167,6 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
b.Header.ParentWeight, pweight)
|
||||
}
|
||||
|
||||
stateRootCheck := async.Err(func() error {
|
||||
stateroot, precp, err := filec.sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||
}
|
||||
|
||||
if stateroot != h.ParentStateRoot {
|
||||
msgs, err := filec.store.MessagesForTipset(ctx, baseTs)
|
||||
if err != nil {
|
||||
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
||||
} else {
|
||||
log.Warn("Messages for tipset with mismatching state:")
|
||||
for i, m := range msgs {
|
||||
mm := m.VMMessage()
|
||||
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
||||
}
|
||||
}
|
||||
|
||||
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", h.ParentStateRoot, stateroot)
|
||||
}
|
||||
|
||||
if precp != h.ParentMessageReceipts {
|
||||
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Stuff that needs worker address
|
||||
waddr, err := stmgr.GetMinerWorkerRaw(ctx, filec.sm, lbst, h.Miner)
|
||||
if err != nil {
|
||||
@@ -255,10 +228,11 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
})
|
||||
|
||||
blockSigCheck := async.Err(func() error {
|
||||
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
|
||||
if err := verifyBlockSignature(ctx, h, waddr); err != nil {
|
||||
return xerrors.Errorf("check block signature failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
})
|
||||
|
||||
beaconValuesCheck := async.Err(func() error {
|
||||
@@ -307,44 +281,17 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock)
|
||||
return nil
|
||||
})
|
||||
|
||||
await := []async.ErrorFuture{
|
||||
commonChecks := consensus.CommonBlkChecks(ctx, filec.sm, filec.store, b, baseTs)
|
||||
await := append([]async.ErrorFuture{
|
||||
minerCheck,
|
||||
tktsCheck,
|
||||
blockSigCheck,
|
||||
beaconValuesCheck,
|
||||
wproofCheck,
|
||||
winnerCheck,
|
||||
msgsCheck,
|
||||
baseFeeCheck,
|
||||
stateRootCheck,
|
||||
}
|
||||
}, commonChecks...)
|
||||
|
||||
var merr error
|
||||
for _, fut := range await {
|
||||
if err := fut.AwaitContext(ctx); err != nil {
|
||||
merr = multierror.Append(merr, err)
|
||||
}
|
||||
}
|
||||
if merr != nil {
|
||||
mulErr := merr.(*multierror.Error)
|
||||
mulErr.ErrorFormat = func(es []error) string {
|
||||
if len(es) == 1 {
|
||||
return fmt.Sprintf("1 error occurred:\n\t* %+v\n\n", es[0])
|
||||
}
|
||||
|
||||
points := make([]string, len(es))
|
||||
for i, err := range es {
|
||||
points[i] = fmt.Sprintf("* %+v", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%d errors occurred:\n\t%s\n\n",
|
||||
len(es), strings.Join(points, "\n\t"))
|
||||
}
|
||||
return mulErr
|
||||
}
|
||||
|
||||
return nil
|
||||
return consensus.RunAsyncChecks(ctx, await)
|
||||
}
|
||||
|
||||
func blockSanityChecks(h *types.BlockHeader) error {
|
||||
@@ -435,209 +382,6 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsValidForSending(nv network.Version, act *types.Actor) bool {
|
||||
// Before nv18 (Hygge), we only supported built-in account actors as senders.
|
||||
//
|
||||
// Note: this gate is probably superfluous, since:
|
||||
// 1. Placeholder actors cannot be created before nv18.
|
||||
// 2. EthAccount actors cannot be created before nv18.
|
||||
// 3. Delegated addresses cannot be created before nv18.
|
||||
//
|
||||
// But it's a safeguard.
|
||||
//
|
||||
// Note 2: ad-hoc checks for network versions like this across the codebase
|
||||
// will be problematic with networks with diverging version lineages
|
||||
// (e.g. Hyperspace). We need to revisit this strategy entirely.
|
||||
if nv < network.Version18 {
|
||||
return builtin.IsAccountActor(act.Code)
|
||||
}
|
||||
|
||||
// After nv18, we also support other kinds of senders.
|
||||
if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Allow placeholder actors with a delegated address and nonce 0 to send a message.
|
||||
// These will be converted to an EthAccount actor on first send.
|
||||
if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only allow such actors to send if their delegated address is in the EAM's namespace.
|
||||
id, _, err := varint.FromUvarint(act.Address.Payload())
|
||||
return err == nil && id == builtintypes.EthereumAddressManagerActorID
|
||||
}
|
||||
|
||||
// TODO: We should extract this somewhere else and make the message pool and miner use the same logic
|
||||
func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
|
||||
{
|
||||
var sigCids []cid.Cid // this is what we get for people not wanting the marshalcbor method on the cid type
|
||||
var pubks [][]byte
|
||||
|
||||
for _, m := range b.BlsMessages {
|
||||
sigCids = append(sigCids, m.Cid())
|
||||
|
||||
pubk, err := filec.sm.GetBlsPublicKey(ctx, m.From, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load bls public to validate block: %w", err)
|
||||
}
|
||||
|
||||
pubks = append(pubks, pubk)
|
||||
}
|
||||
|
||||
if err := consensus.VerifyBlsAggregate(ctx, b.Header.BLSAggregate, sigCids, pubks); err != nil {
|
||||
return xerrors.Errorf("bls aggregate signature was invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
nonces := make(map[address.Address]uint64)
|
||||
|
||||
stateroot, _, err := filec.sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute tipsettate for %s: %w", baseTs.Key(), err)
|
||||
}
|
||||
|
||||
st, err := state.LoadStateTree(filec.store.ActorStore(ctx), stateroot)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||
}
|
||||
|
||||
nv := filec.sm.GetNetworkVersion(ctx, b.Header.Height)
|
||||
pl := vm.PricelistByEpoch(b.Header.Height)
|
||||
var sumGasLimit int64
|
||||
checkMsg := func(msg types.ChainMsg) error {
|
||||
m := msg.VMMessage()
|
||||
|
||||
// Phase 1: syntactic validation, as defined in the spec
|
||||
minGas := pl.OnChainMessage(msg.ChainLength())
|
||||
if err := m.ValidForBlockInclusion(minGas.Total(), nv); err != nil {
|
||||
return xerrors.Errorf("msg %s invalid for block inclusion: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
// ValidForBlockInclusion checks if any single message does not exceed BlockGasLimit
|
||||
// So below is overflow safe
|
||||
sumGasLimit += m.GasLimit
|
||||
if sumGasLimit > build.BlockGasLimit {
|
||||
return xerrors.Errorf("block gas limit exceeded")
|
||||
}
|
||||
|
||||
// Phase 2: (Partial) semantic validation:
|
||||
// the sender exists and is an account actor, and the nonces make sense
|
||||
var sender address.Address
|
||||
if nv >= network.Version13 {
|
||||
sender, err = st.LookupID(m.From)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to lookup sender %s: %w", m.From, err)
|
||||
}
|
||||
} else {
|
||||
sender = m.From
|
||||
}
|
||||
|
||||
if _, ok := nonces[sender]; !ok {
|
||||
// `GetActor` does not validate that this is an account actor.
|
||||
act, err := st.GetActor(sender)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get actor: %w", err)
|
||||
}
|
||||
|
||||
if !IsValidForSending(nv, act) {
|
||||
return xerrors.New("Sender must be an account actor")
|
||||
}
|
||||
nonces[sender] = act.Nonce
|
||||
}
|
||||
|
||||
if nonces[sender] != m.Nonce {
|
||||
return xerrors.Errorf("wrong nonce (exp: %d, got: %d)", nonces[sender], m.Nonce)
|
||||
}
|
||||
nonces[sender]++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate message arrays in a temporary blockstore.
|
||||
tmpbs := bstore.NewMemory()
|
||||
tmpstore := blockadt.WrapStore(ctx, cbor.NewCborStore(tmpbs))
|
||||
|
||||
bmArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.BlsMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
c, err := store.PutMessage(ctx, tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
k := cbg.CborCid(c)
|
||||
if err := bmArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put bls message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
smArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if nv >= network.Version14 && !chain.IsValidSecpkSigType(nv, m.Signature.Type) {
|
||||
return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
// `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
|
||||
// in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
|
||||
kaddr, err := filec.sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||
}
|
||||
|
||||
if err := chain.AuthenticateMessage(m, kaddr); err != nil {
|
||||
return xerrors.Errorf("failed to validate signature: %w", err)
|
||||
}
|
||||
|
||||
c, err := store.PutMessage(ctx, tmpbs, m)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to store message %s: %w", m.Cid(), err)
|
||||
}
|
||||
k := cbg.CborCid(c)
|
||||
if err := smArr.Set(uint64(i), &k); err != nil {
|
||||
return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
bmroot, err := bmArr.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to root bls msgs: %w", err)
|
||||
|
||||
}
|
||||
|
||||
smroot, err := smArr.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to root secp msgs: %w", err)
|
||||
}
|
||||
|
||||
mrcid, err := tmpstore.Put(ctx, &types.MsgMeta{
|
||||
BlsMessages: bmroot,
|
||||
SecpkMessages: smroot,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to put msg meta: %w", err)
|
||||
}
|
||||
|
||||
if b.Header.Messages != mrcid {
|
||||
return fmt.Errorf("messages didnt match message root in header")
|
||||
}
|
||||
|
||||
// Finally, flush.
|
||||
err = vm.Copy(ctx, tmpbs, filec.store.ChainBlockstore(), mrcid)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to flush:%w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||
if filec.genesis == nil {
|
||||
return false
|
||||
@@ -693,140 +437,7 @@ func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []
|
||||
var ErrSoftFailure = errors.New("soft validation failure")
|
||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||
|
||||
func (filec *FilecoinEC) ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||
if self {
|
||||
return filec.validateLocalBlock(ctx, msg)
|
||||
}
|
||||
|
||||
// track validation time
|
||||
begin := build.Clock.Now()
|
||||
defer func() {
|
||||
log.Debugf("block validation time: %s", build.Clock.Since(begin))
|
||||
}()
|
||||
|
||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||
|
||||
recordFailureFlagPeer := func(what string) {
|
||||
// bv.Validate will flag the peer in that case
|
||||
panic(what)
|
||||
}
|
||||
|
||||
blk, what, err := filec.decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
recordFailureFlagPeer(what)
|
||||
return pubsub.ValidationReject, what
|
||||
}
|
||||
|
||||
// validate the block meta: the Message CID in the header must match the included messages
|
||||
err = filec.validateMsgMeta(ctx, blk)
|
||||
if err != nil {
|
||||
log.Warnf("error validating message metadata: %s", err)
|
||||
recordFailureFlagPeer("invalid_block_meta")
|
||||
return pubsub.ValidationReject, "invalid_block_meta"
|
||||
}
|
||||
|
||||
reject, err := filec.validateBlockHeader(ctx, blk.Header)
|
||||
if err != nil {
|
||||
if reject == "" {
|
||||
log.Warn("ignoring block msg: ", err)
|
||||
return pubsub.ValidationIgnore, reject
|
||||
}
|
||||
recordFailureFlagPeer(reject)
|
||||
return pubsub.ValidationReject, reject
|
||||
}
|
||||
|
||||
// all good, accept the block
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept, ""
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) validateLocalBlock(ctx context.Context, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||
stats.Record(ctx, metrics.BlockPublished.M(1))
|
||||
|
||||
if size := msg.Size(); size > 1<<20-1<<15 {
|
||||
log.Errorf("ignoring oversize block (%dB)", size)
|
||||
return pubsub.ValidationIgnore, "oversize_block"
|
||||
}
|
||||
|
||||
blk, what, err := filec.decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Errorf("got invalid local block: %s", err)
|
||||
return pubsub.ValidationIgnore, what
|
||||
}
|
||||
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept, ""
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) decodeAndCheckBlock(msg *pubsub.Message) (*types.BlockMsg, string, error) {
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
return nil, "invalid", xerrors.Errorf("error decoding block: %w", err)
|
||||
}
|
||||
|
||||
if count := len(blk.BlsMessages) + len(blk.SecpkMessages); count > build.BlockMessageLimit {
|
||||
return nil, "too_many_messages", fmt.Errorf("block contains too many messages (%d)", count)
|
||||
}
|
||||
|
||||
// make sure we have a signature
|
||||
if blk.Header.BlockSig == nil {
|
||||
return nil, "missing_signature", fmt.Errorf("block without a signature")
|
||||
}
|
||||
|
||||
return blk, "", nil
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||
// block headers use adt0
|
||||
store := blockadt.WrapStore(ctx, cbor.NewCborStore(bstore.NewMemory()))
|
||||
bmArr := blockadt.MakeEmptyArray(store)
|
||||
smArr := blockadt.MakeEmptyArray(store)
|
||||
|
||||
for i, m := range msg.BlsMessages {
|
||||
c := cbg.CborCid(m)
|
||||
if err := bmArr.Set(uint64(i), &c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i, m := range msg.SecpkMessages {
|
||||
c := cbg.CborCid(m)
|
||||
if err := smArr.Set(uint64(i), &c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bmroot, err := bmArr.Root()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smroot, err := smArr.Root()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mrcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||
BlsMessages: bmroot,
|
||||
SecpkMessages: smroot,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.Header.Messages != mrcid {
|
||||
return fmt.Errorf("messages didn't match root cid in header")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (filec *FilecoinEC) validateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error) {
|
||||
func (filec *FilecoinEC) ValidateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error) {
|
||||
|
||||
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
|
||||
// to prevent spam attacks.
|
||||
@@ -901,4 +512,27 @@ func (filec *FilecoinEC) isChainNearSynced() bool {
|
||||
return build.Clock.Since(timestampTime) < 6*time.Hour
|
||||
}
|
||||
|
||||
func verifyBlockSignature(ctx context.Context, h *types.BlockHeader,
|
||||
addr address.Address) error {
|
||||
return sigs.CheckBlockSignature(ctx, h, addr)
|
||||
}
|
||||
|
||||
func signBlock(ctx context.Context, w api.Wallet,
|
||||
addr address.Address, next *types.BlockHeader) error {
|
||||
|
||||
nosigbytes, err := next.SigningBytes()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get signing bytes for block: %w", err)
|
||||
}
|
||||
|
||||
sig, err := w.WalletSign(ctx, addr, nosigbytes, api.MsgMeta{
|
||||
Type: api.MTBlock,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to sign new block: %w", err)
|
||||
}
|
||||
next.BlockSig = sig
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ consensus.Consensus = &FilecoinEC{}
|
||||
|
||||
@@ -3,13 +3,9 @@ package filcns
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -21,11 +17,6 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
|
||||
return nil, xerrors.Errorf("failed to load parent tipset: %w", err)
|
||||
}
|
||||
|
||||
st, recpts, err := filec.sm.TipSetState(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load tipset state: %w", err)
|
||||
}
|
||||
|
||||
_, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, filec.sm, pts, bt.Epoch)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
||||
@@ -36,102 +27,15 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
|
||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
|
||||
next := &types.BlockHeader{
|
||||
Miner: bt.Miner,
|
||||
Parents: bt.Parents.Cids(),
|
||||
Ticket: bt.Ticket,
|
||||
ElectionProof: bt.Eproof,
|
||||
|
||||
BeaconEntries: bt.BeaconValues,
|
||||
Height: bt.Epoch,
|
||||
Timestamp: bt.Timestamp,
|
||||
WinPoStProof: bt.WinningPoStProof,
|
||||
ParentStateRoot: st,
|
||||
ParentMessageReceipts: recpts,
|
||||
}
|
||||
|
||||
var blsMessages []*types.Message
|
||||
var secpkMessages []*types.SignedMessage
|
||||
|
||||
var blsMsgCids, secpkMsgCids []cid.Cid
|
||||
var blsSigs []crypto.Signature
|
||||
nv := filec.sm.GetNetworkVersion(ctx, bt.Epoch)
|
||||
for _, msg := range bt.Messages {
|
||||
if msg.Signature.Type == crypto.SigTypeBLS {
|
||||
blsSigs = append(blsSigs, msg.Signature)
|
||||
blsMessages = append(blsMessages, &msg.Message)
|
||||
|
||||
c, err := filec.sm.ChainStore().PutMessage(ctx, &msg.Message)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blsMsgCids = append(blsMsgCids, c)
|
||||
} else if chain.IsValidSecpkSigType(nv, msg.Signature.Type) {
|
||||
c, err := filec.sm.ChainStore().PutMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secpkMsgCids = append(secpkMsgCids, c)
|
||||
secpkMessages = append(secpkMessages, msg)
|
||||
|
||||
} else {
|
||||
return nil, xerrors.Errorf("unknown sig type: %d", msg.Signature.Type)
|
||||
}
|
||||
}
|
||||
|
||||
store := filec.sm.ChainStore().ActorStore(ctx)
|
||||
blsmsgroot, err := consensus.ToMessagesArray(store, blsMsgCids)
|
||||
next, blsMessages, secpkMessages, err := consensus.CreateBlockHeader(ctx, filec.sm, pts, bt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("building bls amt: %w", err)
|
||||
}
|
||||
secpkmsgroot, err := consensus.ToMessagesArray(store, secpkMsgCids)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("building secpk amt: %w", err)
|
||||
return nil, xerrors.Errorf("failed to process messages from block template: %w", err)
|
||||
}
|
||||
|
||||
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
|
||||
BlsMessages: blsmsgroot,
|
||||
SecpkMessages: secpkmsgroot,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
next.Messages = mmcid
|
||||
|
||||
aggSig, err := consensus.AggregateSignatures(blsSigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
next.BLSAggregate = aggSig
|
||||
pweight, err := filec.sm.ChainStore().Weight(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
next.ParentWeight = pweight
|
||||
|
||||
baseFee, err := filec.sm.ChainStore().ComputeBaseFee(ctx, pts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("computing base fee: %w", err)
|
||||
}
|
||||
next.ParentBaseFee = baseFee
|
||||
|
||||
nosigbytes, err := next.SigningBytes()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
|
||||
}
|
||||
|
||||
sig, err := w.WalletSign(ctx, worker, nosigbytes, api.MsgMeta{
|
||||
Type: api.MTBlock,
|
||||
})
|
||||
if err != nil {
|
||||
if err := signBlock(ctx, w, worker, next); err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign new block: %w", err)
|
||||
}
|
||||
|
||||
next.BlockSig = sig
|
||||
|
||||
fullBlock := &types.FullBlock{
|
||||
Header: next,
|
||||
BlsMessages: blsMessages,
|
||||
|
||||
@@ -4,17 +4,99 @@ import (
|
||||
"context"
|
||||
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"go.opencensus.io/stats"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
)
|
||||
|
||||
type Consensus interface {
|
||||
// ValidateBlockHeader is called by peers when they receive a new block through the network.
|
||||
//
|
||||
// This is a fast sanity-check validation performed by the PubSub protocol before delivering
|
||||
// it to the syncer. It checks that the block has the right format and it performs
|
||||
// other consensus-specific light verifications like ensuring that the block is signed by
|
||||
// a valid miner, or that it includes all the data required for a full verification.
|
||||
ValidateBlockHeader(ctx context.Context, b *types.BlockHeader) (rejectReason string, err error)
|
||||
|
||||
// ValidateBlock is called by the syncer to determine if to accept a block or not.
|
||||
//
|
||||
// It performs all the checks needed by the syncer to accept
|
||||
// the block (signature verifications, VRF checks, message validity, etc.)
|
||||
ValidateBlock(ctx context.Context, b *types.FullBlock) (err error)
|
||||
ValidateBlockPubsub(ctx context.Context, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string)
|
||||
|
||||
// IsEpochBeyondCurrMax is used to configure the fork rules for longest-chain
|
||||
// consensus protocols.
|
||||
IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool
|
||||
|
||||
// CreateBlock implements all the logic required to propose and assemble a new Filecoin block.
|
||||
//
|
||||
// This function encapsulate all the consensus-specific actions to propose a new block
|
||||
// such as the ordering of transactions, the inclusion of consensus proofs, the signature
|
||||
// of the block, etc.
|
||||
CreateBlock(ctx context.Context, w api.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error)
|
||||
}
|
||||
|
||||
// RewardFunc parametrizes the logic for rewards when a message is executed.
|
||||
//
|
||||
// Each consensus implementation can set their own reward function.
|
||||
type RewardFunc func(ctx context.Context, vmi vm.Interface, em stmgr.ExecMonitor,
|
||||
epoch abi.ChainEpoch, ts *types.TipSet, params *reward.AwardBlockRewardParams) error
|
||||
|
||||
// ValidateBlockPubsub implements the common checks performed by all consensus implementations
|
||||
// when a block is received through the pubsub channel.
|
||||
func ValidateBlockPubsub(ctx context.Context, cns Consensus, self bool, msg *pubsub.Message) (pubsub.ValidationResult, string) {
|
||||
if self {
|
||||
return validateLocalBlock(ctx, msg)
|
||||
}
|
||||
|
||||
// track validation time
|
||||
begin := build.Clock.Now()
|
||||
defer func() {
|
||||
log.Debugf("block validation time: %s", build.Clock.Since(begin))
|
||||
}()
|
||||
|
||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||
|
||||
recordFailureFlagPeer := func(what string) {
|
||||
// bv.Validate will flag the peer in that case
|
||||
panic(what)
|
||||
}
|
||||
|
||||
blk, what, err := decodeAndCheckBlock(msg)
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
recordFailureFlagPeer(what)
|
||||
return pubsub.ValidationReject, what
|
||||
}
|
||||
|
||||
// validate the block meta: the Message CID in the header must match the included messages
|
||||
err = validateMsgMeta(ctx, blk)
|
||||
if err != nil {
|
||||
log.Warnf("error validating message metadata: %s", err)
|
||||
recordFailureFlagPeer("invalid_block_meta")
|
||||
return pubsub.ValidationReject, "invalid_block_meta"
|
||||
}
|
||||
|
||||
reject, err := cns.ValidateBlockHeader(ctx, blk.Header)
|
||||
if err != nil {
|
||||
if reject == "" {
|
||||
log.Warn("ignoring block msg: ", err)
|
||||
return pubsub.ValidationIgnore, reject
|
||||
}
|
||||
recordFailureFlagPeer(reject)
|
||||
return pubsub.ValidationReject, reject
|
||||
}
|
||||
|
||||
// all good, accept the block
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept, ""
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package chain
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
+2
-1
@@ -31,6 +31,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
"github.com/filecoin-project/lotus/chain/rand"
|
||||
@@ -255,7 +256,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
//}
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), sys, us, beac)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), sys, us, beac)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/system"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -486,7 +486,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.Sysca
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.StateBlockstore(),
|
||||
Actors: filcns.NewActorRegistry(),
|
||||
Actors: consensus.NewActorRegistry(),
|
||||
Syscalls: mkFakedSigSyscalls(sys),
|
||||
CircSupplyCalc: csc,
|
||||
NetworkVersion: nv,
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -94,7 +94,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.StateBlockstore(),
|
||||
Actors: filcns.NewActorRegistry(),
|
||||
Actors: consensus.NewActorRegistry(),
|
||||
Syscalls: mkFakedSigSyscalls(sys),
|
||||
CircSupplyCalc: csc,
|
||||
NetworkVersion: nv,
|
||||
|
||||
@@ -33,8 +33,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -794,7 +793,7 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := chain.AuthenticateMessage(m, m.Message.From); err != nil {
|
||||
if err := consensus.AuthenticateMessage(m, m.Message.From); err != nil {
|
||||
return xerrors.Errorf("failed to validate signature: %w", err)
|
||||
}
|
||||
|
||||
@@ -862,7 +861,7 @@ func (mp *MessagePool) addTs(ctx context.Context, m *types.SignedMessage, curTs
|
||||
nv := mp.api.StateNetworkVersion(ctx, epoch)
|
||||
|
||||
// TODO: I'm not thrilled about depending on filcns here, but I prefer this to duplicating logic
|
||||
if !filcns.IsValidForSending(nv, senderAct) {
|
||||
if !consensus.IsValidForSending(nv, senderAct) {
|
||||
return false, xerrors.Errorf("sender actor %s is not a valid top-level sender", m.Message.From)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -26,6 +28,9 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
// EnvDisablePreMigrations when set to '1' stops pre-migrations from running
|
||||
const EnvDisablePreMigrations = "LOTUS_DISABLE_PRE_MIGRATIONS"
|
||||
|
||||
// MigrationCache can be used to cache information used by a migration. This is primarily useful to
|
||||
// "pre-compute" some migration state ahead of time, and make it accessible in the migration itself.
|
||||
type MigrationCache interface {
|
||||
@@ -218,6 +223,11 @@ func runPreMigration(ctx context.Context, sm *StateManager, fn PreMigrationFunc,
|
||||
height := ts.Height()
|
||||
parent := ts.ParentState()
|
||||
|
||||
if disabled := os.Getenv(EnvDisablePreMigrations); strings.TrimSpace(disabled) == "1" {
|
||||
log.Warnw("SKIPPING pre-migration", "height", height)
|
||||
return
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
log.Warn("STARTING pre-migration")
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
. "github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -128,7 +130,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
sm, err := NewStateManager(
|
||||
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||
@@ -169,7 +171,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inv := filcns.NewActorRegistry()
|
||||
inv := consensus.NewActorRegistry()
|
||||
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
|
||||
inv.Register(actorstypes.Version0, nil, registry)
|
||||
|
||||
@@ -274,7 +276,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
|
||||
|
||||
var migrationCount int
|
||||
sm, err := NewStateManager(
|
||||
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Expensive: true,
|
||||
Height: testForkHeight,
|
||||
@@ -287,7 +289,7 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inv := filcns.NewActorRegistry()
|
||||
inv := consensus.NewActorRegistry()
|
||||
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
|
||||
inv.Register(actorstypes.Version0, nil, registry)
|
||||
|
||||
@@ -412,7 +414,7 @@ func TestForkPreMigration(t *testing.T) {
|
||||
counter := make(chan struct{}, 10)
|
||||
|
||||
sm, err := NewStateManager(
|
||||
cg.ChainStore(), filcns.NewTipSetExecutor(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
cg.ChainStore(), consensus.NewTipSetExecutor(filcns.RewardFunc), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||
@@ -509,7 +511,7 @@ func TestForkPreMigration(t *testing.T) {
|
||||
require.NoError(t, sm.Stop(context.Background()))
|
||||
}()
|
||||
|
||||
inv := filcns.NewActorRegistry()
|
||||
inv := consensus.NewActorRegistry()
|
||||
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
|
||||
inv.Register(actorstypes.Version0, nil, registry)
|
||||
|
||||
@@ -534,3 +536,70 @@ func TestForkPreMigration(t *testing.T) {
|
||||
// to this channel.
|
||||
require.Equal(t, 6, len(counter))
|
||||
}
|
||||
|
||||
func TestDisablePreMigration(t *testing.T) {
|
||||
logging.SetAllLoggers(logging.LevelInfo)
|
||||
|
||||
cg, err := gen.NewGenerator()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = os.Setenv(EnvDisablePreMigrations, "1")
|
||||
require.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err := os.Unsetenv(EnvDisablePreMigrations)
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
|
||||
counter := make(chan struct{}, 10)
|
||||
|
||||
sm, err := NewStateManager(
|
||||
cg.ChainStore(),
|
||||
consensus.NewTipSetExecutor(filcns.RewardFunc),
|
||||
cg.StateManager().VMSys(),
|
||||
UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(_ context.Context, _ *StateManager, _ MigrationCache, _ ExecMonitor,
|
||||
root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) {
|
||||
|
||||
counter <- struct{}{}
|
||||
|
||||
return root, nil
|
||||
},
|
||||
PreMigrations: []PreMigration{{
|
||||
StartWithin: 20,
|
||||
PreMigration: func(ctx context.Context, _ *StateManager, _ MigrationCache,
|
||||
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
|
||||
panic("should be skipped")
|
||||
},
|
||||
}}},
|
||||
},
|
||||
cg.BeaconSchedule(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, sm.Start(context.Background()))
|
||||
defer func() {
|
||||
require.NoError(t, sm.Stop(context.Background()))
|
||||
}()
|
||||
|
||||
inv := consensus.NewActorRegistry()
|
||||
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
|
||||
inv.Register(actorstypes.Version0, nil, registry)
|
||||
|
||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
|
||||
nvm, err := vm.NewLegacyVM(ctx, vmopt)
|
||||
require.NoError(t, err)
|
||||
nvm.SetInvoker(inv)
|
||||
return nvm, nil
|
||||
})
|
||||
|
||||
cg.SetStateManager(sm)
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err := cg.NextTipSet()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
require.Equal(t, 1, len(counter))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ package store
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
blocks "github.com/ipfs/go-libipfs/blocks"
|
||||
@@ -12,6 +15,8 @@ import (
|
||||
carv2 "github.com/ipld/go-car/v2"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.uber.org/atomic"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -132,6 +137,423 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
||||
return root, nil
|
||||
}
|
||||
|
||||
type walkSchedTaskType int
|
||||
|
||||
const (
|
||||
finishTask walkSchedTaskType = -1
|
||||
blockTask walkSchedTaskType = iota
|
||||
messageTask
|
||||
receiptTask
|
||||
stateTask
|
||||
dagTask
|
||||
)
|
||||
|
||||
func (t walkSchedTaskType) String() string {
|
||||
switch t {
|
||||
case finishTask:
|
||||
return "finish"
|
||||
case blockTask:
|
||||
return "block"
|
||||
case messageTask:
|
||||
return "message"
|
||||
case receiptTask:
|
||||
return "receipt"
|
||||
case stateTask:
|
||||
return "state"
|
||||
case dagTask:
|
||||
return "dag"
|
||||
}
|
||||
panic(fmt.Sprintf("unknow task %d", t))
|
||||
}
|
||||
|
||||
type walkTask struct {
|
||||
c cid.Cid
|
||||
taskType walkSchedTaskType
|
||||
}
|
||||
|
||||
// an ever growing FIFO
|
||||
type taskFifo struct {
|
||||
in chan walkTask
|
||||
out chan walkTask
|
||||
fifo []walkTask
|
||||
}
|
||||
|
||||
type taskResult struct {
|
||||
c cid.Cid
|
||||
b blocks.Block
|
||||
}
|
||||
|
||||
func newTaskFifo(bufferLen int) *taskFifo {
|
||||
f := taskFifo{
|
||||
in: make(chan walkTask, bufferLen),
|
||||
out: make(chan walkTask, bufferLen),
|
||||
fifo: make([]walkTask, 0),
|
||||
}
|
||||
|
||||
go f.run()
|
||||
|
||||
return &f
|
||||
}
|
||||
|
||||
func (f *taskFifo) Close() error {
|
||||
close(f.in)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *taskFifo) run() {
|
||||
for {
|
||||
if len(f.fifo) > 0 {
|
||||
// we have items in slice
|
||||
// try to put next out or read something in.
|
||||
// blocks if nothing works.
|
||||
next := f.fifo[0]
|
||||
select {
|
||||
case f.out <- next:
|
||||
f.fifo = f.fifo[1:]
|
||||
case elem, ok := <-f.in:
|
||||
if !ok {
|
||||
// drain and close out.
|
||||
for _, elem := range f.fifo {
|
||||
f.out <- elem
|
||||
}
|
||||
close(f.out)
|
||||
return
|
||||
}
|
||||
f.fifo = append(f.fifo, elem)
|
||||
}
|
||||
} else {
|
||||
// no elements in fifo to put out.
|
||||
// Try to read in and block.
|
||||
// When done, try to put out or add to fifo.
|
||||
select {
|
||||
case elem, ok := <-f.in:
|
||||
if !ok {
|
||||
close(f.out)
|
||||
return
|
||||
}
|
||||
select {
|
||||
case f.out <- elem:
|
||||
default:
|
||||
f.fifo = append(f.fifo, elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type walkSchedulerConfig struct {
|
||||
numWorkers int
|
||||
|
||||
head *types.TipSet // Tipset to start walking from.
|
||||
tail *types.TipSet // Tipset to end at.
|
||||
includeMessages bool
|
||||
includeReceipts bool
|
||||
includeState bool
|
||||
}
|
||||
|
||||
type walkScheduler struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
store bstore.Blockstore
|
||||
cfg walkSchedulerConfig
|
||||
writer io.Writer
|
||||
|
||||
workerTasks *taskFifo
|
||||
totalTasks atomic.Int64
|
||||
results chan taskResult
|
||||
writeErrorChan chan error
|
||||
|
||||
// tracks number of inflight tasks
|
||||
//taskWg sync.WaitGroup
|
||||
// launches workers and collects errors if any occur
|
||||
workers *errgroup.Group
|
||||
// set of CIDs already exported
|
||||
seen sync.Map
|
||||
}
|
||||
|
||||
func newWalkScheduler(ctx context.Context, store bstore.Blockstore, cfg walkSchedulerConfig, w io.Writer) (*walkScheduler, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
workers, ctx := errgroup.WithContext(ctx)
|
||||
s := &walkScheduler{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
store: store,
|
||||
cfg: cfg,
|
||||
writer: w,
|
||||
results: make(chan taskResult, cfg.numWorkers*64),
|
||||
workerTasks: newTaskFifo(cfg.numWorkers * 64),
|
||||
writeErrorChan: make(chan error, 1),
|
||||
workers: workers,
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(s.writeErrorChan)
|
||||
for r := range s.results {
|
||||
// Write
|
||||
if err := carutil.LdWrite(s.writer, r.c.Bytes(), r.b.RawData()); err != nil {
|
||||
// abort operations
|
||||
cancel()
|
||||
s.writeErrorChan <- err
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// workers
|
||||
for i := 0; i < cfg.numWorkers; i++ {
|
||||
f := func(n int) func() error {
|
||||
return func() error {
|
||||
return s.workerFunc(n)
|
||||
}
|
||||
}(i)
|
||||
s.workers.Go(f)
|
||||
}
|
||||
|
||||
s.totalTasks.Add(int64(len(cfg.head.Blocks())))
|
||||
for _, b := range cfg.head.Blocks() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Errorw("context done while sending root tasks", ctx.Err())
|
||||
cancel() // kill workers
|
||||
return nil, ctx.Err()
|
||||
case s.workerTasks.in <- walkTask{
|
||||
c: b.Cid(),
|
||||
taskType: blockTask,
|
||||
}:
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *walkScheduler) Wait() error {
|
||||
err := s.workers.Wait()
|
||||
// all workers done. One would have reached genesis and notified the
|
||||
// rest to exit. Yet, there might be some pending tasks in the queue,
|
||||
// so we need to run a "single worker".
|
||||
if err != nil {
|
||||
log.Errorw("export workers finished with error", "error", err)
|
||||
}
|
||||
|
||||
for {
|
||||
if n := s.totalTasks.Load(); n == 0 {
|
||||
break // finally fully done
|
||||
}
|
||||
select {
|
||||
case task := <-s.workerTasks.out:
|
||||
s.totalTasks.Add(-1)
|
||||
if err != nil {
|
||||
continue // just drain if errors happened.
|
||||
}
|
||||
err = s.processTask(task, 0)
|
||||
}
|
||||
}
|
||||
close(s.results)
|
||||
errWrite := <-s.writeErrorChan
|
||||
if errWrite != nil {
|
||||
log.Errorw("error writing to CAR file", "error", err)
|
||||
return errWrite
|
||||
}
|
||||
s.workerTasks.Close() //nolint:errcheck
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *walkScheduler) enqueueIfNew(task walkTask) {
|
||||
if task.c.Prefix().MhType == mh.IDENTITY {
|
||||
//log.Infow("ignored", "cid", todo.c.String())
|
||||
return
|
||||
}
|
||||
if task.c.Prefix().Codec != cid.Raw && task.c.Prefix().Codec != cid.DagCBOR {
|
||||
//log.Infow("ignored", "cid", todo.c.String())
|
||||
return
|
||||
}
|
||||
if _, loaded := s.seen.LoadOrStore(task.c, struct{}{}); loaded {
|
||||
// we already had it on the map
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugw("enqueue", "type", task.taskType.String(), "cid", task.c.String())
|
||||
s.totalTasks.Add(1)
|
||||
s.workerTasks.in <- task
|
||||
}
|
||||
|
||||
func (s *walkScheduler) sendFinish(workerN int) error {
|
||||
log.Infow("worker finished work", "worker", workerN)
|
||||
s.totalTasks.Add(1)
|
||||
s.workerTasks.in <- walkTask{
|
||||
taskType: finishTask,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *walkScheduler) workerFunc(workerN int) error {
|
||||
log.Infow("starting worker", "worker", workerN)
|
||||
for t := range s.workerTasks.out {
|
||||
s.totalTasks.Add(-1)
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return s.ctx.Err()
|
||||
default:
|
||||
// A worker reached genesis, so we wind down and let others do
|
||||
// the same. Exit.
|
||||
if t.taskType == finishTask {
|
||||
return s.sendFinish(workerN)
|
||||
}
|
||||
}
|
||||
|
||||
err := s.processTask(t, workerN)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *walkScheduler) processTask(t walkTask, workerN int) error {
|
||||
if t.taskType == finishTask {
|
||||
return nil
|
||||
}
|
||||
|
||||
blk, err := s.store.Get(s.ctx, t.c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing object to car, bs.Get: %w", err)
|
||||
}
|
||||
|
||||
s.results <- taskResult{
|
||||
c: t.c,
|
||||
b: blk,
|
||||
}
|
||||
|
||||
// extract relevant dags to walk from the block
|
||||
if t.taskType == blockTask {
|
||||
blk := t.c
|
||||
data, err := s.store.Get(s.ctx, blk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var b types.BlockHeader
|
||||
if err := b.UnmarshalCBOR(bytes.NewBuffer(data.RawData())); err != nil {
|
||||
return xerrors.Errorf("unmarshalling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
if b.Height%1_000 == 0 {
|
||||
log.Infow("block export", "height", b.Height)
|
||||
}
|
||||
if b.Height == 0 {
|
||||
log.Info("exporting genesis block")
|
||||
for i := range b.Parents {
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.Parents[i],
|
||||
taskType: dagTask,
|
||||
})
|
||||
}
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.ParentStateRoot,
|
||||
taskType: stateTask,
|
||||
})
|
||||
|
||||
return s.sendFinish(workerN)
|
||||
}
|
||||
// enqueue block parents
|
||||
for i := range b.Parents {
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.Parents[i],
|
||||
taskType: blockTask,
|
||||
})
|
||||
}
|
||||
if s.cfg.tail.Height() >= b.Height {
|
||||
log.Debugw("tail reached: only blocks will be exported from now until genesis", "cid", blk.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.cfg.includeMessages {
|
||||
// enqueue block messages
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.Messages,
|
||||
taskType: messageTask,
|
||||
})
|
||||
}
|
||||
if s.cfg.includeReceipts {
|
||||
// enqueue block receipts
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.ParentMessageReceipts,
|
||||
taskType: receiptTask,
|
||||
})
|
||||
}
|
||||
if s.cfg.includeState {
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: b.ParentStateRoot,
|
||||
taskType: stateTask,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Not a chain-block: we scan for CIDs in the raw block-data
|
||||
return cbg.ScanForLinks(bytes.NewReader(blk.RawData()), func(c cid.Cid) {
|
||||
if t.c.Prefix().Codec != cid.DagCBOR || t.c.Prefix().MhType == mh.IDENTITY {
|
||||
return
|
||||
}
|
||||
|
||||
s.enqueueIfNew(walkTask{
|
||||
c: c,
|
||||
taskType: dagTask,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ExportRange(
|
||||
ctx context.Context,
|
||||
w io.Writer,
|
||||
head, tail *types.TipSet,
|
||||
messages, receipts, stateroots bool,
|
||||
workers int) error {
|
||||
|
||||
h := &car.CarHeader{
|
||||
Roots: head.Cids(),
|
||||
Version: 1,
|
||||
}
|
||||
|
||||
if err := car.WriteHeader(h, w); err != nil {
|
||||
return xerrors.Errorf("failed to write car header: %s", err)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
log.Infow("walking snapshot range",
|
||||
"head", head.Key(),
|
||||
"tail", tail.Key(),
|
||||
"messages", messages,
|
||||
"receipts", receipts,
|
||||
"stateroots",
|
||||
stateroots,
|
||||
"workers", workers)
|
||||
|
||||
cfg := walkSchedulerConfig{
|
||||
numWorkers: workers,
|
||||
head: head,
|
||||
tail: tail,
|
||||
includeMessages: messages,
|
||||
includeState: stateroots,
|
||||
includeReceipts: receipts,
|
||||
}
|
||||
|
||||
pw, err := newWalkScheduler(ctx, cs.UnionStore(), cfg, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait until all workers are done.
|
||||
err = pw.Wait()
|
||||
if err != nil {
|
||||
log.Errorw("walker scheduler", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infow("walking snapshot range complete", "duration", time.Since(start), "success", err == nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs, skipMsgReceipts bool, cb func(cid.Cid) error) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -212,7 +213,7 @@ func TestChainExportImportFull(t *testing.T) {
|
||||
t.Fatal("imported chain differed from exported chain")
|
||||
}
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule())
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), nil, filcns.DefaultUpgradeSchedule(), cg.BeaconSchedule())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub
|
||||
}()
|
||||
|
||||
var what string
|
||||
res, what = bv.consensus.ValidateBlockPubsub(ctx, pid == bv.self, msg)
|
||||
res, what = consensus.ValidateBlockPubsub(ctx, bv.consensus, pid == bv.self, msg)
|
||||
if res == pubsub.ValidationAccept {
|
||||
// it's a good block! make sure we've only seen it once
|
||||
if count := bv.recvBlocks.add(msg.ValidatorData.(*types.BlockMsg).Cid()); count > 0 {
|
||||
|
||||
@@ -207,6 +207,10 @@ func (m *Message) ValidForBlockInclusion(minGas int64, version network.Version)
|
||||
return xerrors.Errorf("'GasLimit' field cannot be greater than a block's gas limit (%d > %d)", m.GasLimit, build.BlockGasLimit)
|
||||
}
|
||||
|
||||
if m.GasLimit <= 0 {
|
||||
return xerrors.Errorf("'GasLimit' field %d must be positive", m.GasLimit)
|
||||
}
|
||||
|
||||
// since prices might vary with time, this is technically semantic validation
|
||||
if m.GasLimit < minGas {
|
||||
return xerrors.Errorf("'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d", m.GasLimit, minGas)
|
||||
|
||||
+10
-1
@@ -61,6 +61,10 @@ func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Comma
|
||||
return xerrors.Errorf("expanding file path: %w", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(fpath); !os.IsNotExist(err) {
|
||||
return xerrors.Errorf("backup file %s already exists. Overwriting it will corrupt the file, please specify another file name", fpath)
|
||||
}
|
||||
|
||||
out, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening backup file %s: %w", fpath, err)
|
||||
@@ -87,7 +91,12 @@ func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Comma
|
||||
}
|
||||
defer closer()
|
||||
|
||||
err = api.CreateBackup(ReqContext(cctx), cctx.Args().First())
|
||||
backupPath := cctx.Args().First()
|
||||
if _, err := os.Stat(backupPath); !os.IsNotExist(err) {
|
||||
return xerrors.Errorf("backup file %s already exists. Overwriting it will corrupt the file, please specify another file name", backupPath)
|
||||
}
|
||||
|
||||
err = api.CreateBackup(ReqContext(cctx), backupPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+133
-8
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -37,7 +38,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -56,6 +57,7 @@ var ChainCmd = &cli.Command{
|
||||
ChainGetCmd,
|
||||
ChainBisectCmd,
|
||||
ChainExportCmd,
|
||||
ChainExportRangeCmd,
|
||||
SlashConsensusFault,
|
||||
ChainGasPriceCmd,
|
||||
ChainInspectUsage,
|
||||
@@ -112,8 +114,8 @@ var ChainGetBlock = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass cid of block to print")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
bcid, err := cid.Decode(cctx.Args().First())
|
||||
@@ -198,6 +200,10 @@ var ChainReadObjCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
c, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse cid input: %s", err)
|
||||
@@ -233,6 +239,10 @@ var ChainDeleteObjCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
c, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse cid input: %s", err)
|
||||
@@ -276,6 +286,10 @@ var ChainStatObjCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
obj, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse cid input: %s", err)
|
||||
@@ -308,8 +322,8 @@ var ChainGetMsgCmd = &cli.Command{
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass a cid of a message to get")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -374,6 +388,10 @@ var ChainSetHeadCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
var ts *types.TipSet
|
||||
|
||||
if cctx.Bool("genesis") {
|
||||
@@ -493,7 +511,7 @@ var ChainInspectUsage = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
mm := filcns.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map
|
||||
mm := consensus.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map
|
||||
|
||||
byMethod[mm.Name] += m.Message.GasLimit
|
||||
byMethodC[mm.Name]++
|
||||
@@ -734,6 +752,10 @@ var ChainGetCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
p := path.Clean(cctx.Args().First())
|
||||
if strings.HasPrefix(p, "/pstate") {
|
||||
p = p[len("/pstate"):]
|
||||
@@ -1071,8 +1093,8 @@ var ChainExportCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify filename to export chain to")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
rsrs := abi.ChainEpoch(cctx.Int64("recent-stateroots"))
|
||||
@@ -1125,6 +1147,109 @@ var ChainExportCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var ChainExportRangeCmd = &cli.Command{
|
||||
Name: "export-range",
|
||||
Usage: "export chain to a car file",
|
||||
ArgsUsage: "",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "head",
|
||||
Usage: "specify tipset to start the export from (higher epoch)",
|
||||
Value: "@head",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tail",
|
||||
Usage: "specify tipset to end the export at (lower epoch)",
|
||||
Value: "@tail",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "messages",
|
||||
Usage: "specify if messages should be include",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "receipts",
|
||||
Usage: "specify if receipts should be include",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "stateroots",
|
||||
Usage: "specify if stateroots should be include",
|
||||
Value: false,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "workers",
|
||||
Usage: "specify the number of workers",
|
||||
Value: 1,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "write-buffer",
|
||||
Usage: "specify write buffer size",
|
||||
Value: 1 << 20,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "internal",
|
||||
Usage: "write the file locally to disk",
|
||||
Value: true,
|
||||
Hidden: true, // currently, non-internal export is not implemented.
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPIV1(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
var head, tail *types.TipSet
|
||||
headstr := cctx.String("head")
|
||||
if headstr == "@head" {
|
||||
head, err = api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
head, err = ParseTipSetRef(ctx, api, headstr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing head: %w", err)
|
||||
}
|
||||
}
|
||||
tailstr := cctx.String("tail")
|
||||
if tailstr == "@tail" {
|
||||
tail, err = api.ChainGetGenesis(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
tail, err = ParseTipSetRef(ctx, api, tailstr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing tail: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if head.Height() < tail.Height() {
|
||||
return errors.New("Height of --head tipset must be greater or equal to the height of the --tail tipset")
|
||||
}
|
||||
|
||||
if !cctx.Bool("internal") {
|
||||
return errors.New("Non-internal exports are not implemented")
|
||||
}
|
||||
|
||||
err = api.ChainExportRangeInternal(ctx, head.Key(), tail.Key(), lapi.ChainExportConfig{
|
||||
WriteBufferSize: cctx.Int("write-buffer"),
|
||||
NumWorkers: cctx.Int("workers"),
|
||||
IncludeMessages: cctx.Bool("messages"),
|
||||
IncludeReceipts: cctx.Bool("receipts"),
|
||||
IncludeStateRoots: cctx.Bool("stateroots"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var SlashConsensusFault = &cli.Command{
|
||||
Name: "slash-consensus",
|
||||
Usage: "Report consensus fault",
|
||||
|
||||
+20
-48
@@ -166,8 +166,8 @@ var clientDropCmd = &cli.Command{
|
||||
Usage: "Remove import",
|
||||
ArgsUsage: "[import ID...]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return xerrors.Errorf("no imports specified")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -996,9 +996,8 @@ var clientFindCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
fmt.Println("Usage: find [CID]")
|
||||
return nil
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
file, err := cid.Parse(cctx.Args().First())
|
||||
@@ -1063,8 +1062,7 @@ var clientQueryRetrievalAskCmd = &cli.Command{
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
if cctx.NArg() != 2 {
|
||||
afmt.Println("Usage: retrieval-ask [minerAddress] [data CID]")
|
||||
return nil
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -1120,11 +1118,6 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
Aliases: []string{"v"},
|
||||
Usage: "print verbose deal details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
Usage: "show failed/failing deals",
|
||||
@@ -1140,10 +1133,6 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1639,8 +1628,7 @@ var clientQueryAskCmd = &cli.Command{
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
if cctx.NArg() != 1 {
|
||||
afmt.Println("Usage: query-ask [minerAddress]")
|
||||
return nil
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -1712,11 +1700,6 @@ var clientListDeals = &cli.Command{
|
||||
Aliases: []string{"v"},
|
||||
Usage: "print verbose deal details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
Usage: "show failed/failing deals",
|
||||
@@ -1727,10 +1710,6 @@ var clientListDeals = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1944,8 +1923,8 @@ var clientGetDealCmd = &cli.Command{
|
||||
Usage: "Print detailed deal information",
|
||||
ArgsUsage: "[proposalCID]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -2058,8 +2037,8 @@ var clientStat = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() || cctx.NArg() != 1 {
|
||||
return fmt.Errorf("must specify cid of data")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
dataCid, err := cid.Parse(cctx.Args().First())
|
||||
@@ -2080,8 +2059,9 @@ var clientStat = &cli.Command{
|
||||
}
|
||||
|
||||
var clientRestartTransfer = &cli.Command{
|
||||
Name: "restart-transfer",
|
||||
Usage: "Force restart a stalled data transfer",
|
||||
Name: "restart-transfer",
|
||||
Usage: "Force restart a stalled data transfer",
|
||||
ArgsUsage: "[transferID]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "peerid",
|
||||
@@ -2094,8 +2074,8 @@ var clientRestartTransfer = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -2140,8 +2120,9 @@ var clientRestartTransfer = &cli.Command{
|
||||
}
|
||||
|
||||
var clientCancelTransfer = &cli.Command{
|
||||
Name: "cancel-transfer",
|
||||
Usage: "Force cancel a data transfer",
|
||||
Name: "cancel-transfer",
|
||||
Usage: "Force cancel a data transfer",
|
||||
ArgsUsage: "[transferID]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "peerid",
|
||||
@@ -2159,8 +2140,8 @@ var clientCancelTransfer = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return cli.ShowCommandHelp(cctx, cctx.Command.Name)
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -2242,11 +2223,6 @@ var clientListTransfers = &cli.Command{
|
||||
Aliases: []string{"v"},
|
||||
Usage: "print verbose transfer details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "completed",
|
||||
Usage: "show completed data transfers",
|
||||
@@ -2261,10 +2237,6 @@ var clientListTransfers = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-2
@@ -58,8 +58,7 @@ var disputerMsgCmd = &cli.Command{
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 3 {
|
||||
fmt.Println("Usage: dispute [minerAddress index postIndex]")
|
||||
return nil
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
+180
@@ -43,7 +43,9 @@ var filplusCmd = &cli.Command{
|
||||
filplusCheckNotaryCmd,
|
||||
filplusSignRemoveDataCapProposal,
|
||||
filplusListAllocationsCmd,
|
||||
filplusListClaimsCmd,
|
||||
filplusRemoveExpiredAllocationsCmd,
|
||||
filplusRemoveExpiredClaimsCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -310,6 +312,91 @@ var filplusListAllocationsCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var filplusListClaimsCmd = &cli.Command{
|
||||
Name: "list-claims",
|
||||
Usage: "List claims made by provider",
|
||||
ArgsUsage: "providerAddress",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "expired",
|
||||
Usage: "list only expired claims",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
providerAddr, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
providerIdAddr, err := api.StateLookupID(ctx, providerAddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api)))
|
||||
|
||||
verifregActor, err := api.StateGetActor(ctx, verifreg.Address, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
verifregState, err := verifreg.Load(store, verifregActor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ts, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
claimsMap, err := verifregState.GetClaims(providerIdAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tw := tablewriter.New(
|
||||
tablewriter.Col("ID"),
|
||||
tablewriter.Col("Provider"),
|
||||
tablewriter.Col("Client"),
|
||||
tablewriter.Col("Data"),
|
||||
tablewriter.Col("Size"),
|
||||
tablewriter.Col("TermMin"),
|
||||
tablewriter.Col("TermMax"),
|
||||
tablewriter.Col("TermStart"),
|
||||
tablewriter.Col("Sector"),
|
||||
)
|
||||
|
||||
for claimId, claim := range claimsMap {
|
||||
if ts.Height() > claim.TermMax || !cctx.IsSet("expired") {
|
||||
tw.Write(map[string]interface{}{
|
||||
"ID": claimId,
|
||||
"Provider": claim.Provider,
|
||||
"Client": claim.Client,
|
||||
"Data": claim.Data,
|
||||
"Size": claim.Size,
|
||||
"TermMin": claim.TermMin,
|
||||
"TermMax": claim.TermMax,
|
||||
"TermStart": claim.TermStart,
|
||||
"Sector": claim.Sector,
|
||||
})
|
||||
}
|
||||
}
|
||||
return tw.Flush(os.Stdout)
|
||||
},
|
||||
}
|
||||
|
||||
var filplusRemoveExpiredAllocationsCmd = &cli.Command{
|
||||
Name: "remove-expired-allocations",
|
||||
Usage: "remove expired allocations (if no allocations are specified all eligible allocations are removed)",
|
||||
@@ -403,6 +490,99 @@ var filplusRemoveExpiredAllocationsCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var filplusRemoveExpiredClaimsCmd = &cli.Command{
|
||||
Name: "remove-expired-claims",
|
||||
Usage: "remove expired claims (if no claims are specified all eligible claims are removed)",
|
||||
ArgsUsage: "providerAddress Optional[...claimId]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "optionally specify the account to send the message from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() < 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
args := cctx.Args().Slice()
|
||||
|
||||
providerAddr, err := address.NewFromString(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
providerIdAddr, err := api.StateLookupID(ctx, providerAddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
providerId, err := address.IDFromAddress(providerIdAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fromAddr := providerIdAddr
|
||||
if from := cctx.String("from"); from != "" {
|
||||
addr, err := address.NewFromString(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fromAddr = addr
|
||||
}
|
||||
|
||||
claimIDs := make([]verifregtypes9.ClaimId, len(args)-1)
|
||||
for i, claimStr := range args[1:] {
|
||||
id, err := strconv.ParseUint(claimStr, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
claimIDs[i] = verifregtypes9.ClaimId(id)
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&verifregtypes9.RemoveExpiredClaimsParams{
|
||||
Provider: abi.ActorID(providerId),
|
||||
ClaimIds: claimIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: verifreg.Address,
|
||||
From: fromAddr,
|
||||
Method: verifreg.Methods.RemoveExpiredClaims,
|
||||
Params: params,
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("message sent, now waiting on cid: %s\n", smsg.Cid())
|
||||
|
||||
mwait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mwait.Receipt.ExitCode.IsError() {
|
||||
return fmt.Errorf("failed to remove expired allocations: %d", mwait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var filplusCheckClientCmd = &cli.Command{
|
||||
Name: "check-client-datacap",
|
||||
Usage: "check verified client remaining bytes",
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -325,7 +325,7 @@ var msigInspectCmd = &cli.Command{
|
||||
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%s(%d)\t%s\n", txid, "pending", len(tx.Approved), target, types.FIL(tx.Value), "new account, unknown method", tx.Method, paramStr)
|
||||
}
|
||||
} else {
|
||||
method := filcns.NewActorRegistry().Methods[targAct.Code][tx.Method] // TODO: use remote map
|
||||
method := consensus.NewActorRegistry().Methods[targAct.Code][tx.Method] // TODO: use remote map
|
||||
|
||||
if decParams && tx.Method != 0 {
|
||||
ptyp := reflect.New(method.Params.Elem()).Interface().(cbg.CBORUnmarshaler)
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ var FetchParamCmd = &cli.Command{
|
||||
Usage: "Fetch proving parameters",
|
||||
ArgsUsage: "[sectorSize]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return xerrors.Errorf("must pass sector size to fetch params for (specify as \"32GiB\", for instance)")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
sectorSizeInt, err := units.RAMInBytes(cctx.Args().First())
|
||||
if err != nil {
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -88,7 +88,7 @@ func (s *ServicesImpl) DecodeTypedParamsFromJSON(ctx context.Context, to address
|
||||
return nil, err
|
||||
}
|
||||
|
||||
methodMeta, found := filcns.NewActorRegistry().Methods[act.Code][method] // TODO: use remote map
|
||||
methodMeta, found := consensus.NewActorRegistry().Methods[act.Code][method] // TODO: use remote map
|
||||
if !found {
|
||||
return nil, fmt.Errorf("method %d not found on actor %s", method, act.Code)
|
||||
}
|
||||
|
||||
+41
-34
@@ -41,7 +41,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -99,8 +99,8 @@ var StateMinerProvingDeadlineCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify miner to get information for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -142,8 +142,8 @@ var StateMinerInfo = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify miner to get information for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -252,10 +252,16 @@ func ParseTipSetString(ts string) ([]cid.Cid, error) {
|
||||
return cids, nil
|
||||
}
|
||||
|
||||
type TipSetResolver interface {
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||
}
|
||||
|
||||
// LoadTipSet gets the tipset from the context, or the head from the API.
|
||||
//
|
||||
// It always gets the head from the API so commands use a consistent tipset even if time pases.
|
||||
func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*types.TipSet, error) {
|
||||
func LoadTipSet(ctx context.Context, cctx *cli.Context, api TipSetResolver) (*types.TipSet, error) {
|
||||
tss := cctx.String("tipset")
|
||||
if tss == "" {
|
||||
return api.ChainHead(ctx)
|
||||
@@ -264,7 +270,7 @@ func LoadTipSet(ctx context.Context, cctx *cli.Context, api v0api.FullNode) (*ty
|
||||
return ParseTipSetRef(ctx, api, tss)
|
||||
}
|
||||
|
||||
func ParseTipSetRef(ctx context.Context, api v0api.FullNode, tss string) (*types.TipSet, error) {
|
||||
func ParseTipSetRef(ctx context.Context, api TipSetResolver, tss string) (*types.TipSet, error) {
|
||||
if tss[0] == '@' {
|
||||
if tss == "@head" {
|
||||
return api.ChainHead(ctx)
|
||||
@@ -391,8 +397,8 @@ var StateSectorsCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify miner to list sectors for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -431,8 +437,8 @@ var StateActiveSectorsCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify miner to list sectors for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -463,8 +469,8 @@ var StateExecTraceCmd = &cli.Command{
|
||||
Usage: "Get the execution trace of a given message",
|
||||
ArgsUsage: "<messageCid>",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return ShowHelp(cctx, fmt.Errorf("must pass message cid"))
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
mcid, err := cid.Decode(cctx.Args().First())
|
||||
@@ -606,8 +612,8 @@ var StateGetDealSetCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify deal ID")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
dealid, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
|
||||
@@ -750,8 +756,8 @@ var StateGetActorCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass address of actor to get")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -804,8 +810,8 @@ var StateLookupIDCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass address of actor to get")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -848,8 +854,8 @@ var StateSectorSizeCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass miner's address")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -885,8 +891,8 @@ var StateReadStateCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass address of actor to get")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -1411,7 +1417,7 @@ func codeStr(c cid.Cid) string {
|
||||
}
|
||||
|
||||
func getMethod(code cid.Cid, method abi.MethodNum) string {
|
||||
return filcns.NewActorRegistry().Methods[code][method].Name // todo: use remote
|
||||
return consensus.NewActorRegistry().Methods[code][method].Name // todo: use remote
|
||||
}
|
||||
|
||||
func toFil(f types.BigInt) types.FIL {
|
||||
@@ -1427,7 +1433,7 @@ func isVerySlow(t time.Duration) bool {
|
||||
}
|
||||
|
||||
func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) {
|
||||
p, err := stmgr.GetParamType(filcns.NewActorRegistry(), code, method) // todo use api for correct actor registry
|
||||
p, err := stmgr.GetParamType(consensus.NewActorRegistry(), code, method) // todo use api for correct actor registry
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1441,7 +1447,7 @@ func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro
|
||||
}
|
||||
|
||||
func JsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) {
|
||||
methodMeta, found := filcns.NewActorRegistry().Methods[code][method] // TODO: use remote
|
||||
methodMeta, found := consensus.NewActorRegistry().Methods[code][method] // TODO: use remote
|
||||
if !found {
|
||||
return "", fmt.Errorf("method %d not found on actor %s", method, code)
|
||||
}
|
||||
@@ -1467,8 +1473,8 @@ var StateWaitMsgCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify message cid to wait for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -1504,8 +1510,8 @@ var StateSearchMsgCmd = &cli.Command{
|
||||
Usage: "Search to see whether a message has appeared on chain",
|
||||
ArgsUsage: "[messageCid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify message cid to search for")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -1836,11 +1842,12 @@ var StateMarketCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var stateMarketBalanceCmd = &cli.Command{
|
||||
Name: "balance",
|
||||
Usage: "Get the market balance (locked and escrowed) for a given account",
|
||||
Name: "balance",
|
||||
Usage: "Get the market balance (locked and escrowed) for a given account",
|
||||
ArgsUsage: "[address]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return ShowHelp(cctx, fmt.Errorf("must specify address to print market balance for"))
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
|
||||
+12
-12
@@ -251,8 +251,8 @@ var walletSetDefault = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass address to set as default")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -279,8 +279,8 @@ var walletExport = &cli.Command{
|
||||
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify key to export")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -414,8 +414,8 @@ var walletSign = &cli.Command{
|
||||
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
if !cctx.Args().Present() || cctx.NArg() != 2 {
|
||||
return fmt.Errorf("must specify signing address and message to sign")
|
||||
if cctx.NArg() != 2 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -457,8 +457,8 @@ var walletVerify = &cli.Command{
|
||||
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
if !cctx.Args().Present() || cctx.NArg() != 3 {
|
||||
return fmt.Errorf("must specify signing address, message, and signature to verify")
|
||||
if cctx.NArg() != 3 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -509,8 +509,8 @@ var walletDelete = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() || cctx.NArg() != 1 {
|
||||
return fmt.Errorf("must specify address to delete")
|
||||
if cctx.NArg() != 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
@@ -701,8 +701,8 @@ var walletMarketAdd = &cli.Command{
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
// Get amount param
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass amount to add")
|
||||
if cctx.NArg() < 1 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
f, err := types.ParseFIL(cctx.Args().First())
|
||||
if err != nil {
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
badgerbs "github.com/filecoin-project/lotus/blockstore/badger"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -228,7 +229,7 @@ var importBenchCmd = &cli.Command{
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
// TODO: We need to supply the actual beacon after v14
|
||||
stm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
stm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+15
-18
@@ -55,9 +55,10 @@ var actorCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var actorSetAddrsCmd = &cli.Command{
|
||||
Name: "set-addresses",
|
||||
Aliases: []string{"set-addrs"},
|
||||
Usage: "set addresses that your miner can be publicly dialed on",
|
||||
Name: "set-addresses",
|
||||
Aliases: []string{"set-addrs"},
|
||||
Usage: "set addresses that your miner can be publicly dialed on",
|
||||
ArgsUsage: "<multiaddrs>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
@@ -170,8 +171,9 @@ var actorSetAddrsCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var actorSetPeeridCmd = &cli.Command{
|
||||
Name: "set-peer-id",
|
||||
Usage: "set the peer id of your miner",
|
||||
Name: "set-peer-id",
|
||||
Usage: "set the peer id of your miner",
|
||||
ArgsUsage: "<peer id>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "gas-limit",
|
||||
@@ -194,6 +196,10 @@ var actorSetPeeridCmd = &cli.Command{
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
pid, err := peer.Decode(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse input as a peerId: %w", err)
|
||||
@@ -433,17 +439,8 @@ var actorControlList = &cli.Command{
|
||||
&cli.BoolFlag{
|
||||
Name: "verbose",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -729,15 +726,15 @@ var actorSetOwnerCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 2 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
fmt.Println("Pass --really-do-it to actually execute this action")
|
||||
return nil
|
||||
}
|
||||
|
||||
if cctx.NArg() != 2 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -34,8 +34,8 @@ func TestWorkerKeyChange(t *testing.T) {
|
||||
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
blocktime := 1 * time.Millisecond
|
||||
client1, client2, miner, ens := kit.EnsembleTwoOne(t, kit.MockProofs())
|
||||
blocktime := 5 * time.Millisecond
|
||||
client1, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs())
|
||||
ens.InterconnectAll().BeginMining(blocktime)
|
||||
|
||||
output := bytes.NewBuffer(nil)
|
||||
@@ -96,7 +96,4 @@ func TestWorkerKeyChange(t *testing.T) {
|
||||
// Wait for finality (worker key switch).
|
||||
targetHeight := head.Height() + policy.ChainFinality
|
||||
client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
|
||||
|
||||
// Make sure the other node can catch up.
|
||||
client2.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestMinerAllInfo(t *testing.T) {
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
client, miner, ens := kit.EnsembleMinimal(t)
|
||||
ens.InterconnectAll().BeginMining(time.Second)
|
||||
ens.InterconnectAll().BeginMiningMustPost(5 * time.Millisecond)
|
||||
|
||||
run := func(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
|
||||
@@ -31,18 +31,7 @@ var dagstoreCmd = &cli.Command{
|
||||
var dagstoreListShardsCmd = &cli.Command{
|
||||
Name: "list-shards",
|
||||
Usage: "List all shards known to the dagstore, with their current status",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -64,18 +53,7 @@ var dagstoreRegisterShardCmd = &cli.Command{
|
||||
Name: "register-shard",
|
||||
ArgsUsage: "[key]",
|
||||
Usage: "Register a shard",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
@@ -103,18 +81,7 @@ var dagstoreInitializeShardCmd = &cli.Command{
|
||||
Name: "initialize-shard",
|
||||
ArgsUsage: "[key]",
|
||||
Usage: "Initialize the specified shard",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
@@ -135,18 +102,7 @@ var dagstoreRecoverShardCmd = &cli.Command{
|
||||
Name: "recover-shard",
|
||||
ArgsUsage: "[key]",
|
||||
Usage: "Attempt to recover a shard in errored state",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
@@ -176,17 +132,8 @@ var dagstoreInitializeAllCmd = &cli.Command{
|
||||
Name: "include-sealed",
|
||||
Usage: "initialize sealed pieces as well",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
concurrency := cctx.Uint("concurrency")
|
||||
sealed := cctx.Bool("sealed")
|
||||
|
||||
@@ -236,18 +183,7 @@ var dagstoreInitializeAllCmd = &cli.Command{
|
||||
var dagstoreGcCmd = &cli.Command{
|
||||
Name: "gc",
|
||||
Usage: "Garbage collect the dagstore",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -317,18 +253,7 @@ var dagstoreLookupPiecesCmd = &cli.Command{
|
||||
Name: "lookup-pieces",
|
||||
Usage: "Lookup pieces that a given CID belongs to",
|
||||
ArgsUsage: "<cid>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
@@ -23,18 +22,7 @@ var indexProvAnnounceCmd = &cli.Command{
|
||||
Name: "announce",
|
||||
ArgsUsage: "<deal proposal cid>",
|
||||
Usage: "Announce a deal to indexers so they can download its index",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
@@ -60,18 +48,7 @@ var indexProvAnnounceCmd = &cli.Command{
|
||||
var indexProvAnnounceAllCmd = &cli.Command{
|
||||
Name: "announce-all",
|
||||
Usage: "Announce all active deals to indexers so they can download the indices",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-122
@@ -7,8 +7,6 @@ import (
|
||||
corebig "math/big"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
@@ -18,8 +16,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@@ -65,12 +61,6 @@ func infoCmdAct(cctx *cli.Context) error {
|
||||
}
|
||||
defer closer()
|
||||
|
||||
marketsApi, closer, err := lcli.GetMarketsAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
fullapi, acloser, err := lcli.GetFullNodeAPIV1(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -84,14 +74,7 @@ func infoCmdAct(cctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Enabled subsystems (from miner API):", subsystems)
|
||||
|
||||
subsystems, err = marketsApi.RuntimeSubsystems(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Enabled subsystems (from markets API):", subsystems)
|
||||
fmt.Println("Enabled subsystems:", subsystems)
|
||||
|
||||
start, err := minerApi.StartTime(ctx)
|
||||
if err != nil {
|
||||
@@ -128,11 +111,6 @@ func infoCmdAct(cctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = handleMarketsInfo(ctx, marketsApi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -393,105 +371,6 @@ func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v1api.Full
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleMarketsInfo(ctx context.Context, nodeApi api.StorageMiner) error {
|
||||
deals, err := nodeApi.MarketListIncompleteDeals(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type dealStat struct {
|
||||
count, verifCount int
|
||||
bytes, verifBytes uint64
|
||||
}
|
||||
dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) {
|
||||
ds.count++
|
||||
ds.bytes += uint64(deal.Proposal.PieceSize)
|
||||
if deal.Proposal.VerifiedDeal {
|
||||
ds.verifCount++
|
||||
ds.verifBytes += uint64(deal.Proposal.PieceSize)
|
||||
}
|
||||
}
|
||||
|
||||
showDealStates := map[storagemarket.StorageDealStatus]struct{}{
|
||||
storagemarket.StorageDealActive: {},
|
||||
storagemarket.StorageDealAcceptWait: {},
|
||||
storagemarket.StorageDealReserveProviderFunds: {},
|
||||
storagemarket.StorageDealProviderFunding: {},
|
||||
storagemarket.StorageDealTransferring: {},
|
||||
storagemarket.StorageDealValidating: {},
|
||||
storagemarket.StorageDealStaged: {},
|
||||
storagemarket.StorageDealAwaitingPreCommit: {},
|
||||
storagemarket.StorageDealSealing: {},
|
||||
storagemarket.StorageDealPublish: {},
|
||||
storagemarket.StorageDealCheckForAcceptance: {},
|
||||
storagemarket.StorageDealPublishing: {},
|
||||
}
|
||||
|
||||
var total dealStat
|
||||
perState := map[storagemarket.StorageDealStatus]*dealStat{}
|
||||
for _, deal := range deals {
|
||||
if _, ok := showDealStates[deal.State]; !ok {
|
||||
continue
|
||||
}
|
||||
if perState[deal.State] == nil {
|
||||
perState[deal.State] = new(dealStat)
|
||||
}
|
||||
|
||||
dsAdd(&total, deal)
|
||||
dsAdd(perState[deal.State], deal)
|
||||
}
|
||||
|
||||
type wstr struct {
|
||||
str string
|
||||
status storagemarket.StorageDealStatus
|
||||
}
|
||||
sorted := make([]wstr, 0, len(perState))
|
||||
for status, stat := range perState {
|
||||
st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal")
|
||||
sorted = append(sorted, wstr{
|
||||
str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))),
|
||||
status: status,
|
||||
},
|
||||
)
|
||||
}
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive {
|
||||
return sorted[i].status == storagemarket.StorageDealActive
|
||||
}
|
||||
return sorted[i].status > sorted[j].status
|
||||
})
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes)))
|
||||
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
|
||||
for _, e := range sorted {
|
||||
_, _ = tw.Write([]byte(e.str))
|
||||
}
|
||||
|
||||
_ = tw.Flush()
|
||||
fmt.Println()
|
||||
|
||||
retrievals, err := nodeApi.MarketListRetrievalDeals(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting retrieval deal list: %w", err)
|
||||
}
|
||||
|
||||
var retrComplete dealStat
|
||||
for _, retrieval := range retrievals {
|
||||
if retrieval.Status == retrievalmarket.DealStatusCompleted {
|
||||
retrComplete.count++
|
||||
retrComplete.bytes += retrieval.TotalSent
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes)))
|
||||
|
||||
fmt.Println()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type stateMeta struct {
|
||||
i int
|
||||
col color.Attribute
|
||||
|
||||
@@ -198,8 +198,17 @@ var infoAllCmd = &cli.Command{
|
||||
}
|
||||
|
||||
fmt.Println("\n#: Sector List")
|
||||
if err := sectorsListCmd.Action(cctx); err != nil {
|
||||
fmt.Println("ERROR: ", err)
|
||||
{
|
||||
fs := &flag.FlagSet{}
|
||||
for _, f := range sectorsListCmd.Flags {
|
||||
if err := f.Apply(fs); err != nil {
|
||||
fmt.Println("ERROR: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := sectorsListCmd.Action(cli.NewContext(cctx.App, fs, cctx)); err != nil {
|
||||
fmt.Println("ERROR: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("\n#: Storage Sector List")
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/fatih/color"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cidutil/cidenc"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
@@ -779,11 +778,6 @@ var transfersListCmd = &cli.Command{
|
||||
Aliases: []string{"v"},
|
||||
Usage: "print verbose transfer details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "completed",
|
||||
Usage: "show completed data transfers",
|
||||
@@ -798,10 +792,6 @@ var transfersListCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := lcli.GetMarketsAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -45,18 +45,7 @@ func workersCmd(sealing bool) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "workers",
|
||||
Usage: "list workers",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -218,21 +207,12 @@ var sealingJobsCmd = &cli.Command{
|
||||
Name: "jobs",
|
||||
Usage: "list running jobs",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-ret-done",
|
||||
Usage: "show returned but not consumed calls",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+116
-315
@@ -9,6 +9,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
@@ -33,11 +34,14 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||
"github.com/filecoin-project/lotus/lib/result"
|
||||
"github.com/filecoin-project/lotus/lib/strle"
|
||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||
sealing "github.com/filecoin-project/lotus/storage/pipeline"
|
||||
)
|
||||
|
||||
const parallelSectorChecks = 300
|
||||
|
||||
var sectorsCmd = &cli.Command{
|
||||
Name: "sectors",
|
||||
Usage: "interact with sector store",
|
||||
@@ -51,7 +55,6 @@ var sectorsCmd = &cli.Command{
|
||||
sectorPreCommitsCmd,
|
||||
sectorsCheckExpireCmd,
|
||||
sectorsExpiredCmd,
|
||||
sectorsRenewCmd,
|
||||
sectorsExtendCmd,
|
||||
sectorsTerminateCmd,
|
||||
sectorsRemoveCmd,
|
||||
@@ -121,8 +124,8 @@ var sectorsStatusCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify sector number to get status of")
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
|
||||
@@ -278,12 +281,6 @@ var sectorsListCmd = &cli.Command{
|
||||
Usage: "show removed sectors",
|
||||
Aliases: []string{"r"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
Aliases: []string{"c"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "fast",
|
||||
Usage: "don't show on-chain info for better performance",
|
||||
@@ -313,13 +310,15 @@ var sectorsListCmd = &cli.Command{
|
||||
Usage: "only show sectors which aren't in the 'Proving' state",
|
||||
Aliases: []string{"u"},
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "check-parallelism",
|
||||
Usage: "number of parallel requests to make for checking sector states",
|
||||
Value: parallelSectorChecks,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
// http mode allows for parallel json decoding/encoding, which was a bottleneck here
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -418,16 +417,37 @@ var sectorsListCmd = &cli.Command{
|
||||
|
||||
fast := cctx.Bool("fast")
|
||||
|
||||
for _, s := range list {
|
||||
st, err := minerApi.SectorsStatus(ctx, s, !fast)
|
||||
if err != nil {
|
||||
throttle := make(chan struct{}, cctx.Int64("check-parallelism"))
|
||||
|
||||
slist := make([]result.Result[api.SectorInfo], len(list))
|
||||
var wg sync.WaitGroup
|
||||
for i, s := range list {
|
||||
throttle <- struct{}{}
|
||||
wg.Add(1)
|
||||
go func(i int, s abi.SectorNumber) {
|
||||
defer wg.Done()
|
||||
defer func() { <-throttle }()
|
||||
r := result.Wrap(minerApi.SectorsStatus(ctx, s, !fast))
|
||||
if r.Error != nil {
|
||||
r.Value.SectorID = s
|
||||
}
|
||||
slist[i] = r
|
||||
}(i, s)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for _, rsn := range slist {
|
||||
if rsn.Error != nil {
|
||||
tw.Write(map[string]interface{}{
|
||||
"ID": s,
|
||||
"ID": rsn.Value.SectorID,
|
||||
"Error": err,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
st := rsn.Value
|
||||
s := st.SectorID
|
||||
|
||||
if !showRemoved && st.State == api.SectorState(sealing.Removed) {
|
||||
continue
|
||||
}
|
||||
@@ -743,14 +763,14 @@ func ArrayToString(array []uint64) string {
|
||||
return strings.Join(sarray, ",")
|
||||
}
|
||||
|
||||
func getSectorsFromFile(filePath string) ([]uint64, error) {
|
||||
func getSectorsFromFile(filePath string) ([]abi.SectorNumber, error) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
sectors := make([]uint64, 0)
|
||||
sectors := make([]abi.SectorNumber, 0)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
@@ -760,7 +780,7 @@ func getSectorsFromFile(filePath string) ([]uint64, error) {
|
||||
return nil, xerrors.Errorf("could not parse %s as sector id: %s", line, err)
|
||||
}
|
||||
|
||||
sectors = append(sectors, id)
|
||||
sectors = append(sectors, abi.SectorNumber(id))
|
||||
}
|
||||
|
||||
if err = file.Close(); err != nil {
|
||||
@@ -770,9 +790,19 @@ func getSectorsFromFile(filePath string) ([]uint64, error) {
|
||||
return sectors, nil
|
||||
}
|
||||
|
||||
var sectorsRenewCmd = &cli.Command{
|
||||
Name: "renew",
|
||||
Usage: "Renew expiring sectors while not exceeding each sector's max life",
|
||||
func SectorNumsToBitfield(sectors []abi.SectorNumber) bitfield.BitField {
|
||||
var numbers []uint64
|
||||
for _, sector := range sectors {
|
||||
numbers = append(numbers, uint64(sector))
|
||||
}
|
||||
|
||||
return bitfield.NewFromSet(numbers)
|
||||
}
|
||||
|
||||
var sectorsExtendCmd = &cli.Command{
|
||||
Name: "extend",
|
||||
Usage: "Extend expiring sectors while not exceeding each sector's max life",
|
||||
ArgsUsage: "<sectorNumbers...(optional)>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "from",
|
||||
@@ -819,7 +849,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
Usage: "pass this flag to really renew sectors, otherwise will only print out json representation of parameters",
|
||||
Usage: "pass this flag to really extend sectors, otherwise will only print out json representation of parameters",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
@@ -896,8 +926,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
excludeSet := make(map[uint64]struct{})
|
||||
|
||||
excludeSet := make(map[abi.SectorNumber]struct{})
|
||||
if cctx.IsSet("exclude") {
|
||||
excludeSectors, err := getSectorsFromFile(cctx.String("exclude"))
|
||||
if err != nil {
|
||||
@@ -909,28 +938,24 @@ var sectorsRenewCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
var sis []*miner.SectorOnChainInfo
|
||||
|
||||
if cctx.IsSet("sector-file") {
|
||||
sectors, err := getSectorsFromFile(cctx.String("sector-file"))
|
||||
if err != nil {
|
||||
return err
|
||||
var sectors []abi.SectorNumber
|
||||
if cctx.Args().Present() {
|
||||
if cctx.IsSet("sector-file") {
|
||||
return xerrors.Errorf("sector-file specified along with command line params")
|
||||
}
|
||||
|
||||
for _, id := range sectors {
|
||||
if _, exclude := excludeSet[id]; exclude {
|
||||
continue
|
||||
for i, s := range cctx.Args().Slice() {
|
||||
id, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not parse sector %d: %w", i, err)
|
||||
}
|
||||
|
||||
si, found := activeSectorsInfo[abi.SectorNumber(id)]
|
||||
if !found {
|
||||
return xerrors.Errorf("sector %d is not active", id)
|
||||
}
|
||||
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
|
||||
continue
|
||||
}
|
||||
|
||||
sis = append(sis, si)
|
||||
sectors = append(sectors, abi.SectorNumber(id))
|
||||
}
|
||||
} else if cctx.IsSet("sector-file") {
|
||||
sectors, err = getSectorsFromFile(cctx.String("sector-file"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
from := currEpoch + 120
|
||||
@@ -945,19 +970,28 @@ var sectorsRenewCmd = &cli.Command{
|
||||
}
|
||||
|
||||
for _, si := range activeSet {
|
||||
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
|
||||
continue
|
||||
}
|
||||
|
||||
if si.Expiration >= from && si.Expiration <= to {
|
||||
if _, exclude := excludeSet[uint64(si.SectorNumber)]; !exclude {
|
||||
sis = append(sis, si)
|
||||
}
|
||||
sectors = append(sectors, si.SectorNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]uint64{}
|
||||
var sis []*miner.SectorOnChainInfo
|
||||
for _, id := range sectors {
|
||||
if _, exclude := excludeSet[id]; exclude {
|
||||
continue
|
||||
}
|
||||
|
||||
si, found := activeSectorsInfo[id]
|
||||
if !found {
|
||||
return xerrors.Errorf("sector %d is not active", id)
|
||||
}
|
||||
if len(si.DealIDs) > 0 && cctx.Bool("only-cc") {
|
||||
continue
|
||||
}
|
||||
|
||||
sis = append(sis, si)
|
||||
}
|
||||
|
||||
withinTolerance := func(a, b abi.ChainEpoch) bool {
|
||||
diff := a - b
|
||||
@@ -968,6 +1002,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
return diff <= abi.ChainEpoch(cctx.Int64("tolerance"))
|
||||
}
|
||||
|
||||
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]abi.SectorNumber{}
|
||||
for _, si := range sis {
|
||||
extension := abi.ChainEpoch(cctx.Int64("extension"))
|
||||
newExp := si.Expiration + extension
|
||||
@@ -997,21 +1032,21 @@ var sectorsRenewCmd = &cli.Command{
|
||||
|
||||
es, found := extensions[*l]
|
||||
if !found {
|
||||
ne := make(map[abi.ChainEpoch][]uint64)
|
||||
ne[newExp] = []uint64{uint64(si.SectorNumber)}
|
||||
ne := make(map[abi.ChainEpoch][]abi.SectorNumber)
|
||||
ne[newExp] = []abi.SectorNumber{si.SectorNumber}
|
||||
extensions[*l] = ne
|
||||
} else {
|
||||
added := false
|
||||
for exp := range es {
|
||||
if withinTolerance(newExp, exp) {
|
||||
es[exp] = append(es[exp], uint64(si.SectorNumber))
|
||||
es[exp] = append(es[exp], si.SectorNumber)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !added {
|
||||
es[newExp] = []uint64{uint64(si.SectorNumber)}
|
||||
es[newExp] = []abi.SectorNumber{si.SectorNumber}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1051,7 +1086,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
|
||||
Deadline: l.Deadline,
|
||||
Partition: l.Partition,
|
||||
Sectors: bitfield.NewFromSet(numbers),
|
||||
Sectors: SectorNumsToBitfield(numbers),
|
||||
NewExpiration: newExp,
|
||||
})
|
||||
}
|
||||
@@ -1083,7 +1118,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
}
|
||||
scount += int(count)
|
||||
}
|
||||
fmt.Printf("Renewing %d sectors: ", scount)
|
||||
fmt.Printf("Extending %d sectors: ", scount)
|
||||
stotal += scount
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
@@ -1097,8 +1132,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(string(data))
|
||||
fmt.Println("\n", string(data))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1121,252 +1155,7 @@ var sectorsRenewCmd = &cli.Command{
|
||||
fmt.Println(smsg.Cid())
|
||||
}
|
||||
|
||||
fmt.Printf("%d sectors renewed\n", stotal)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var sectorsExtendCmd = &cli.Command{
|
||||
Name: "extend",
|
||||
Usage: "Extend sector expiration",
|
||||
ArgsUsage: "<sectorNumbers...>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Int64Flag{
|
||||
Name: "new-expiration",
|
||||
Usage: "new expiration epoch",
|
||||
Required: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "v1-sectors",
|
||||
Usage: "renews all v1 sectors up to the maximum possible lifetime",
|
||||
Required: false,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "tolerance",
|
||||
Value: 20160,
|
||||
Usage: "when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs",
|
||||
Required: false,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "expiration-ignore",
|
||||
Value: 120,
|
||||
Usage: "when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now",
|
||||
Required: false,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "expiration-cutoff",
|
||||
Usage: "when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified)",
|
||||
Required: false,
|
||||
},
|
||||
&cli.StringFlag{},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
api, nCloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer nCloser()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
maddr, err := getActorAddress(ctx, cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var params []miner.ExtendSectorExpirationParams
|
||||
|
||||
if cctx.Bool("v1-sectors") {
|
||||
|
||||
head, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nv, err := api.StateNetworkVersion(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extensions := map[lminer.SectorLocation]map[abi.ChainEpoch][]uint64{}
|
||||
|
||||
// are given durations within tolerance epochs
|
||||
withinTolerance := func(a, b abi.ChainEpoch) bool {
|
||||
diff := a - b
|
||||
if diff < 0 {
|
||||
diff = b - a
|
||||
}
|
||||
|
||||
return diff <= abi.ChainEpoch(cctx.Int64("tolerance"))
|
||||
}
|
||||
|
||||
sis, err := api.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner sector infos: %w", err)
|
||||
}
|
||||
|
||||
for _, si := range sis {
|
||||
if si.SealProof >= abi.RegisteredSealProof_StackedDrg2KiBV1_1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if si.Expiration < (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-ignore"))) {
|
||||
continue
|
||||
}
|
||||
|
||||
if cctx.IsSet("expiration-cutoff") {
|
||||
if si.Expiration > (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-cutoff"))) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ml := policy.GetSectorMaxLifetime(si.SealProof, nv)
|
||||
// if the sector's missing less than "tolerance" of its maximum possible lifetime, don't bother extending it
|
||||
if withinTolerance(si.Expiration-si.Activation, ml) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Set the new expiration to 48 hours less than the theoretical maximum lifetime
|
||||
newExp := ml - (miner.WPoStProvingPeriod * 2) + si.Activation
|
||||
if withinTolerance(si.Expiration, newExp) || si.Expiration >= newExp {
|
||||
continue
|
||||
}
|
||||
|
||||
p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err)
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
return xerrors.Errorf("sector %d not found in any partition", si.SectorNumber)
|
||||
}
|
||||
|
||||
es, found := extensions[*p]
|
||||
if !found {
|
||||
ne := make(map[abi.ChainEpoch][]uint64)
|
||||
ne[newExp] = []uint64{uint64(si.SectorNumber)}
|
||||
extensions[*p] = ne
|
||||
} else {
|
||||
added := false
|
||||
for exp := range es {
|
||||
if withinTolerance(exp, newExp) && newExp >= exp && exp > si.Expiration {
|
||||
es[exp] = append(es[exp], uint64(si.SectorNumber))
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !added {
|
||||
es[newExp] = []uint64{uint64(si.SectorNumber)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := miner.ExtendSectorExpirationParams{}
|
||||
scount := 0
|
||||
|
||||
for l, exts := range extensions {
|
||||
for newExp, numbers := range exts {
|
||||
scount += len(numbers)
|
||||
addressedMax, err := policy.GetAddressedSectorsMax(nv)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get addressed sectors max")
|
||||
}
|
||||
declMax, err := policy.GetDeclarationsMax(nv)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get declarations max")
|
||||
}
|
||||
if scount > addressedMax || len(p.Extensions) == declMax {
|
||||
params = append(params, p)
|
||||
p = miner.ExtendSectorExpirationParams{}
|
||||
scount = len(numbers)
|
||||
}
|
||||
|
||||
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
|
||||
Deadline: l.Deadline,
|
||||
Partition: l.Partition,
|
||||
Sectors: bitfield.NewFromSet(numbers),
|
||||
NewExpiration: newExp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// if we have any sectors, then one last append is needed here
|
||||
if scount != 0 {
|
||||
params = append(params, p)
|
||||
}
|
||||
|
||||
} else {
|
||||
if !cctx.Args().Present() || !cctx.IsSet("new-expiration") {
|
||||
return xerrors.Errorf("must pass at least one sector number and new expiration")
|
||||
}
|
||||
sectors := map[lminer.SectorLocation][]uint64{}
|
||||
|
||||
for i, s := range cctx.Args().Slice() {
|
||||
id, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not parse sector %d: %w", i, err)
|
||||
}
|
||||
|
||||
p, err := api.StateSectorPartition(ctx, maddr, abi.SectorNumber(id), types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting sector location for sector %d: %w", id, err)
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
return xerrors.Errorf("sector %d not found in any partition", id)
|
||||
}
|
||||
|
||||
sectors[*p] = append(sectors[*p], id)
|
||||
}
|
||||
|
||||
p := miner.ExtendSectorExpirationParams{}
|
||||
for l, numbers := range sectors {
|
||||
|
||||
// TODO: Dedup with above loop
|
||||
p.Extensions = append(p.Extensions, miner.ExpirationExtension{
|
||||
Deadline: l.Deadline,
|
||||
Partition: l.Partition,
|
||||
Sectors: bitfield.NewFromSet(numbers),
|
||||
NewExpiration: abi.ChainEpoch(cctx.Int64("new-expiration")),
|
||||
})
|
||||
}
|
||||
|
||||
params = append(params, p)
|
||||
}
|
||||
|
||||
if len(params) == 0 {
|
||||
fmt.Println("nothing to extend")
|
||||
return nil
|
||||
}
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
for i := range params {
|
||||
sp, aerr := actors.SerializeParams(¶ms[i])
|
||||
if aerr != nil {
|
||||
return xerrors.Errorf("serializing params: %w", err)
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
|
||||
From: mi.Worker,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ExtendSectorExpiration,
|
||||
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push message: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(smsg.Cid())
|
||||
}
|
||||
fmt.Printf("%d sectors extended\n", stotal)
|
||||
|
||||
return nil
|
||||
},
|
||||
@@ -1387,9 +1176,6 @@ var sectorsTerminateCmd = &cli.Command{
|
||||
sectorsTerminatePendingCmd,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Bool("really-do-it") {
|
||||
return xerrors.Errorf("pass --really-do-it to confirm this action")
|
||||
}
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1400,6 +1186,10 @@ var sectorsTerminateCmd = &cli.Command{
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
return xerrors.Errorf("pass --really-do-it to confirm this action")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not parse sector number: %w", err)
|
||||
@@ -1620,8 +1410,14 @@ var sectorsStartSealCmd = &cli.Command{
|
||||
|
||||
var sectorsSealDelayCmd = &cli.Command{
|
||||
Name: "set-seal-delay",
|
||||
Usage: "Set the time, in minutes, that a new sector waits for deals before sealing starts",
|
||||
ArgsUsage: "<minutes>",
|
||||
Usage: "Set the time (in minutes) that a new sector waits for deals before sealing starts",
|
||||
ArgsUsage: "<time>",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "seconds",
|
||||
Usage: "Specifies that the time argument should be in seconds",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
minerAPI, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -1638,7 +1434,12 @@ var sectorsSealDelayCmd = &cli.Command{
|
||||
return xerrors.Errorf("could not parse sector number: %w", err)
|
||||
}
|
||||
|
||||
delay := hs * uint64(time.Minute)
|
||||
var delay uint64
|
||||
if cctx.Bool("seconds") {
|
||||
delay = hs * uint64(time.Second)
|
||||
} else {
|
||||
delay = hs * uint64(time.Minute)
|
||||
}
|
||||
|
||||
return minerAPI.SectorSetSealDelay(ctx, time.Duration(delay))
|
||||
},
|
||||
@@ -1732,8 +1533,8 @@ var sectorsUpdateCmd = &cli.Command{
|
||||
}
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
if cctx.NArg() < 2 {
|
||||
return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number and new state"))
|
||||
if cctx.NArg() != 2 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||
|
||||
+18
-30
@@ -55,8 +55,9 @@ stored while moving through the sealing pipeline (references as 'seal').`,
|
||||
}
|
||||
|
||||
var storageAttachCmd = &cli.Command{
|
||||
Name: "attach",
|
||||
Usage: "attach local storage path",
|
||||
Name: "attach",
|
||||
Usage: "attach local storage path",
|
||||
ArgsUsage: "[path]",
|
||||
Description: `Storage can be attached to the miner using this command. The storage volume
|
||||
list is stored local to the miner in $LOTUS_MINER_PATH/storage.json. We do not
|
||||
recommend manually modifying this value without further understanding of the
|
||||
@@ -115,8 +116,8 @@ over time
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return xerrors.Errorf("must specify storage path to attach")
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
p, err := homedir.Expand(cctx.Args().First())
|
||||
@@ -192,8 +193,8 @@ var storageDetachCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return xerrors.Errorf("must specify storage path")
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
p, err := homedir.Expand(cctx.Args().First())
|
||||
@@ -210,8 +211,9 @@ var storageDetachCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var storageRedeclareCmd = &cli.Command{
|
||||
Name: "redeclare",
|
||||
Usage: "redeclare sectors in a local storage path",
|
||||
Name: "redeclare",
|
||||
Usage: "redeclare sectors in a local storage path",
|
||||
ArgsUsage: "[path]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "id",
|
||||
@@ -234,6 +236,10 @@ var storageRedeclareCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
if cctx.IsSet("id") && cctx.Bool("all") {
|
||||
return xerrors.Errorf("--id and --all can't be passed at the same time")
|
||||
}
|
||||
@@ -254,21 +260,10 @@ var storageRedeclareCmd = &cli.Command{
|
||||
var storageListCmd = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list local storage paths",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
storageListSectorsCmd,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -477,6 +472,10 @@ var storageFindCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
ma, err := minerApi.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -633,18 +632,7 @@ var storageFindCmd = &cli.Command{
|
||||
var storageListSectorsCmd = &cli.Command{
|
||||
Name: "sectors",
|
||||
Usage: "get list of all sector files",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
|
||||
@@ -35,6 +37,8 @@ var actorCmd = &cli.Command{
|
||||
actorProposeChangeWorker,
|
||||
actorConfirmChangeWorker,
|
||||
actorGetMethodNum,
|
||||
actorProposeChangeBeneficiary,
|
||||
actorConfirmChangeBeneficiary,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -831,3 +835,255 @@ var actorGetMethodNum = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var actorProposeChangeBeneficiary = &cli.Command{
|
||||
Name: "propose-change-beneficiary",
|
||||
Usage: "Propose a beneficiary address change",
|
||||
ArgsUsage: "[beneficiaryAddress quota expiration minerID]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
Usage: "Actually send transaction performing the action",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "overwrite-pending-change",
|
||||
Usage: "Overwrite the current beneficiary change proposal",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 4 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting fullnode api: %w", err)
|
||||
}
|
||||
defer acloser()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
na, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("looking up new beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
quota, err := types.ParseFIL(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing quota: %w", err)
|
||||
}
|
||||
|
||||
expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing expiration: %w", err)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().Get(3))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner address: %w", err)
|
||||
}
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if mi.Beneficiary == mi.Owner && newAddr == mi.Owner {
|
||||
return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary)
|
||||
}
|
||||
|
||||
if mi.PendingBeneficiaryTerm != nil {
|
||||
fmt.Println("WARNING: replacing Pending Beneficiary Term of:")
|
||||
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
|
||||
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
|
||||
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
|
||||
|
||||
if !cctx.Bool("overwrite-pending-change") {
|
||||
return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY")
|
||||
}
|
||||
}
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &miner.ChangeBeneficiaryParams{
|
||||
NewBeneficiary: newAddr,
|
||||
NewQuota: abi.TokenAmount(quota),
|
||||
NewExpiration: abi.ChainEpoch(expiration),
|
||||
}
|
||||
|
||||
sp, err := actors.SerializeParams(params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("serializing params: %w", err)
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
|
||||
From: mi.Owner,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ChangeBeneficiary,
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Propose Message CID:", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("waiting for message to be included in block: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode.IsError() {
|
||||
return fmt.Errorf("propose beneficiary change failed")
|
||||
}
|
||||
|
||||
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr {
|
||||
fmt.Println("Beneficiary address successfully changed")
|
||||
} else {
|
||||
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var actorConfirmChangeBeneficiary = &cli.Command{
|
||||
Name: "confirm-change-beneficiary",
|
||||
Usage: "Confirm a beneficiary address change",
|
||||
ArgsUsage: "[minerAddress]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
Usage: "Actually send transaction performing the action",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "existing-beneficiary",
|
||||
Usage: "send confirmation from the existing beneficiary address",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "new-beneficiary",
|
||||
Usage: "send confirmation from the new beneficiary address",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting fullnode api: %w", err)
|
||||
}
|
||||
defer acloser()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing beneficiary address: %w", err)
|
||||
}
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
if mi.PendingBeneficiaryTerm == nil {
|
||||
return fmt.Errorf("no pending beneficiary term found for miner %s", maddr)
|
||||
}
|
||||
|
||||
if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) {
|
||||
return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary"))
|
||||
}
|
||||
|
||||
var fromAddr address.Address
|
||||
if cctx.IsSet("existing-beneficiary") {
|
||||
if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary {
|
||||
return fmt.Errorf("beneficiary change already approved by current beneficiary")
|
||||
}
|
||||
fromAddr = mi.Beneficiary
|
||||
} else {
|
||||
if mi.PendingBeneficiaryTerm.ApprovedByNominee {
|
||||
return fmt.Errorf("beneficiary change already approved by new beneficiary")
|
||||
}
|
||||
fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary
|
||||
}
|
||||
|
||||
fmt.Println("Confirming Pending Beneficiary Term of:")
|
||||
fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary)
|
||||
fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota)
|
||||
fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration)
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please")
|
||||
return nil
|
||||
}
|
||||
|
||||
params := &miner.ChangeBeneficiaryParams{
|
||||
NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary,
|
||||
NewQuota: mi.PendingBeneficiaryTerm.NewQuota,
|
||||
NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration,
|
||||
}
|
||||
|
||||
sp, err := actors.SerializeParams(params)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("serializing params: %w", err)
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, &types.Message{
|
||||
From: fromAddr,
|
||||
To: maddr,
|
||||
Method: builtin.MethodsMiner.ChangeBeneficiary,
|
||||
Value: big.Zero(),
|
||||
Params: sp,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("mpool push: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Confirm Message CID:", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("waiting for message to be included in block: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode.IsError() {
|
||||
return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary {
|
||||
fmt.Println("Beneficiary address successfully changed")
|
||||
} else {
|
||||
fmt.Println("Beneficiary address change awaiting additional confirmations")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -13,6 +13,15 @@ import (
|
||||
|
||||
var addressCmd = &cli.Command{
|
||||
Name: "addr",
|
||||
Usage: "interact with filecoin addresses",
|
||||
Subcommands: cli.Commands{
|
||||
addrDecode,
|
||||
addrEncode,
|
||||
},
|
||||
}
|
||||
|
||||
var addrDecode = &cli.Command{
|
||||
Name: "decode",
|
||||
Usage: "decode hex bytes into address",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
addrHex := cctx.Args().First()
|
||||
@@ -39,3 +48,17 @@ var addressCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var addrEncode = &cli.Command{
|
||||
Name: "encode",
|
||||
Usage: "encode address to hex bytes",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
addr, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%x\n", addr.Bytes())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
@@ -512,7 +513,7 @@ var chainBalanceStateCmd = &cli.Command{
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -736,7 +737,7 @@ var chainPledgeCmd = &cli.Command{
|
||||
cst := cbor.NewCborStore(bs)
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/ipld/go-car"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -27,6 +29,42 @@ var cidCmd = &cli.Command{
|
||||
Subcommands: cli.Commands{
|
||||
cidIdCmd,
|
||||
inspectBundleCmd,
|
||||
cborCid,
|
||||
cidBytes,
|
||||
},
|
||||
}
|
||||
|
||||
var cidBytes = &cli.Command{
|
||||
Name: "bytes",
|
||||
Usage: "cid bytes",
|
||||
ArgsUsage: "[cid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
c, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Add in the troublesome zero byte prefix
|
||||
fmt.Printf("00%x\n", c.Bytes())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var cborCid = &cli.Command{
|
||||
Name: "cbor",
|
||||
Usage: "Serialize cid to cbor",
|
||||
ArgsUsage: "[cid]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
c, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cbgc := cbg.CborCid(c)
|
||||
buf := bytes.NewBuffer(make([]byte, 0))
|
||||
if err := cbgc.MarshalCBOR(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%x\n", buf.Bytes())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/beacon/drand"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -110,7 +111,7 @@ var gasTraceCmd = &cli.Command{
|
||||
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -211,7 +212,7 @@ var replayOfflineCmd = &cli.Command{
|
||||
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), shd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -89,7 +90,7 @@ var invariantsCmd = &cli.Command{
|
||||
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ func main() {
|
||||
|
||||
local := []*cli.Command{
|
||||
addressCmd,
|
||||
statActorCmd,
|
||||
statObjCmd,
|
||||
base64Cmd,
|
||||
base32Cmd,
|
||||
base16Cmd,
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -120,7 +121,7 @@ var migrationsCmd = &cli.Command{
|
||||
cs := store.NewChainStore(bs, bs, mds, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
sm, err := stmgr.NewStateManager(cs, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
sm, err := stmgr.NewStateManager(cs, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
@@ -141,7 +141,7 @@ func printMessage(cctx *cli.Context, msg *types.Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][msg.Method].Name) // todo use remote
|
||||
fmt.Println("Method:", consensus.NewActorRegistry().Methods[toact.Code][msg.Method].Name) // todo use remote
|
||||
p, err := lcli.JsonParams(toact.Code, msg.Method, msg.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/cheggaaa/pb.v1"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
@@ -31,6 +32,11 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/parmap"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage/paths"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/fr32"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
||||
)
|
||||
|
||||
var sectorsCmd = &cli.Command{
|
||||
@@ -42,6 +48,8 @@ var sectorsCmd = &cli.Command{
|
||||
terminateSectorPenaltyEstimationCmd,
|
||||
visAllocatedSectorsCmd,
|
||||
dumpRLESectorCmd,
|
||||
sectorReadCmd,
|
||||
sectorDeleteCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -563,3 +571,219 @@ func rleToPng(rleBytes []byte) ([]byte, error) {
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
var sectorReadCmd = &cli.Command{
|
||||
Name: "read",
|
||||
Usage: "read data from a sector into stdout",
|
||||
ArgsUsage: "[sector num] [padded length] [padded offset]",
|
||||
Description: `Read data from a sector.
|
||||
|
||||
TIP: to get sectornum/len/offset for a piece you can use 'boostd pieces piece-info [cid]'
|
||||
|
||||
fr32 padding is removed from the output.`,
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 3 {
|
||||
return xerrors.Errorf("must pass sectornum/len/offset")
|
||||
}
|
||||
|
||||
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing sector number: %w", err)
|
||||
}
|
||||
|
||||
length, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing length: %w", err)
|
||||
}
|
||||
|
||||
offset, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing offset: %w", err)
|
||||
}
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maddr, err := api.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner actor address: %w", err)
|
||||
}
|
||||
|
||||
mid, err := address.IDFromAddress(maddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner id: %w", err)
|
||||
}
|
||||
|
||||
sid := abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sectorNum),
|
||||
}
|
||||
|
||||
si, err := api.SectorsStatus(ctx, sid.Number, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting sector status: %w", err)
|
||||
}
|
||||
|
||||
sref := storiface.SectorRef{
|
||||
ID: sid,
|
||||
ProofType: si.SealProof,
|
||||
}
|
||||
|
||||
defer closer()
|
||||
|
||||
// Setup remote sector store
|
||||
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get api info: %w", err)
|
||||
}
|
||||
|
||||
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
|
||||
&paths.DefaultPartialFileHandler{})
|
||||
|
||||
readStarter, err := remote.Reader(ctx, sref, abi.PaddedPieceSize(offset), abi.PaddedPieceSize(length))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting reader: %w", err)
|
||||
}
|
||||
|
||||
rd, err := readStarter(0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("starting reader: %w", err)
|
||||
}
|
||||
|
||||
upr, err := fr32.NewUnpadReaderBuf(rd, abi.PaddedPieceSize(length), make([]byte, 1<<20))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("creating unpadded reader: %w", err)
|
||||
}
|
||||
|
||||
l := int64(abi.PaddedPieceSize(length).Unpadded())
|
||||
|
||||
bar := pb.New64(l)
|
||||
br := bar.NewProxyReader(upr)
|
||||
bar.ShowTimeLeft = true
|
||||
bar.ShowPercent = true
|
||||
bar.ShowSpeed = true
|
||||
bar.Units = pb.U_BYTES
|
||||
bar.Output = os.Stderr
|
||||
bar.Start()
|
||||
|
||||
_, err = io.CopyN(os.Stdout, br, l)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading data: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var sectorDeleteCmd = &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete a sector file from sector storage",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "really-do-it",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[sector num] [file type]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 2 {
|
||||
return xerrors.Errorf("must pass sectornum/filetype")
|
||||
}
|
||||
|
||||
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing sector number: %w", err)
|
||||
}
|
||||
|
||||
var ft storiface.SectorFileType
|
||||
switch cctx.Args().Get(1) {
|
||||
case "cache":
|
||||
ft = storiface.FTCache
|
||||
case "sealed":
|
||||
ft = storiface.FTSealed
|
||||
case "unsealed":
|
||||
ft = storiface.FTUnsealed
|
||||
case "update-cache":
|
||||
ft = storiface.FTUpdateCache
|
||||
case "update":
|
||||
ft = storiface.FTUpdate
|
||||
default:
|
||||
return xerrors.Errorf("invalid file type")
|
||||
}
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
maddr, err := api.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner actor address: %w", err)
|
||||
}
|
||||
|
||||
mid, err := address.IDFromAddress(maddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner id: %w", err)
|
||||
}
|
||||
|
||||
sid := abi.SectorID{
|
||||
Miner: abi.ActorID(mid),
|
||||
Number: abi.SectorNumber(sectorNum),
|
||||
}
|
||||
|
||||
// get remote store
|
||||
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get api info: %w", err)
|
||||
}
|
||||
|
||||
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !cctx.Bool("really-do-it") {
|
||||
return xerrors.Errorf("pass --really-do-it to actually perform the deletion")
|
||||
}
|
||||
|
||||
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
|
||||
&paths.DefaultPartialFileHandler{})
|
||||
|
||||
err = remote.Remove(ctx, sid, ft, true, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("removing sector: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type emptyLocalStorage struct {
|
||||
}
|
||||
|
||||
func (e *emptyLocalStorage) GetStorage() (storiface.StorageConfig, error) {
|
||||
return storiface.StorageConfig{}, nil
|
||||
}
|
||||
|
||||
func (e *emptyLocalStorage) SetStorage(f func(*storiface.StorageConfig)) error {
|
||||
panic("don't call")
|
||||
}
|
||||
|
||||
func (e *emptyLocalStorage) Stat(path string) (fsutil.FsStat, error) {
|
||||
panic("don't call")
|
||||
}
|
||||
|
||||
func (e *emptyLocalStorage) DiskUsage(path string) (int64, error) {
|
||||
panic("don't call")
|
||||
}
|
||||
|
||||
var _ paths.LocalStorage = &emptyLocalStorage{}
|
||||
|
||||
@@ -0,0 +1,533 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
format "github.com/ipfs/go-ipld-format"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
)
|
||||
|
||||
type actorStats struct {
|
||||
Address address.Address
|
||||
Actor *types.Actor
|
||||
Fields []fieldItem
|
||||
Stats api.ObjStat
|
||||
}
|
||||
|
||||
type fieldItem struct {
|
||||
Name string
|
||||
Cid cid.Cid
|
||||
Stats api.ObjStat
|
||||
}
|
||||
|
||||
type cacheNodeGetter struct {
|
||||
ds format.NodeGetter
|
||||
cache *lru.TwoQueueCache
|
||||
}
|
||||
|
||||
func newCacheNodeGetter(d format.NodeGetter, size int) (*cacheNodeGetter, error) {
|
||||
cng := &cacheNodeGetter{ds: d}
|
||||
|
||||
cache, err := lru.New2Q(size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cng.cache = cache
|
||||
|
||||
return cng, nil
|
||||
}
|
||||
|
||||
func (cng *cacheNodeGetter) Get(ctx context.Context, c cid.Cid) (format.Node, error) {
|
||||
if n, ok := cng.cache.Get(c); ok {
|
||||
return n.(format.Node), nil
|
||||
}
|
||||
|
||||
n, err := cng.ds.Get(ctx, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cng.cache.Add(c, n)
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (cng *cacheNodeGetter) GetMany(ctx context.Context, list []cid.Cid) <-chan *format.NodeOption {
|
||||
out := make(chan *format.NodeOption, len(list))
|
||||
go func() {
|
||||
for _, c := range list {
|
||||
n, err := cng.Get(ctx, c)
|
||||
if err != nil {
|
||||
out <- &format.NodeOption{Err: err}
|
||||
continue
|
||||
}
|
||||
|
||||
out <- &format.NodeOption{Node: n}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type dagStatCollector struct {
|
||||
ds format.NodeGetter
|
||||
walk func(format.Node) ([]*format.Link, error)
|
||||
|
||||
statsLk sync.Mutex
|
||||
stats api.ObjStat
|
||||
}
|
||||
|
||||
func (dsc *dagStatCollector) record(ctx context.Context, nd format.Node) error {
|
||||
size, err := nd.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dsc.statsLk.Lock()
|
||||
defer dsc.statsLk.Unlock()
|
||||
|
||||
dsc.stats.Size = dsc.stats.Size + size
|
||||
dsc.stats.Links = dsc.stats.Links + 1
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsc *dagStatCollector) walkLinks(ctx context.Context, c cid.Cid) ([]*format.Link, error) {
|
||||
nd, err := dsc.ds.Get(ctx, c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := dsc.record(ctx, nd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dsc.walk(nd)
|
||||
}
|
||||
|
||||
type ChainStoreTipSetResolver struct {
|
||||
Chain *store.ChainStore
|
||||
}
|
||||
|
||||
func (tsr *ChainStoreTipSetResolver) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
return tsr.Chain.GetHeaviestTipSet(), nil
|
||||
}
|
||||
|
||||
func (tsr *ChainStoreTipSetResolver) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
ts, err := tsr.Chain.GetTipSetFromKey(ctx, tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return tsr.Chain.GetTipsetByHeight(ctx, h, ts, true)
|
||||
}
|
||||
func (tsr *ChainStoreTipSetResolver) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return tsr.Chain.LoadTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
var statObjCmd = &cli.Command{
|
||||
Name: "stat-obj",
|
||||
Usage: "calculates the size of any DAG in the blockstore",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
c, err := cid.Parse(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := repo.NewFS(cctx.String("repo"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening fs repo: %w", err)
|
||||
}
|
||||
|
||||
exists, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return xerrors.Errorf("lotus repo doesn't exist")
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.FullNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open blockstore: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if c, ok := bs.(io.Closer); ok {
|
||||
if err := c.Close(); err != nil {
|
||||
log.Warnf("failed to close blockstore: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dag := merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
|
||||
dsc := &dagStatCollector{
|
||||
ds: dag,
|
||||
walk: carWalkFunc,
|
||||
}
|
||||
|
||||
if err := merkledag.Walk(ctx, dsc.walkLinks, c, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return DumpJSON(dsc.stats)
|
||||
},
|
||||
}
|
||||
|
||||
var statActorCmd = &cli.Command{
|
||||
Name: "stat-actor",
|
||||
Usage: "calculates the size of actors and their immeidate structures",
|
||||
Description: `Any DAG linked by the actor object (field) will have its size calculated independently of all
|
||||
other linked DAG. If an actor has two fields containing links to the same DAG the structure size will be counted
|
||||
twice, included in each fields size individually.
|
||||
|
||||
The top level stats reported for an actor is computed independently of all fields and is a more accurate
|
||||
accounting of the true size of the actor in the state datastore.
|
||||
|
||||
The calculation of these stats results in the actor state being traversed twice. The dag-cache-size flag can be used
|
||||
to reduce the number of decode operations performed by caching the decoded object after first access.`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
Usage: "specify tipset to call method on (pass comma separated array of cids)",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "workers",
|
||||
Usage: "number of workers to use when processing",
|
||||
Value: 10,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "dag-cache-size",
|
||||
Usage: "cache size per worker (setting to 0 disables)",
|
||||
Value: 8092,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "process all actors in stateroot of tipset",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "pretty",
|
||||
Usage: "print formated output instead of ldjson",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
var addrs []address.Address
|
||||
|
||||
if !cctx.Bool("all") {
|
||||
for _, a := range cctx.Args().Slice() {
|
||||
addr, err := address.NewFromString(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
}
|
||||
|
||||
r, err := repo.NewFS(cctx.String("repo"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening fs repo: %w", err)
|
||||
}
|
||||
|
||||
exists, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return xerrors.Errorf("lotus repo doesn't exist")
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.FullNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
bs, err := lr.Blockstore(ctx, repo.UniversalBlockstore)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open blockstore: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if c, ok := bs.(io.Closer); ok {
|
||||
if err := c.Close(); err != nil {
|
||||
log.Warnf("failed to close blockstore: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
mds, err := lr.Datastore(context.Background(), "/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, bs, mds, nil, nil)
|
||||
if err := cs.Load(ctx); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tsExec := consensus.NewTipSetExecutor(filcns.RewardFunc)
|
||||
sm, err := stmgr.NewStateManager(cs, tsExec, vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tsr := &ChainStoreTipSetResolver{
|
||||
Chain: cs,
|
||||
}
|
||||
|
||||
ts, err := lcli.LoadTipSet(ctx, cctx, tsr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infow("tipset", "parentstate", ts.ParentState())
|
||||
|
||||
if len(addrs) == 0 && cctx.Bool("all") {
|
||||
var err error
|
||||
addrs, err = sm.ListAllActors(ctx, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
numWorkers := cctx.Int("workers")
|
||||
dagCacheSize := cctx.Int("dag-cache-size")
|
||||
|
||||
eg, egctx := errgroup.WithContext(ctx)
|
||||
|
||||
jobs := make(chan address.Address, numWorkers)
|
||||
results := make(chan actorStats, numWorkers)
|
||||
|
||||
worker := func(ctx context.Context, id int) error {
|
||||
completed := 0
|
||||
defer func() {
|
||||
log.Infow("worker done", "id", id, "completed", completed)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case addr, ok := <-jobs:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
actor, err := sm.LoadActor(ctx, addr, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var dag format.NodeGetter = merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
|
||||
if dagCacheSize != 0 {
|
||||
var err error
|
||||
dag, err = newCacheNodeGetter(merkledag.NewDAGService(blockservice.New(bs, offline.Exchange(bs))), dagCacheSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
actStats, err := collectStats(ctx, addr, actor, dag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
select {
|
||||
case results <- actStats:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
completed = completed + 1
|
||||
}
|
||||
}
|
||||
|
||||
for w := 0; w < numWorkers; w++ {
|
||||
id := w
|
||||
eg.Go(func() error {
|
||||
return worker(egctx, id)
|
||||
})
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(jobs)
|
||||
for _, addr := range addrs {
|
||||
jobs <- addr
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
// error is check later
|
||||
eg.Wait() //nolint:errcheck
|
||||
close(results)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case result, ok := <-results:
|
||||
if !ok {
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
if cctx.Bool("pretty") {
|
||||
DumpStats(result)
|
||||
} else {
|
||||
if err := DumpJSON(result); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func collectStats(ctx context.Context, addr address.Address, actor *types.Actor, dag format.NodeGetter) (actorStats, error) {
|
||||
log.Infow("actor", "addr", addr, "code", actor.Code, "name", builtin.ActorNameByCode(actor.Code))
|
||||
|
||||
nd, err := dag.Get(ctx, actor.Head)
|
||||
if err != nil {
|
||||
return actorStats{}, err
|
||||
}
|
||||
|
||||
// When it comes to fvm / evm actors this method of inspecting fields will probably not work
|
||||
// and we may only be able to collect stats for the top level object. We might be able to iterate
|
||||
// over the top level fields for the actors and identify field that are CIDs, but unsure if we would
|
||||
// be able to identify a field name.
|
||||
|
||||
oif, err := vm.DumpActorState(consensus.NewTipSetExecutor(filcns.RewardFunc).NewActorRegistry(), actor, nd.RawData())
|
||||
if err != nil {
|
||||
oif = nil
|
||||
}
|
||||
|
||||
fields := []fieldItem{}
|
||||
|
||||
// Account actors return nil from DumpActorState as they have no state
|
||||
if oif != nil {
|
||||
v := reflect.Indirect(reflect.ValueOf(oif))
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
varName := v.Type().Field(i).Name
|
||||
varType := v.Type().Field(i).Type
|
||||
varValue := v.Field(i).Interface()
|
||||
|
||||
if varType == reflect.TypeOf(cid.Cid{}) {
|
||||
fields = append(fields, fieldItem{
|
||||
Name: varName,
|
||||
Cid: varValue.(cid.Cid),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actStats := actorStats{
|
||||
Address: addr,
|
||||
Actor: actor,
|
||||
}
|
||||
|
||||
dsc := &dagStatCollector{
|
||||
ds: dag,
|
||||
walk: carWalkFunc,
|
||||
}
|
||||
|
||||
if err := merkledag.Walk(ctx, dsc.walkLinks, actor.Head, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
|
||||
return actorStats{}, err
|
||||
}
|
||||
|
||||
actStats.Stats = dsc.stats
|
||||
|
||||
for _, field := range fields {
|
||||
dsc := &dagStatCollector{
|
||||
ds: dag,
|
||||
walk: carWalkFunc,
|
||||
}
|
||||
|
||||
if err := merkledag.Walk(ctx, dsc.walkLinks, field.Cid, cid.NewSet().Visit, merkledag.Concurrent()); err != nil {
|
||||
return actorStats{}, err
|
||||
}
|
||||
|
||||
field.Stats = dsc.stats
|
||||
|
||||
actStats.Fields = append(actStats.Fields, field)
|
||||
}
|
||||
|
||||
return actStats, nil
|
||||
}
|
||||
|
||||
func DumpJSON(i interface{}) error {
|
||||
bs, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(bs))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DumpStats(actStats actorStats) {
|
||||
strtype := builtin.ActorNameByCode(actStats.Actor.Code)
|
||||
fmt.Printf("Address:\t%s\n", actStats.Address)
|
||||
fmt.Printf("Balance:\t%s\n", types.FIL(actStats.Actor.Balance))
|
||||
fmt.Printf("Nonce:\t\t%d\n", actStats.Actor.Nonce)
|
||||
fmt.Printf("Code:\t\t%s (%s)\n", actStats.Actor.Code, strtype)
|
||||
fmt.Printf("Head:\t\t%s\n", actStats.Actor.Head)
|
||||
fmt.Println()
|
||||
|
||||
fmt.Printf("%-*s%-*s%-*s\n", 32, "Field", 24, "Size", 24, "\"Blocks\"")
|
||||
|
||||
stats := actStats.Stats
|
||||
sizeStr := units.BytesSize(float64(stats.Size))
|
||||
fmt.Printf("%-*s%-*s%-*s%-*d\n", 32, "<self>", 10, sizeStr, 14, fmt.Sprintf("(%d)", stats.Size), 24, stats.Links)
|
||||
|
||||
for _, s := range actStats.Fields {
|
||||
stats := s.Stats
|
||||
sizeStr := units.BytesSize(float64(stats.Size))
|
||||
fmt.Printf("%-*s%-*s%-*s%-*d\n", 32, s.Name, 10, sizeStr, 14, fmt.Sprintf("(%d)", stats.Size), 24, stats.Links)
|
||||
}
|
||||
|
||||
fmt.Println("--------------------------------------------------------------------------")
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
lrand "github.com/filecoin-project/lotus/chain/rand"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -85,7 +85,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S
|
||||
Epoch: parentTs.Height() + 1,
|
||||
Rand: r,
|
||||
Bstore: sm.ChainStore().StateBlockstore(),
|
||||
Actors: filcns.NewActorRegistry(),
|
||||
Actors: consensus.NewActorRegistry(),
|
||||
Syscalls: sm.VMSys(),
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NetworkVersion: sm.GetNetworkVersion(ctx, parentTs.Height()+1),
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -105,7 +106,7 @@ func (nd *Node) LoadSim(ctx context.Context, name string) (*Simulation, error) {
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create upgrade schedule for simulation %s: %w", name, err)
|
||||
}
|
||||
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), us, nil)
|
||||
sim.StateManager, err = stmgr.NewStateManager(nd.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), us, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create state manager for simulation %s: %w", name, err)
|
||||
}
|
||||
@@ -124,7 +125,7 @@ func (nd *Node) CreateSim(ctx context.Context, name string, head *types.TipSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sm, err := stmgr.NewStateManager(nd.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
sm, err := stmgr.NewStateManager(nd.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("creating state manager: %w", err)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -200,7 +201,7 @@ func (sim *Simulation) SetUpgradeHeight(nv network.Version, epoch abi.ChainEpoch
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, filcns.NewTipSetExecutor(), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil)
|
||||
sm, err := stmgr.NewStateManager(sim.Node.Chainstore, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(mock.Verifier), newUpgradeSchedule, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
)
|
||||
@@ -103,7 +103,7 @@ func (c *InteractiveWallet) WalletSign(ctx context.Context, k address.Address, m
|
||||
return xerrors.Errorf("looking up dest actor: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][cmsg.Method].Name)
|
||||
fmt.Println("Method:", consensus.NewActorRegistry().Methods[toact.Code][cmsg.Method].Name)
|
||||
p, err := lcli.JsonParams(toact.Code, cmsg.Method, cmsg.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -125,7 +125,7 @@ func (c *InteractiveWallet) WalletSign(ctx context.Context, k address.Address, m
|
||||
return xerrors.Errorf("looking up msig dest actor: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("\tMultiSig Proposal Method:", filcns.NewActorRegistry().Methods[toact.Code][mp.Method].Name) // todo use remote
|
||||
fmt.Println("\tMultiSig Proposal Method:", consensus.NewActorRegistry().Methods[toact.Code][mp.Method].Name) // todo use remote
|
||||
p, err := lcli.JsonParams(toact.Code, mp.Method, mp.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -35,9 +37,11 @@ var setCmd = &cli.Command{
|
||||
}
|
||||
|
||||
var waitQuietCmd = &cli.Command{
|
||||
Name: "wait-quiet",
|
||||
Usage: "Block until all running tasks exit",
|
||||
Name: "wait-quiet",
|
||||
Usage: "Block until all running tasks exit",
|
||||
Hidden: true,
|
||||
Action: func(cctx *cli.Context) error {
|
||||
fmt.Println("DEPRECATED: This command will be removed in the future")
|
||||
api, closer, err := lcli.GetWorkerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -184,25 +184,25 @@ var runCmd = &cli.Command{
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "precommit1",
|
||||
Usage: "enable precommit1 (32G sectors: 1 core, 128GiB Memory)",
|
||||
Usage: "enable precommit1",
|
||||
Value: true,
|
||||
EnvVars: []string{"LOTUS_WORKER_PRECOMMIT1"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "unseal",
|
||||
Usage: "enable unsealing (32G sectors: 1 core, 128GiB Memory)",
|
||||
Usage: "enable unsealing",
|
||||
Value: true,
|
||||
EnvVars: []string{"LOTUS_WORKER_UNSEAL"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "precommit2",
|
||||
Usage: "enable precommit2 (32G sectors: all cores, 96GiB Memory)",
|
||||
Usage: "enable precommit2",
|
||||
Value: true,
|
||||
EnvVars: []string{"LOTUS_WORKER_PRECOMMIT2"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "commit",
|
||||
Usage: "enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap)",
|
||||
Usage: "enable commit",
|
||||
Value: true,
|
||||
EnvVars: []string{"LOTUS_WORKER_COMMIT"},
|
||||
},
|
||||
@@ -257,7 +257,7 @@ var runCmd = &cli.Command{
|
||||
&cli.IntFlag{
|
||||
Name: "post-parallel-reads",
|
||||
Usage: "maximum number of parallel challenge reads (0 = no limit)",
|
||||
Value: 128,
|
||||
Value: 32,
|
||||
EnvVars: []string{"LOTUS_WORKER_POST_PARALLEL_READS"},
|
||||
},
|
||||
&cli.DurationFlag{
|
||||
|
||||
+42
-13
@@ -44,33 +44,53 @@ var settableStr = func() string {
|
||||
var tasksEnableCmd = &cli.Command{
|
||||
Name: "enable",
|
||||
Usage: "Enable a task type",
|
||||
ArgsUsage: "[" + settableStr + "]",
|
||||
Action: taskAction(api.Worker.TaskEnable),
|
||||
ArgsUsage: "--all | [" + settableStr + "]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "Enable all task types",
|
||||
},
|
||||
},
|
||||
Action: taskAction(api.Worker.TaskEnable),
|
||||
}
|
||||
|
||||
var tasksDisableCmd = &cli.Command{
|
||||
Name: "disable",
|
||||
Usage: "Disable a task type",
|
||||
ArgsUsage: "[" + settableStr + "]",
|
||||
Action: taskAction(api.Worker.TaskDisable),
|
||||
ArgsUsage: "--all | [" + settableStr + "]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "Disable all task types",
|
||||
},
|
||||
},
|
||||
Action: taskAction(api.Worker.TaskDisable),
|
||||
}
|
||||
|
||||
func taskAction(tf func(a api.Worker, ctx context.Context, tt sealtasks.TaskType) error) func(cctx *cli.Context) error {
|
||||
return func(cctx *cli.Context) error {
|
||||
if cctx.NArg() != 1 {
|
||||
return xerrors.Errorf("expected 1 argument")
|
||||
allFlag := cctx.Bool("all")
|
||||
|
||||
if cctx.NArg() == 1 && allFlag {
|
||||
return xerrors.Errorf("Cannot use --all flag with task type argument")
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 && !allFlag {
|
||||
return xerrors.Errorf("Expected 1 argument or use --all flag")
|
||||
}
|
||||
|
||||
var tt sealtasks.TaskType
|
||||
for taskType := range allowSetting {
|
||||
if taskType.Short() == cctx.Args().First() {
|
||||
tt = taskType
|
||||
break
|
||||
if cctx.NArg() == 1 {
|
||||
for taskType := range allowSetting {
|
||||
if taskType.Short() == cctx.Args().First() {
|
||||
tt = taskType
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tt == "" {
|
||||
return xerrors.Errorf("unknown task type '%s'", cctx.Args().First())
|
||||
if tt == "" {
|
||||
return xerrors.Errorf("unknown task type '%s'", cctx.Args().First())
|
||||
}
|
||||
}
|
||||
|
||||
api, closer, err := lcli.GetWorkerAPI(cctx)
|
||||
@@ -81,6 +101,15 @@ func taskAction(tf func(a api.Worker, ctx context.Context, tt sealtasks.TaskType
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
if allFlag {
|
||||
for taskType := range allowSetting {
|
||||
if err := tf(api, ctx, taskType); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return tf(api, ctx, tt)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -33,6 +33,7 @@ import (
|
||||
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -539,7 +540,7 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
||||
}
|
||||
|
||||
// TODO: We need to supply the actual beacon after v14
|
||||
stm, err := stmgr.NewStateManager(cst, filcns.NewTipSetExecutor(), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
stm, err := stmgr.NewStateManager(cst, consensus.NewTipSetExecutor(filcns.RewardFunc), vm.Syscalls(ffiwrapper.ProofVerifier), filcns.DefaultUpgradeSchedule(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -52,6 +53,10 @@ func main() {
|
||||
}
|
||||
jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name)
|
||||
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if originBefore != nil {
|
||||
return originBefore(cctx)
|
||||
}
|
||||
@@ -75,6 +80,12 @@ func main() {
|
||||
Hidden: true,
|
||||
Value: "~/.lotus", // should follow --repo default
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
// examined in the Before above
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
EnvVars: []string{"LOTUS_PATH"},
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
)
|
||||
|
||||
var extractManyFlags struct {
|
||||
@@ -159,7 +159,7 @@ func runExtractMany(c *cli.Context) error {
|
||||
}
|
||||
|
||||
// Lookup the method in actor method table.
|
||||
if m, ok := filcns.NewActorRegistry().Methods[codeCid]; !ok {
|
||||
if m, ok := consensus.NewActorRegistry().Methods[codeCid]; !ok {
|
||||
return fmt.Errorf("unrecognized actor: %s", actorcode)
|
||||
} else if methodnum >= len(m) {
|
||||
return fmt.Errorf("unrecognized method number for actor %s: %d", actorcode, methodnum)
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -106,7 +107,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
||||
syscalls = vm.Syscalls(ffiwrapper.ProofVerifier)
|
||||
|
||||
cs = store.NewChainStore(bs, bs, ds, filcns.Weight, nil)
|
||||
tse = filcns.NewTipSetExecutor()
|
||||
tse = consensus.NewTipSetExecutor(filcns.RewardFunc)
|
||||
sm, err = stmgr.NewStateManager(cs, tse, syscalls, filcns.DefaultUpgradeSchedule(), nil)
|
||||
)
|
||||
if err != nil {
|
||||
@@ -123,7 +124,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
||||
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
blocks := make([]filcns.FilecoinBlockMessages, 0, len(tipset.Blocks))
|
||||
blocks := make([]consensus.FilecoinBlockMessages, 0, len(tipset.Blocks))
|
||||
for _, b := range tipset.Blocks {
|
||||
sb := store.BlockMessages{
|
||||
Miner: b.MinerAddr,
|
||||
@@ -145,7 +146,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params
|
||||
sb.BlsMessages = append(sb.BlsMessages, msg)
|
||||
}
|
||||
}
|
||||
blocks = append(blocks, filcns.FilecoinBlockMessages{
|
||||
blocks = append(blocks, consensus.FilecoinBlockMessages{
|
||||
BlockMessages: sb,
|
||||
WinCount: b.WinCount,
|
||||
})
|
||||
@@ -265,7 +266,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
|
||||
invoker := filcns.NewActorRegistry()
|
||||
invoker := consensus.NewActorRegistry()
|
||||
av, _ := actorstypes.VersionForNetwork(params.NetworkVersion)
|
||||
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{chaos.Actor{}})
|
||||
invoker.Register(av, nil, registry)
|
||||
@@ -283,7 +284,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
invoker := filcns.NewActorRegistry()
|
||||
invoker := consensus.NewActorRegistry()
|
||||
lvm.SetInvoker(invoker)
|
||||
vmi = lvm
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Genesis block
|
||||
|
||||
Seems a good way to start exploring the VM state though the instantiation of its different actors like the storage power.
|
||||
Seems a good way to start exploring the VM state through the instantiation of its different actors like the storage power.
|
||||
|
||||
Explain where do we load the genesis block, the CAR entries, and we set the root of the state. Follow the daemon command option, `chain.LoadGenesis()` saves all the blocks of the CAR file into the store provided by `ChainBlockstore` (this should already be explained in the previous section). The CAR root (MT root?) of those blocks is decoded into the `BlockHeader` that will be the Filecoin (genesis) block of the chain, but most of the information was stored in the raw data (non-Filecoin, what's the correct term?) blocks forwarded directly to the chain, the block header just has a pointer to it.
|
||||
Explain where we load the genesis block, the CAR entries, and we set the root of the state. Follow the daemon command option, `chain.LoadGenesis()` saves all the blocks of the CAR file into the store provided by `ChainBlockstore` (this should already be explained in the previous section). The CAR root (MT root?) of those blocks is decoded into the `BlockHeader` that will be the Filecoin (genesis) block of the chain, but most of the information was stored in the raw data (non-Filecoin, what's the correct term?) blocks forwarded directly to the chain, the block header just has a pointer to it.
|
||||
|
||||
`SetGenesis` block with name 0. `(ChainStore).SetGenesis()` stores it there.
|
||||
|
||||
`MakeInitialStateTree` (`chain/gen/genesis/genesis.go`, used to construct the genesis block (`MakeGenesisBlock()`), constructs the state tree (`NewStateTree`) which is just a "pointer" (root node in the HAMT) to the different actors. It will be continuously used in `(*StateTree).SetActor()` an `types.Actor` structure under a certain `Address` (in the HAMT). (How does the `stateSnaps` work? It has no comments.)
|
||||
|
||||
From this point we can follow different setup function like:
|
||||
From this point we can follow different setup functions like:
|
||||
|
||||
* `SetupInitActor()`: see the `AddressMap`.
|
||||
|
||||
@@ -40,7 +40,7 @@ List what are the main directories we should be looking at (e.g., `chain/`) and
|
||||
|
||||
# Tests
|
||||
|
||||
Run a few messages and observe state changes. What is the easiest test that also let's us "interact" with it (modify something and observe the difference).
|
||||
Run a few messages and observe state changes. What is the easiest test that also lets us "interact" with it (modify something and observe the difference).
|
||||
|
||||
### Filecoin blocks vs IPFS blocks
|
||||
|
||||
@@ -84,7 +84,7 @@ func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
|
||||
These edited extracts from the `BlockHeader` show how it's treated as an IPFS block, `github.com/ipfs/go-block-format.block.BasicBlock`, to be both stored and referenced by its block storage CID.
|
||||
|
||||
This duality permeates the code (and the Filecoin spec for that matter) but it is usually clear within the context to which block we are referring to. Normally the unqualified *block* is reserved for the Filecoin block and we won't usually refer to the IPFS one but only implicitly through the concept of its CID. With enough understanding of both stack's architecture the two definitions can coexist without much confusion as we will abstract away the IPFS layer and just use the CID as an identifier that we now its unique for two sequences of different *raw* byte strings.
|
||||
This duality permeates the code (and the Filecoin spec for that matter) but it is usually clear within the context to which block we are referring to. Normally the unqualified *block* is reserved for the Filecoin block and we won't usually refer to the IPFS one but only implicitly through the concept of its CID. With enough understanding of both stack's architecture the two definitions can coexist without much confusion as we will abstract away the IPFS layer and just use the CID as an identifier that we know is unique for two sequences of different *raw* byte strings.
|
||||
|
||||
(FIXME: We use to do this presentation when talking about `gossipsub` topics and incoming blocks, and had to deal with, besides the block ambiguity, a similar confusion with the *message* term, used in libp2p to name anything that comes through the network, needing to present the extremely confusing hierarchy of a libp2p message containing a Filecoin block, identified by a IPFS block CID, containing Filecoin messages.)
|
||||
|
||||
@@ -150,4 +150,4 @@ Because we rely heavily on reflection for this part of the code the call chain i
|
||||
|
||||
This means that when we are tracking the logic of a CLI command we will eventually find this bifurcation and need to study the code of the server-side implementation in `node/impl/full` (mostly in the `common/` and `full/` directories). If we understand this architecture going directly to that part of the code abstracts away the JSON-RPC client/server logic and we can think that the CLI is actually running the node's logic.
|
||||
|
||||
FIXME: Explain that "*the* node" is actually an API structure like `impl.FullNodeAPI` with the different API subcomponents like `full.SyncAPI`. We won't see a *single* node structure, each API (full node, minder, etc) will gather the necessary subcomponents it needs to service its calls.
|
||||
FIXME: Explain that "*the* node" is actually an API structure like `impl.FullNodeAPI` with the different API subcomponents like `full.SyncAPI`. We won't see a *single* node structure, each API (full node, minder, etc) will gather the necessary subcomponents it needs to service its calls.
|
||||
|
||||
@@ -5,7 +5,7 @@ Lotus is an implementation of the **Filecoin Distributed Storage Network**.
|
||||
It is written in Go and provides a suite of command-line applications:
|
||||
|
||||
- Lotus Node (`lotus`): a Filecoin Node: validates network transactions, manages a FIL wallet, can perform storage and retrieval deals.
|
||||
- Lotus Miner (`lotus-miner`): a Filecoin miner. See the the respective Lotus Miner section in the Mine documentation.
|
||||
- Lotus Miner (`lotus-miner`): a Filecoin miner. See the respective Lotus Miner section in the Mine documentation.
|
||||
- Lotus Worker (`lotus-worker`): a worker that assists miners to perform mining-related tasks. See its respective guide for more information.
|
||||
|
||||
The [Lotus user documentation](https://lotus.filecoin.io/lotus/get-started/what-is-lotus/) is part of the [Filecoin documentation site](https://lotus.filecoin.io):
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* [ChainCheckBlockstore](#ChainCheckBlockstore)
|
||||
* [ChainDeleteObj](#ChainDeleteObj)
|
||||
* [ChainExport](#ChainExport)
|
||||
* [ChainExportRangeInternal](#ChainExportRangeInternal)
|
||||
* [ChainGetBlock](#ChainGetBlock)
|
||||
* [ChainGetBlockMessages](#ChainGetBlockMessages)
|
||||
* [ChainGetEvents](#ChainGetEvents)
|
||||
@@ -475,6 +476,50 @@ Inputs:
|
||||
|
||||
Response: `"Ynl0ZSBhcnJheQ=="`
|
||||
|
||||
### ChainExportRangeInternal
|
||||
ChainExportRangeInternal triggers the export of a chain
|
||||
CAR-snapshot directly to disk. It is similar to ChainExport,
|
||||
except, depending on options, the snapshot can include receipts,
|
||||
messages and stateroots for the length between the specified head
|
||||
and tail, thus producing "archival-grade" snapshots that include
|
||||
all the on-chain data. The header chain is included back to
|
||||
genesis and these snapshots can be used to initialize Filecoin
|
||||
nodes.
|
||||
|
||||
|
||||
Perms: admin
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
],
|
||||
{
|
||||
"WriteBufferSize": 123,
|
||||
"NumWorkers": 123,
|
||||
"IncludeMessages": true,
|
||||
"IncludeReceipts": true,
|
||||
"IncludeStateRoots": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Response: `{}`
|
||||
|
||||
### ChainGetBlock
|
||||
ChainGetBlock returns the block specified by the given CID.
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ Note: The API refers to these stages as `StageHeaders` and `StagePersistHeaders`
|
||||
|
||||
We proceed in the sync process by requesting block headers from the peer,
|
||||
moving back from their head, until we reach a tipset that we have in common
|
||||
(such a common tipset must exist, thought it may simply be the genesis block).
|
||||
(such a common tipset must exist, though it may simply be the genesis block).
|
||||
The functionality can be found in `Syncer::collectHeaders()`.
|
||||
|
||||
If the common tipset is our head, we treat the sync as a "fast-forward", else we must
|
||||
@@ -126,7 +126,7 @@ If all validations pass we will now set that head as our heaviest tipset in
|
||||
We already have the full state, since we calculated
|
||||
it during the sync process.
|
||||
|
||||
FIXME (aayush) I don't fuilly understand the next 2 paragraphs, but it seems important. Confirm and polish.
|
||||
FIXME (aayush) I don't fully understand the next 2 paragraphs, but it seems important. Confirm and polish.
|
||||
Relevant issue in IPFS: https://github.com/ipfs/ipfs-docs/issues/264
|
||||
|
||||
It is important to note at this point that similar to the IPFS architecture of addressing by content and not by location/address (FIXME: check and link to IPFS docs) the "actual" chain stored in the node repo is *relative* to which CID we look for. We always have stored a series of Filecoin blocks pointing to other blocks, each a potential chain in itself by following its parent's reference, and its parent's parent, and so on up to the genesis block. (FIXME: We need a diagram here, one of the Filecoin blog entries might have something similar to what we are describing here.) It only depends on *where* (location) do we start to look for. The *only* address/location reference we hold of the chain, a relative reference, is the `heaviest` pointer. This is reflected by the fact that we don't store it in the `Blockstore` by a fixed, *absolute*, CID that reflects its contents, as this will change each time we sync to a new head (FIXME: link to the immutability IPFS doc that I need to write).
|
||||
@@ -149,7 +149,7 @@ encapsulated in the [`StateTree`](https://github.com/filecoin-project/lotus/blob
|
||||
and accessed through the
|
||||
[`StateManager`](https://github.com/filecoin-project/lotus/blob/master/chain/stmgr/stmgr.go).
|
||||
The state at the chain's head is thus easily tracked and updated in a state root CID.
|
||||
(FIXME: Talk about CIDs somewhere, we might want to explain some of the modify/flush/update-root mechanism here.))
|
||||
(FIXME: Talk about CIDs somewhere, we might want to explain some of the modify/flush/update-root mechanism here.)
|
||||
|
||||
## Calculating a Tipset State
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Assemble a `FullTipSet` populated with the single block received earlier.
|
||||
|
||||
`(*Syncer).collectHeaders()`: we retrieve all tipsets from the received block down to our chain. Validation now is expanded to *every* block inside these tipsets.
|
||||
|
||||
`V`: Beacon entires are ordered by their round number.
|
||||
`V`: Beacon entries are ordered by their round number.
|
||||
|
||||
`V:` Tipset `Parents` CIDs match the fetched parent tipset through block sync. (This check is not enforced correctly at the moment, see [issue](https://github.com/filecoin-project/lotus/issues/1918).)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE:
|
||||
lotus-miner [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.20.0
|
||||
1.21.0-dev
|
||||
|
||||
COMMANDS:
|
||||
init Initialize a lotus miner repo
|
||||
@@ -286,7 +286,7 @@ NAME:
|
||||
lotus-miner actor set-peer-id - set the peer id of your miner
|
||||
|
||||
USAGE:
|
||||
lotus-miner actor set-peer-id [command options] [arguments...]
|
||||
lotus-miner actor set-peer-id [command options] <peer id>
|
||||
|
||||
OPTIONS:
|
||||
--gas-limit value set gas limit (default: 0)
|
||||
@@ -333,7 +333,6 @@ USAGE:
|
||||
lotus-miner actor control list [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--verbose (default: false)
|
||||
|
||||
```
|
||||
@@ -980,7 +979,6 @@ USAGE:
|
||||
lotus-miner data-transfers list [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--completed show completed data transfers (default: false)
|
||||
--show-failed show failed/cancelled transfers (default: false)
|
||||
--verbose, -v print verbose transfer details (default: false)
|
||||
@@ -1062,7 +1060,7 @@ USAGE:
|
||||
lotus-miner dagstore list-shards [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1075,7 +1073,7 @@ USAGE:
|
||||
lotus-miner dagstore register-shard [command options] [key]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1088,7 +1086,7 @@ USAGE:
|
||||
lotus-miner dagstore initialize-shard [command options] [key]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1101,7 +1099,7 @@ USAGE:
|
||||
lotus-miner dagstore recover-shard [command options] [key]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1114,7 +1112,6 @@ USAGE:
|
||||
lotus-miner dagstore initialize-all [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--concurrency value maximum shards to initialize concurrently at a time; use 0 for unlimited (default: 0)
|
||||
--include-sealed initialize sealed pieces as well (default: false)
|
||||
|
||||
@@ -1129,7 +1126,7 @@ USAGE:
|
||||
lotus-miner dagstore gc [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1142,7 +1139,7 @@ USAGE:
|
||||
lotus-miner dagstore lookup-pieces [command options] <cid>
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1173,7 +1170,7 @@ USAGE:
|
||||
lotus-miner index announce [command options] <deal proposal cid>
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1186,7 +1183,7 @@ USAGE:
|
||||
lotus-miner index announce-all [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1677,14 +1674,13 @@ COMMANDS:
|
||||
precommits Print on-chain precommit info
|
||||
check-expire Inspect expiring sectors
|
||||
expired Get or cleanup expired sectors
|
||||
renew Renew expiring sectors while not exceeding each sector's max life
|
||||
extend Extend sector expiration
|
||||
extend Extend expiring sectors while not exceeding each sector's max life
|
||||
terminate Terminate sector on-chain then remove (WARNING: This means losing power and collateral for the removed sector)
|
||||
remove Forcefully remove a sector (WARNING: This means losing power and collateral for the removed sector (use 'terminate' for lower penalty))
|
||||
snap-up Mark a committed capacity sector to be filled with deals
|
||||
abort-upgrade Abort the attempted (SnapDeals) upgrade of a CC sector, reverting it to as before
|
||||
seal Manually start sealing a sector (filling any unused space with junk)
|
||||
set-seal-delay Set the time, in minutes, that a new sector waits for deals before sealing starts
|
||||
set-seal-delay Set the time (in minutes) that a new sector waits for deals before sealing starts
|
||||
get-cc-collateral Get the collateral required to pledge a committed capacity sector
|
||||
batching manage batch sector operations
|
||||
match-pending-pieces force a refreshed match of pending pieces to open sectors without manually waiting for more deals
|
||||
@@ -1721,14 +1717,14 @@ USAGE:
|
||||
lotus-miner sectors list [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color, -c use color in display output (default: depends on output being a TTY)
|
||||
--events, -e display number of events the sector has received (default: false)
|
||||
--fast, -f don't show on-chain info for better performance (default: false)
|
||||
--initial-pledge, -p display initial pledge (default: false)
|
||||
--seal-time, -t display how long it took for the sector to be sealed (default: false)
|
||||
--show-removed, -r show removed sectors (default: false)
|
||||
--states value filter sectors by a comma-separated list of states
|
||||
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
|
||||
--check-parallelism value number of parallel requests to make for checking sector states (default: 300)
|
||||
--events, -e display number of events the sector has received (default: false)
|
||||
--fast, -f don't show on-chain info for better performance (default: false)
|
||||
--initial-pledge, -p display initial pledge (default: false)
|
||||
--seal-time, -t display how long it took for the sector to be sealed (default: false)
|
||||
--show-removed, -r show removed sectors (default: false)
|
||||
--states value filter sectors by a comma-separated list of states
|
||||
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -1884,13 +1880,13 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
### lotus-miner sectors renew
|
||||
### lotus-miner sectors extend
|
||||
```
|
||||
NAME:
|
||||
lotus-miner sectors renew - Renew expiring sectors while not exceeding each sector's max life
|
||||
lotus-miner sectors extend - Extend expiring sectors while not exceeding each sector's max life
|
||||
|
||||
USAGE:
|
||||
lotus-miner sectors renew [command options] [arguments...]
|
||||
lotus-miner sectors extend [command options] <sectorNumbers...(optional)>
|
||||
|
||||
OPTIONS:
|
||||
--exclude value optionally provide a file containing excluding sectors
|
||||
@@ -1900,31 +1896,13 @@ OPTIONS:
|
||||
--max-sectors value the maximum number of sectors contained in each message message (default: 0)
|
||||
--new-expiration value try to extend selected sectors to this epoch, ignoring extension (default: 0)
|
||||
--only-cc only extend CC sectors (useful for making sector ready for snap upgrade) (default: false)
|
||||
--really-do-it pass this flag to really renew sectors, otherwise will only print out json representation of parameters (default: false)
|
||||
--really-do-it pass this flag to really extend sectors, otherwise will only print out json representation of parameters (default: false)
|
||||
--sector-file value provide a file containing one sector number in each line, ignoring above selecting criteria
|
||||
--to value only consider sectors whose current expiration epoch is in the range of [from, to], <to> defaults to: now + 92160 (32 days) (default: 0)
|
||||
--tolerance value don't try to extend sectors by fewer than this number of epochs, defaults to 7 days (default: 20160)
|
||||
|
||||
```
|
||||
|
||||
### lotus-miner sectors extend
|
||||
```
|
||||
NAME:
|
||||
lotus-miner sectors extend - Extend sector expiration
|
||||
|
||||
USAGE:
|
||||
lotus-miner sectors extend [command options] <sectorNumbers...>
|
||||
|
||||
OPTIONS:
|
||||
|
||||
--expiration-cutoff value when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified) (default: 0)
|
||||
--expiration-ignore value when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now (default: 120)
|
||||
--new-expiration value new expiration epoch (default: 0)
|
||||
--tolerance value when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs (default: 20160)
|
||||
--v1-sectors renews all v1 sectors up to the maximum possible lifetime (default: false)
|
||||
|
||||
```
|
||||
|
||||
### lotus-miner sectors terminate
|
||||
```
|
||||
NAME:
|
||||
@@ -2025,13 +2003,13 @@ OPTIONS:
|
||||
### lotus-miner sectors set-seal-delay
|
||||
```
|
||||
NAME:
|
||||
lotus-miner sectors set-seal-delay - Set the time, in minutes, that a new sector waits for deals before sealing starts
|
||||
lotus-miner sectors set-seal-delay - Set the time (in minutes) that a new sector waits for deals before sealing starts
|
||||
|
||||
USAGE:
|
||||
lotus-miner sectors set-seal-delay [command options] <minutes>
|
||||
lotus-miner sectors set-seal-delay [command options] <time>
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
--seconds Specifies that the time argument should be in seconds (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -2223,7 +2201,7 @@ USAGE:
|
||||
lotus-miner proving workers [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -2296,7 +2274,7 @@ NAME:
|
||||
lotus-miner storage attach - attach local storage path
|
||||
|
||||
USAGE:
|
||||
lotus-miner storage attach [command options] [arguments...]
|
||||
lotus-miner storage attach [command options] [path]
|
||||
|
||||
DESCRIPTION:
|
||||
Storage can be attached to the miner using this command. The storage volume
|
||||
@@ -2349,7 +2327,7 @@ NAME:
|
||||
lotus-miner storage redeclare - redeclare sectors in a local storage path
|
||||
|
||||
USAGE:
|
||||
lotus-miner storage redeclare [command options] [arguments...]
|
||||
lotus-miner storage redeclare [command options] [path]
|
||||
|
||||
OPTIONS:
|
||||
--all redeclare all storage paths (default: false)
|
||||
@@ -2371,7 +2349,6 @@ COMMANDS:
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
@@ -2385,7 +2362,7 @@ USAGE:
|
||||
lotus-miner storage list sectors [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -2458,7 +2435,6 @@ USAGE:
|
||||
lotus-miner sealing jobs [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--show-ret-done show returned but not consumed calls (default: false)
|
||||
|
||||
```
|
||||
@@ -2472,7 +2448,7 @@ USAGE:
|
||||
lotus-miner sealing workers [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -7,18 +7,17 @@ USAGE:
|
||||
lotus-worker [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.20.0
|
||||
1.21.0-dev
|
||||
|
||||
COMMANDS:
|
||||
run Start lotus worker
|
||||
stop Stop a running lotus worker
|
||||
info Print worker info
|
||||
storage manage sector storage
|
||||
set Manage worker settings
|
||||
wait-quiet Block until all running tasks exit
|
||||
resources Manage resource table overrides
|
||||
tasks Manage task processing
|
||||
help, h Shows a list of commands or help for one command
|
||||
run Start lotus worker
|
||||
stop Stop a running lotus worker
|
||||
info Print worker info
|
||||
storage manage sector storage
|
||||
set Manage worker settings
|
||||
resources Manage resource table overrides
|
||||
tasks Manage task processing
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--enable-gpu-proving enable use of GPU for mining operations (default: true) [$LOTUS_WORKER_ENABLE_GPU_PROVING]
|
||||
@@ -39,7 +38,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
--addpiece enable addpiece (default: true) [$LOTUS_WORKER_ADDPIECE]
|
||||
--commit enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap) (default: true) [$LOTUS_WORKER_COMMIT]
|
||||
--commit enable commit (default: true) [$LOTUS_WORKER_COMMIT]
|
||||
--http-server-timeout value (default: "30s")
|
||||
--listen value host address and port the worker api will listen on (default: "0.0.0.0:3456") [$LOTUS_WORKER_LISTEN]
|
||||
--name value custom worker name (default: hostname) [$LOTUS_WORKER_NAME]
|
||||
@@ -47,16 +46,16 @@ OPTIONS:
|
||||
--no-local-storage don't use storageminer repo for sector storage (default: false) [$LOTUS_WORKER_NO_LOCAL_STORAGE]
|
||||
--no-swap don't use swap (default: false) [$LOTUS_WORKER_NO_SWAP]
|
||||
--parallel-fetch-limit value maximum fetch operations to run in parallel (default: 5) [$LOTUS_WORKER_PARALLEL_FETCH_LIMIT]
|
||||
--post-parallel-reads value maximum number of parallel challenge reads (0 = no limit) (default: 128) [$LOTUS_WORKER_POST_PARALLEL_READS]
|
||||
--post-parallel-reads value maximum number of parallel challenge reads (0 = no limit) (default: 32) [$LOTUS_WORKER_POST_PARALLEL_READS]
|
||||
--post-read-timeout value time limit for reading PoSt challenges (0 = no limit) (default: 0s) [$LOTUS_WORKER_POST_READ_TIMEOUT]
|
||||
--precommit1 enable precommit1 (32G sectors: 1 core, 128GiB Memory) (default: true) [$LOTUS_WORKER_PRECOMMIT1]
|
||||
--precommit2 enable precommit2 (32G sectors: all cores, 96GiB Memory) (default: true) [$LOTUS_WORKER_PRECOMMIT2]
|
||||
--precommit1 enable precommit1 (default: true) [$LOTUS_WORKER_PRECOMMIT1]
|
||||
--precommit2 enable precommit2 (default: true) [$LOTUS_WORKER_PRECOMMIT2]
|
||||
--prove-replica-update2 enable prove replica update 2 (default: true) [$LOTUS_WORKER_PROVE_REPLICA_UPDATE2]
|
||||
--regen-sector-key enable regen sector key (default: true) [$LOTUS_WORKER_REGEN_SECTOR_KEY]
|
||||
--replica-update enable replica update (default: true) [$LOTUS_WORKER_REPLICA_UPDATE]
|
||||
--sector-download enable external sector data download (default: false) [$LOTUS_WORKER_SECTOR_DOWNLOAD]
|
||||
--timeout value used when 'listen' is unspecified. must be a valid duration recognized by golang's time.ParseDuration function (default: "30m") [$LOTUS_WORKER_TIMEOUT]
|
||||
--unseal enable unsealing (32G sectors: 1 core, 128GiB Memory) (default: true) [$LOTUS_WORKER_UNSEAL]
|
||||
--unseal enable unsealing (default: true) [$LOTUS_WORKER_UNSEAL]
|
||||
--windowpost enable window post (default: false) [$LOTUS_WORKER_WINDOWPOST]
|
||||
--winningpost enable winning post (default: false) [$LOTUS_WORKER_WINNINGPOST]
|
||||
|
||||
@@ -167,19 +166,6 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
## lotus-worker wait-quiet
|
||||
```
|
||||
NAME:
|
||||
lotus-worker wait-quiet - Block until all running tasks exit
|
||||
|
||||
USAGE:
|
||||
lotus-worker wait-quiet [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
## lotus-worker resources
|
||||
```
|
||||
NAME:
|
||||
@@ -218,10 +204,10 @@ NAME:
|
||||
lotus-worker tasks enable - Enable a task type
|
||||
|
||||
USAGE:
|
||||
lotus-worker tasks enable [command options] [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
|
||||
lotus-worker tasks enable [command options] --all | [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
--all Enable all task types (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -231,9 +217,9 @@ NAME:
|
||||
lotus-worker tasks disable - Disable a task type
|
||||
|
||||
USAGE:
|
||||
lotus-worker tasks disable [command options] [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
|
||||
lotus-worker tasks disable [command options] --all | [UNS|C2|PC2|PC1|PR2|RU|AP|DC|GSK]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
--all Disable all task types (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE:
|
||||
lotus [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.20.0
|
||||
1.21.0-dev
|
||||
|
||||
COMMANDS:
|
||||
daemon Start a lotus daemon process
|
||||
@@ -39,6 +39,7 @@ COMMANDS:
|
||||
status Check node status
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--force-send if true, will ignore pre-send checks (default: false)
|
||||
--help, -h show help (default: false)
|
||||
--interactive setting to false will disable interactive functionality of commands (default: false)
|
||||
@@ -687,7 +688,6 @@ CATEGORY:
|
||||
RETRIEVAL
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--completed show completed retrievals (default: false)
|
||||
--show-failed show failed/failing deals (default: true)
|
||||
--verbose, -v print verbose deal details (default: false)
|
||||
@@ -758,7 +758,6 @@ CATEGORY:
|
||||
STORAGE
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--show-failed show failed/failing deals (default: false)
|
||||
--verbose, -v print verbose deal details (default: false)
|
||||
--watch watch deal updates in real-time, rather than a one time list (default: false)
|
||||
@@ -891,7 +890,6 @@ CATEGORY:
|
||||
UTIL
|
||||
|
||||
OPTIONS:
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--completed show completed data transfers (default: false)
|
||||
--show-failed show failed/cancelled transfers (default: false)
|
||||
--verbose, -v print verbose transfer details (default: false)
|
||||
@@ -905,7 +903,7 @@ NAME:
|
||||
lotus client restart-transfer - Force restart a stalled data transfer
|
||||
|
||||
USAGE:
|
||||
lotus client restart-transfer [command options] [arguments...]
|
||||
lotus client restart-transfer [command options] [transferID]
|
||||
|
||||
CATEGORY:
|
||||
UTIL
|
||||
@@ -922,7 +920,7 @@ NAME:
|
||||
lotus client cancel-transfer - Force cancel a data transfer
|
||||
|
||||
USAGE:
|
||||
lotus client cancel-transfer [command options] [arguments...]
|
||||
lotus client cancel-transfer [command options] [transferID]
|
||||
|
||||
CATEGORY:
|
||||
UTIL
|
||||
@@ -1212,7 +1210,9 @@ COMMANDS:
|
||||
check-notary-datacap check a notary's remaining bytes
|
||||
sign-remove-data-cap-proposal allows a notary to sign a Remove Data Cap Proposal
|
||||
list-allocations List allocations made by client
|
||||
list-claims List claims made by provider
|
||||
remove-expired-allocations remove expired allocations (if no allocations are specified all eligible allocations are removed)
|
||||
remove-expired-claims remove expired claims (if no claims are specified all eligible claims are removed)
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
OPTIONS:
|
||||
@@ -1311,6 +1311,19 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
### lotus filplus list-claims
|
||||
```
|
||||
NAME:
|
||||
lotus filplus list-claims - List claims made by provider
|
||||
|
||||
USAGE:
|
||||
lotus filplus list-claims [command options] providerAddress
|
||||
|
||||
OPTIONS:
|
||||
--expired list only expired claims (default: false)
|
||||
|
||||
```
|
||||
|
||||
### lotus filplus remove-expired-allocations
|
||||
```
|
||||
NAME:
|
||||
@@ -1324,6 +1337,19 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
### lotus filplus remove-expired-claims
|
||||
```
|
||||
NAME:
|
||||
lotus filplus remove-expired-claims - remove expired claims (if no claims are specified all eligible claims are removed)
|
||||
|
||||
USAGE:
|
||||
lotus filplus remove-expired-claims [command options] providerAddress Optional[...claimId]
|
||||
|
||||
OPTIONS:
|
||||
--from value optionally specify the account to send the message from
|
||||
|
||||
```
|
||||
|
||||
## lotus paych
|
||||
```
|
||||
NAME:
|
||||
@@ -2005,7 +2031,7 @@ NAME:
|
||||
lotus state market balance - Get the market balance (locked and escrowed) for a given account
|
||||
|
||||
USAGE:
|
||||
lotus state market balance [command options] [arguments...]
|
||||
lotus state market balance [command options] [address]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
@@ -2084,6 +2110,7 @@ COMMANDS:
|
||||
get Get chain DAG node by path
|
||||
bisect bisect chain for an event
|
||||
export export chain to a car file
|
||||
export-range export chain to a car file
|
||||
slash-consensus Report consensus fault
|
||||
gas-price Estimate gas prices
|
||||
inspect-usage Inspect block space usage of a given tipset
|
||||
@@ -2265,6 +2292,25 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
### lotus chain export-range
|
||||
```
|
||||
NAME:
|
||||
lotus chain export-range - export chain to a car file
|
||||
|
||||
USAGE:
|
||||
lotus chain export-range [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--head value specify tipset to start the export from (higher epoch) (default: "@head")
|
||||
--messages specify if messages should be include (default: false)
|
||||
--receipts specify if receipts should be include (default: false)
|
||||
--stateroots specify if stateroots should be include (default: false)
|
||||
--tail value specify tipset to end the export at (lower epoch) (default: "@tail")
|
||||
--workers value specify the number of workers (default: 1)
|
||||
--write-buffer value specify write buffer size (default: 1048576)
|
||||
|
||||
```
|
||||
|
||||
### lotus chain slash-consensus
|
||||
```
|
||||
NAME:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This document explains the code flow of the [storage miner](https://filecoin-project.github.io/specs/#systems__filecoin_mining) creation process. It describes the flow on two dimensions: at the network level, from the local node to the rest of the Filecoin network, and at the VM level, from the CLI commands to the new chain state. It assumes the reader is already familiar with the general Lotus [architecture](architecture-2.md), relying especially on the descriptions of the CLI/API interface and the VM chain state.
|
||||
|
||||
Note we are not following the [Storage Mining](https://lotu.sh/en+mining) user documentation where the miner is created along with the owner through the faucet, but we do those in separate stages try to exercise what will be the closest code path to Mainnet, using the `createStorageMiner()` call in the CLI (when `--actor` is not provided).
|
||||
Note we are not following the [Storage Mining](https://lotu.sh/en+mining) user documentation where the miner is created along with the owner through the faucet, but we do those in separate stages to try to exercise what will be the closest code path to Mainnet, using the `createStorageMiner()` call in the CLI (when `--actor` is not provided).
|
||||
|
||||
FIXME: Check that all the information it assumes throughout this document is actually present in the main architecture doc.
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@
|
||||
#
|
||||
# type: int
|
||||
# env var: LOTUS_PROVING_PARALLELCHECKLIMIT
|
||||
#ParallelCheckLimit = 128
|
||||
#ParallelCheckLimit = 32
|
||||
|
||||
# Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped
|
||||
#
|
||||
|
||||
@@ -19,7 +19,7 @@ Now go to `http://127.0.0.1:2222`.
|
||||
## What can I test?
|
||||
|
||||
- The `Spawn Node` button starts a new **Lotus Node** in a new draggable window.
|
||||
- Click `[Spawn Miner]` to start a **Lotus Miner**. This require's the node's wallet to have funds.
|
||||
- Click `[Spawn Miner]` to start a **Lotus Miner**. This requires the node's wallet to have funds.
|
||||
- Click on `[Client]` to open the **Lotus Node**'s client interface and propose a deal with an existing Miner. If successful you'll see a payment channel open up with that Miner.
|
||||
|
||||
Don't leave Pond unattended for more than 10 hours, the web client will eventually consume all available RAM.
|
||||
|
||||
@@ -19,7 +19,7 @@ export LOTUS_JAEGER_AGENT_ENDPOINT=127.0.0.1:6831
|
||||
lotus daemon
|
||||
```
|
||||
|
||||
Alternatively, the agent endpoint can also be configured by a pair of environemnt variables to provide the host and port. The following snipit is functionally equivilent to the previous.
|
||||
Alternatively, the agent endpoint can also be configured by a pair of environment variables to provide the host and port. The following snippet is functionally equivalent to the previous.
|
||||
|
||||
```bash
|
||||
export LOTUS_JAEGER_AGENT_HOST=127.0.0.1
|
||||
|
||||
+2
-1
@@ -307,7 +307,8 @@ type {{.Num}}Struct struct {
|
||||
|
||||
type {{.Num}}Methods struct {
|
||||
{{range .Methods}}
|
||||
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
||||
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{$first := true}}{{range .Tags}}{{if $first}}{{$first = false}}{{else}} {{end}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
||||
|
||||
{{end}}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ require (
|
||||
github.com/filecoin-project/go-data-transfer v1.15.2
|
||||
github.com/filecoin-project/go-fil-commcid v0.1.0
|
||||
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
|
||||
github.com/filecoin-project/go-fil-markets v1.25.2
|
||||
github.com/filecoin-project/go-fil-markets v1.26.0
|
||||
github.com/filecoin-project/go-jsonrpc v0.2.1
|
||||
github.com/filecoin-project/go-legs v0.4.4
|
||||
github.com/filecoin-project/go-padreader v0.0.1
|
||||
@@ -48,7 +48,6 @@ require (
|
||||
github.com/filecoin-project/go-statemachine v1.0.2
|
||||
github.com/filecoin-project/go-statestore v0.2.0
|
||||
github.com/filecoin-project/go-storedcounter v0.1.0
|
||||
github.com/filecoin-project/index-provider v0.9.1
|
||||
github.com/filecoin-project/pubsub v1.0.0
|
||||
github.com/filecoin-project/specs-actors v0.9.15
|
||||
github.com/filecoin-project/specs-actors/v2 v2.3.6
|
||||
@@ -111,6 +110,7 @@ require (
|
||||
github.com/ipld/go-codec-dagpb v1.5.0
|
||||
github.com/ipld/go-ipld-prime v0.20.0
|
||||
github.com/ipld/go-ipld-selector-text-lite v0.0.1
|
||||
github.com/ipni/index-provider v0.10.0
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/koalacxr/quantile v0.0.1
|
||||
github.com/libp2p/go-buffer-pool v0.1.0
|
||||
@@ -153,6 +153,7 @@ require (
|
||||
go.opentelemetry.io/otel/bridge/opencensus v0.33.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.2.0
|
||||
go.opentelemetry.io/otel/sdk v1.11.1
|
||||
go.uber.org/atomic v1.10.0
|
||||
go.uber.org/fx v1.15.0
|
||||
go.uber.org/multierr v1.8.0
|
||||
go.uber.org/zap v1.23.0
|
||||
@@ -203,7 +204,6 @@ require (
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect
|
||||
github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 // indirect
|
||||
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 // indirect
|
||||
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
@@ -247,6 +247,7 @@ require (
|
||||
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
||||
github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect
|
||||
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 // indirect
|
||||
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c // indirect
|
||||
@@ -334,7 +335,6 @@ require (
|
||||
go.opentelemetry.io/otel/metric v0.33.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.33.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.11.1 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/dig v1.12.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
|
||||
@@ -331,8 +331,8 @@ github.com/filecoin-project/go-fil-commcid v0.1.0 h1:3R4ds1A9r6cr8mvZBfMYxTS88Oq
|
||||
github.com/filecoin-project/go-fil-commcid v0.1.0/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ=
|
||||
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 h1:imrrpZWEHRnNqqv0tN7LXep5bFEVOVmQWHJvl2mgsGo=
|
||||
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0/go.mod h1:73S8WSEWh9vr0fDJVnKADhfIv/d6dCbAGaAGWbdJEI8=
|
||||
github.com/filecoin-project/go-fil-markets v1.25.2 h1:kVfgaamTC7dkn8KwS5zRJBNEBSNvVqdG3BCoDaUYuCI=
|
||||
github.com/filecoin-project/go-fil-markets v1.25.2/go.mod h1:dc2oTPU6GH3Qk1nA+Er+hSX64rg+NVykkPIWFBYxcZU=
|
||||
github.com/filecoin-project/go-fil-markets v1.26.0 h1:uNtt1UAxX2C/Q8tlWD00oF2Zma3CVGxhZmBc2ljYhkk=
|
||||
github.com/filecoin-project/go-fil-markets v1.26.0/go.mod h1:eOIYHfPwyqc64O1HiapvcelfnrTfU7gLQgBf55IYleQ=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM=
|
||||
github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24=
|
||||
github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0 h1:b3UDemBYN2HNfk3KOXNuxgTTxlWi3xVvbQP0IT38fvM=
|
||||
@@ -366,8 +366,6 @@ github.com/filecoin-project/go-statestore v0.2.0 h1:cRRO0aPLrxKQCZ2UOQbzFGn4WDNd
|
||||
github.com/filecoin-project/go-statestore v0.2.0/go.mod h1:8sjBYbS35HwPzct7iT4lIXjLlYyPor80aU7t7a/Kspo=
|
||||
github.com/filecoin-project/go-storedcounter v0.1.0 h1:Mui6wSUBC+cQGHbDUBcO7rfh5zQkWJM/CpAZa/uOuus=
|
||||
github.com/filecoin-project/go-storedcounter v0.1.0/go.mod h1:4ceukaXi4vFURIoxYMfKzaRF5Xv/Pinh2oTnoxpv+z8=
|
||||
github.com/filecoin-project/index-provider v0.9.1 h1:Jnh9dviIHvQxZ2baNoYu3n8z6F9O62ksnVlyREgPyyM=
|
||||
github.com/filecoin-project/index-provider v0.9.1/go.mod h1:NlHxQcy2iMGfUoUGUzrRxntcpiC50QSnvp68u2VTT40=
|
||||
github.com/filecoin-project/pubsub v1.0.0 h1:ZTmT27U07e54qV1mMiQo4HDr0buo8I1LDHBYLXlsNXM=
|
||||
github.com/filecoin-project/pubsub v1.0.0/go.mod h1:GkpB33CcUtUNrLPhJgfdy4FDx4OMNR9k+46DHx/Lqrg=
|
||||
github.com/filecoin-project/specs-actors v0.9.13/go.mod h1:TS1AW/7LbG+615j4NsjMK1qlpAwaFsG9w0V2tg2gSao=
|
||||
@@ -388,8 +386,6 @@ github.com/filecoin-project/specs-actors/v7 v7.0.1 h1:w72xCxijK7xs1qzmJiw+WYJaVt
|
||||
github.com/filecoin-project/specs-actors/v7 v7.0.1/go.mod h1:tPLEYXoXhcpyLh69Ccq91SOuLXsPWjHiY27CzawjUEk=
|
||||
github.com/filecoin-project/specs-actors/v8 v8.0.1 h1:4u0tIRJeT5G7F05lwLRIsDnsrN+bJ5Ixj6h49Q7uE2Y=
|
||||
github.com/filecoin-project/specs-actors/v8 v8.0.1/go.mod h1:UYIPg65iPWoFw5NEftREdJwv9b/5yaLKdCgTvNI/2FA=
|
||||
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893 h1:6GCuzxLVHBzlz7y+FkbHh6n0UyoEGWqDwJKQPJoz7bE=
|
||||
github.com/filecoin-project/storetheindex v0.4.30-0.20221114113647-683091f8e893/go.mod h1:S7590oDimBvXMUtzWsBXoshu9HtYKwtXl47zAK9rcP8=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
@@ -910,6 +906,10 @@ github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd
|
||||
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
|
||||
github.com/ipld/go-ipld-selector-text-lite v0.0.1 h1:lNqFsQpBHc3p5xHob2KvEg/iM5dIFn6iw4L/Hh+kS1Y=
|
||||
github.com/ipld/go-ipld-selector-text-lite v0.0.1/go.mod h1:U2CQmFb+uWzfIEF3I1arrDa5rwtj00PrpiwwCO+k1RM=
|
||||
github.com/ipni/index-provider v0.10.0 h1:nu8YBxzRopdjwZHsgCUuC4AHpq88VVHJYrbkqUDx7eg=
|
||||
github.com/ipni/index-provider v0.10.0/go.mod h1:InSXbZp2p/ZhAwiDElG/wzjnA1ea1iJ3hhyiAHrD+Vo=
|
||||
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 h1:qJq6QtLk+9nQi3CDBhNfJ1cjZ4pghjCHcQUZ1mWbF0k=
|
||||
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15/go.mod h1:c/NS640Iu2NrCCIErnUhsUM5KVEyeXymgtNnx6eDwMU=
|
||||
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52 h1:QG4CGBqCeuBo6aZlGAamSkxWdgWfZGeE49eUOWJPA4c=
|
||||
github.com/ipsn/go-secp256k1 v0.0.0-20180726113642-9d62b9f0bc52/go.mod h1:fdg+/X9Gg4AsAIzWpEHwnqd+QY3b7lajxyjE1m4hkq4=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
|
||||
@@ -8,12 +8,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
provider "github.com/ipni/index-provider"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/shared_testutil"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
provider "github.com/filecoin-project/index-provider"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/itests/kit"
|
||||
|
||||
@@ -166,7 +166,7 @@ func testDMExportAsFile(ctx context.Context, client *kit.TestFullNode, expDirect
|
||||
func testV0RetrievalAsFile(ctx context.Context, client *kit.TestFullNode, retOrder api0.RetrievalOrder, tempDir string) error {
|
||||
out := tempDir + string(os.PathSeparator) + "exp-test" + retOrder.Root.String()
|
||||
|
||||
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
|
||||
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
|
||||
err := cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
||||
Path: out,
|
||||
})
|
||||
@@ -220,7 +220,7 @@ func tesV0RetrievalAsCar(ctx context.Context, client *kit.TestFullNode, retOrder
|
||||
}
|
||||
defer out.Close() //nolint:errcheck
|
||||
|
||||
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
|
||||
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
|
||||
err = cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
||||
Path: out.Name(),
|
||||
IsCAR: true,
|
||||
|
||||
@@ -858,6 +858,39 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
|
||||
require.Len(t, receipt.Logs, 1)
|
||||
}
|
||||
|
||||
// This test ensures that we can deploy new contracts from a solidity call to `transfer` without
|
||||
// exceeding the 10M gas limit.
|
||||
func TestFEVMTestDeployOnTransfer(t *testing.T) {
|
||||
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||
defer cancel()
|
||||
|
||||
fromAddr := client.DefaultKey.Address
|
||||
t.Log("from - ", fromAddr)
|
||||
|
||||
//create contract A
|
||||
filenameStorage := "contracts/ValueSender.hex"
|
||||
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||
|
||||
//send to some random address.
|
||||
params := [32]byte{}
|
||||
params[30] = 0xff
|
||||
randomAddr, err := ethtypes.CastEthAddress(params[12:])
|
||||
value := big.NewInt(100)
|
||||
entryPoint := kit.CalcFuncSignature("sendEthToB(address)")
|
||||
require.NoError(t, err)
|
||||
ret, err := client.EVM().InvokeSolidityWithValue(ctx, fromAddr, contractAddr, entryPoint, params[:], value)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.Receipt.ExitCode.IsSuccess())
|
||||
|
||||
balance, err := client.EVM().EthGetBalance(ctx, randomAddr, "latest")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value.Int, balance.Int)
|
||||
|
||||
filAddr, err := randomAddr.ToFilecoinAddress()
|
||||
require.NoError(t, err)
|
||||
client.AssertActorType(ctx, filAddr, manifest.PlaceholderKey)
|
||||
}
|
||||
|
||||
func TestFEVMProxyUpgradeable(t *testing.T) {
|
||||
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||
defer cancel()
|
||||
|
||||
+5
-1
@@ -104,6 +104,10 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string
|
||||
}
|
||||
|
||||
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) {
|
||||
return e.InvokeSolidityWithValue(ctx, sender, target, selector, inputData, big.Zero())
|
||||
}
|
||||
|
||||
func (e *EVM) InvokeSolidityWithValue(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte, value big.Int) (*api.MsgLookup, error) {
|
||||
params := append(selector, inputData...)
|
||||
var buffer bytes.Buffer
|
||||
err := cbg.WriteByteArray(&buffer, params)
|
||||
@@ -115,7 +119,7 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
|
||||
msg := &types.Message{
|
||||
To: target,
|
||||
From: sender,
|
||||
Value: big.Zero(),
|
||||
Value: value,
|
||||
Method: builtintypes.MethodsEVM.InvokeContract,
|
||||
GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041
|
||||
Params: params,
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestPaymentChannelsAPI(t *testing.T) {
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
ctx := context.Background()
|
||||
blockTime := 5 * time.Millisecond
|
||||
blockTime := 10 * time.Millisecond
|
||||
|
||||
var (
|
||||
paymentCreator kit.TestFullNode
|
||||
@@ -55,6 +55,15 @@ func TestPaymentChannelsAPI(t *testing.T) {
|
||||
bms := ens.BeginMiningMustPost(blockTime)
|
||||
bm := bms[0]
|
||||
|
||||
waitRecvInSync := func() {
|
||||
// paymentCreator is the block miner, in some cases paymentReceiver may fall behind, so we wait for it to catch up
|
||||
|
||||
head, err := paymentReceiver.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
paymentReceiver.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()))
|
||||
}
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
@@ -74,6 +83,8 @@ func TestPaymentChannelsAPI(t *testing.T) {
|
||||
channel, err := paymentCreator.PaychGetWaitReady(ctx, channelInfo.WaitSentinel)
|
||||
require.NoError(t, err)
|
||||
|
||||
waitRecvInSync()
|
||||
|
||||
// allocate three lanes
|
||||
var lanes []uint64
|
||||
for i := 0; i < 3; i++ {
|
||||
@@ -110,6 +121,8 @@ func TestPaymentChannelsAPI(t *testing.T) {
|
||||
res := waitForMessage(ctx, t, paymentCreator, settleMsgCid, time.Second*10, "settle")
|
||||
require.EqualValues(t, 0, res.Receipt.ExitCode, "Unable to settle payment channel")
|
||||
|
||||
waitRecvInSync()
|
||||
|
||||
creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(paymentCreator)))
|
||||
|
||||
// wait for the receiver to submit their vouchers
|
||||
|
||||
+24
-1
@@ -282,7 +282,7 @@ func (w *RpcReader) Read(p []byte) (int, error) {
|
||||
}
|
||||
|
||||
if w.postBody == nil {
|
||||
return 0, xerrors.Errorf("reader already closed or redirected")
|
||||
return 0, xerrors.Errorf("reader already closed, redirected or cancelled")
|
||||
}
|
||||
|
||||
n, err := w.postBody.Read(p)
|
||||
@@ -406,6 +406,29 @@ func ReaderParamDecoder() (http.HandlerFunc, jsonrpc.ServerOption) {
|
||||
return
|
||||
case <-req.Context().Done():
|
||||
log.Errorf("context error in reader stream handler (2): %v", req.Context().Err())
|
||||
|
||||
closed := make(chan struct{})
|
||||
// start a draining goroutine
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case r, ok := <-wr.res:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
log.Errorw("discarding read res", "type", r.rt, "meta", r.meta)
|
||||
case <-closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
wr.beginOnce.Do(func() {})
|
||||
wr.closeOnce.Do(func() {
|
||||
close(wr.res)
|
||||
})
|
||||
close(closed)
|
||||
|
||||
resp.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -20,6 +22,9 @@ import (
|
||||
|
||||
type ReaderHandler struct {
|
||||
readApi func(ctx context.Context, r io.Reader) ([]byte, error)
|
||||
|
||||
cont chan struct{}
|
||||
subErr error
|
||||
}
|
||||
|
||||
func (h *ReaderHandler) ReadAllApi(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
|
||||
@@ -31,6 +36,24 @@ func (h *ReaderHandler) ReadAllApi(ctx context.Context, r io.Reader, mustRedir b
|
||||
return h.readApi(ctx, r)
|
||||
}
|
||||
|
||||
func (h *ReaderHandler) ReadAllWaiting(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
|
||||
if mustRedir {
|
||||
if err := r.(*RpcReader).MustRedirect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
h.cont <- struct{}{}
|
||||
<-h.cont
|
||||
|
||||
var m []byte
|
||||
m, h.subErr = h.readApi(ctx, r)
|
||||
|
||||
h.cont <- struct{}{}
|
||||
|
||||
return m, h.subErr
|
||||
}
|
||||
|
||||
func (h *ReaderHandler) ReadStartAndApi(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error) {
|
||||
if mustRedir {
|
||||
if err := r.(*RpcReader).MustRedirect(); err != nil {
|
||||
@@ -194,3 +217,110 @@ func TestReaderRedirect(t *testing.T) {
|
||||
err = redirClient.CloseReader(context.TODO(), strings.NewReader("rediracted pooooootato"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestReaderRedirectDrop(t *testing.T) {
|
||||
// lower timeout so that the dangling connection between client and reader is dropped quickly
|
||||
// after the test. Otherwise httptest.Close is blocked.
|
||||
Timeout = 200 * time.Millisecond
|
||||
|
||||
var allClient struct {
|
||||
ReadAll func(ctx context.Context, r io.Reader) ([]byte, error)
|
||||
}
|
||||
|
||||
{
|
||||
allServerHandler := &ReaderHandler{}
|
||||
readerHandler, readerServerOpt := ReaderParamDecoder()
|
||||
rpcServer := jsonrpc.NewServer(readerServerOpt)
|
||||
rpcServer.Register("ReaderHandler", allServerHandler)
|
||||
|
||||
mux := mux.NewRouter()
|
||||
mux.Handle("/rpc/v0", rpcServer)
|
||||
mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler)
|
||||
|
||||
testServ := httptest.NewServer(mux)
|
||||
defer testServ.Close()
|
||||
t.Logf("test server reading: %s", testServ.URL)
|
||||
|
||||
re := ReaderParamEncoder("http://" + testServ.Listener.Addr().String() + "/rpc/streams/v0/push")
|
||||
closer, err := jsonrpc.NewMergeClient(context.Background(), "ws://"+testServ.Listener.Addr().String()+"/rpc/v0", "ReaderHandler", []interface{}{&allClient}, nil, re)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer closer()
|
||||
}
|
||||
|
||||
var redirClient struct {
|
||||
ReadAllWaiting func(ctx context.Context, r io.Reader, mustRedir bool) ([]byte, error)
|
||||
}
|
||||
contCh := make(chan struct{})
|
||||
|
||||
allServerHandler := &ReaderHandler{readApi: allClient.ReadAll, cont: contCh}
|
||||
readerHandler, readerServerOpt := ReaderParamDecoder()
|
||||
rpcServer := jsonrpc.NewServer(readerServerOpt)
|
||||
rpcServer.Register("ReaderHandler", allServerHandler)
|
||||
|
||||
mux := mux.NewRouter()
|
||||
mux.Handle("/rpc/v0", rpcServer)
|
||||
mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler)
|
||||
|
||||
testServ := httptest.NewServer(mux)
|
||||
defer testServ.Close()
|
||||
t.Logf("test server redirecting: %s", testServ.URL)
|
||||
|
||||
re := ReaderParamEncoder("http://" + testServ.Listener.Addr().String() + "/rpc/streams/v0/push")
|
||||
closer, err := jsonrpc.NewMergeClient(context.Background(), "http://"+testServ.Listener.Addr().String()+"/rpc/v0", "ReaderHandler", []interface{}{&redirClient}, nil, re)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer closer()
|
||||
|
||||
var done sync.WaitGroup
|
||||
|
||||
// Happy case
|
||||
|
||||
done.Add(1)
|
||||
go func() {
|
||||
defer done.Done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
read, err := redirClient.ReadAllWaiting(ctx, strings.NewReader("rediracted pooooootato"), true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rediracted pooooootato", string(read), "potatoes weren't equal")
|
||||
}()
|
||||
|
||||
<-contCh // exec enter ReadAllWaiting
|
||||
contCh <- struct{}{} // stert subcall
|
||||
<-contCh // wait for subcall to finish
|
||||
|
||||
done.Wait()
|
||||
|
||||
// Redir client drops before subcall
|
||||
done.Add(1)
|
||||
|
||||
go func() {
|
||||
defer done.Done()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
_, err := redirClient.ReadAllWaiting(ctx, strings.NewReader("rediracted pooooootato"), true)
|
||||
require.ErrorContains(t, err, "sendRequest failed")
|
||||
}()
|
||||
|
||||
// wait for execution to enter ReadAllWaiting
|
||||
<-contCh
|
||||
|
||||
// kill redirecting server connection
|
||||
testServ.CloseClientConnections()
|
||||
|
||||
// ReadAllWaiting should fail
|
||||
done.Wait()
|
||||
|
||||
// resume execution in ReadAllWaiting, calling redicect
|
||||
contCh <- struct{}{}
|
||||
|
||||
// wait for subcall to finish
|
||||
<-contCh
|
||||
|
||||
require.ErrorContains(t, allServerHandler.subErr, "decoding params for 'ReaderHandler.ReadAll' (param: 0; custom decoder): context canceled")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/minio/blake2b-simd"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-crypto"
|
||||
crypto "github.com/filecoin-project/go-crypto"
|
||||
crypto2 "github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestLotusAccessorFetchUnsealedPiece(t *testing.T) {
|
||||
dealInfo := piecestore.DealInfo{
|
||||
SectorID: sectorID,
|
||||
}
|
||||
err = ps.AddDealForPiece(cid1, dealInfo)
|
||||
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ func TestLotusAccessorGetUnpaddedCARSize(t *testing.T) {
|
||||
dealInfo := piecestore.DealInfo{
|
||||
Length: 10,
|
||||
}
|
||||
err = ps.AddDealForPiece(cid1, dealInfo)
|
||||
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that the data length is correct
|
||||
@@ -153,7 +153,7 @@ func TestThrottle(t *testing.T) {
|
||||
SectorID: unsealedSectorID,
|
||||
Length: 10,
|
||||
}
|
||||
err = ps.AddDealForPiece(cid1, dealInfo)
|
||||
err = ps.AddDealForPiece(cid1, cid.Undef, dealInfo)
|
||||
require.NoError(t, err)
|
||||
|
||||
// hold the lock to block.
|
||||
|
||||
+2
-1
@@ -67,9 +67,10 @@ var (
|
||||
ConnectionManagerKey = special{9} // Libp2p option
|
||||
AutoNATSvcKey = special{10} // Libp2p option
|
||||
BandwidthReporterKey = special{11} // Libp2p option
|
||||
ConnGaterKey = special{12} // libp2p option
|
||||
ConnGaterKey = special{12} // Libp2p option
|
||||
DAGStoreKey = special{13} // constructor returns multiple values
|
||||
ResourceManagerKey = special{14} // Libp2p option
|
||||
UserAgentKey = special{15} // Libp2p option
|
||||
)
|
||||
|
||||
type invoke int
|
||||
|
||||
@@ -76,7 +76,7 @@ var ChainNode = Options(
|
||||
// Consensus: Chain storage/access
|
||||
Override(new(chain.Genesis), chain.LoadGenesis),
|
||||
Override(new(store.WeightFunc), filcns.Weight),
|
||||
Override(new(stmgr.Executor), filcns.NewTipSetExecutor()),
|
||||
Override(new(stmgr.Executor), consensus.NewTipSetExecutor(filcns.RewardFunc)),
|
||||
Override(new(consensus.Consensus), filcns.NewFilecoinExpectedConsensus),
|
||||
Override(new(*store.ChainStore), modules.ChainStore),
|
||||
Override(new(*stmgr.StateManager), modules.StateManager),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user