Compare commits
351
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
613226dec5 | ||
|
|
366359803a | ||
|
|
3b13397165 | ||
|
|
163c2b2544 | ||
|
|
9e2603c1bf | ||
|
|
d27750590a | ||
|
|
33a00ab9e5 | ||
|
|
f765fe36d7 | ||
|
|
be7a95c9a5 | ||
|
|
2571480bb6 | ||
|
|
73d928751d | ||
|
|
0c19544d94 | ||
|
|
a80dce2e3b | ||
|
|
fb09d1ad2b | ||
|
|
963e4dd2fc | ||
|
|
a5d81c6cc9 | ||
|
|
b167e73acb | ||
|
|
e7af464033 | ||
|
|
28e454fd4a | ||
|
|
55a9c9ae0a | ||
|
|
b3eef76cdd | ||
|
|
3f81ff3507 | ||
|
|
2347ba6f39 | ||
|
|
b9d3c26eae | ||
|
|
cd6670205c | ||
|
|
9f4ac4f4f3 | ||
|
|
e4bed4d963 | ||
|
|
76b5c8b145 | ||
|
|
9836c45e03 | ||
|
|
51f1712564 | ||
|
|
e9eff8be5c | ||
|
|
4855045ea2 | ||
|
|
6b06ae528c | ||
|
|
813961b458 | ||
|
|
7ae9d26cd1 | ||
|
|
9e5cc7c910 | ||
|
|
7d166fd730 | ||
|
|
60101fd97b | ||
|
|
0bc174697a | ||
|
|
7bee5b3abc | ||
|
|
656b285195 | ||
|
|
86083531c6 | ||
|
|
c01f70105f | ||
|
|
5aafa91e22 | ||
|
|
bada564c10 | ||
|
|
f9f0d86ddf | ||
|
|
6beabb5e8a | ||
|
|
3719938849 | ||
|
|
6420990007 | ||
|
|
1fab24b9bc | ||
|
|
8bbe63bd9d | ||
|
|
fa3b1552cf | ||
|
|
c625b30781 | ||
|
|
b339750757 | ||
|
|
da960a9de4 | ||
|
|
954a20ff4c | ||
|
|
8057b994cf | ||
|
|
ea111b058e | ||
|
|
ce33074626 | ||
|
|
5f95a92135 | ||
|
|
cd817906b2 | ||
|
|
29dbc26dbd | ||
|
|
04f0130530 | ||
|
|
f210a6e91a | ||
|
|
aded0706be | ||
|
|
57567db017 | ||
|
|
5574e4f11b | ||
|
|
4b01b666f6 | ||
|
|
35740895ed | ||
|
|
4c5d84d106 | ||
|
|
a8915f0331 | ||
|
|
7f962e19c2 | ||
|
|
186fd4da74 | ||
|
|
2fdcf5347b | ||
|
|
4a983995a8 | ||
|
|
263bdc9687 | ||
|
|
42c76aaebc | ||
|
|
9326cb5411 | ||
|
|
415b69155b | ||
|
|
3423d29815 | ||
|
|
673a972fe9 | ||
|
|
1fd20b636b | ||
|
|
d7a2556292 | ||
|
|
8aa158d4e6 | ||
|
|
3595b1f8e9 | ||
|
|
9b867a221a | ||
|
|
46a016cdce | ||
|
|
bea9cd2fe2 | ||
|
|
ee9d9a52a9 | ||
|
|
1e8a875edb | ||
|
|
36a93c90eb | ||
|
|
38d714a28a | ||
|
|
bbb954afc5 | ||
|
|
de5d16eeac | ||
|
|
1968195da9 | ||
|
|
22851df145 | ||
|
|
96ade5f2dd | ||
|
|
5e727819ad | ||
|
|
5605aae269 | ||
|
|
c6b6c2990c | ||
|
|
a49dc90386 | ||
|
|
64f4e80446 | ||
|
|
e67253b6a8 | ||
|
|
c73326e96d | ||
|
|
7003960fdd | ||
|
|
0acc2a2a63 | ||
|
|
596f78f9e6 | ||
|
|
17f1eec81f | ||
|
|
f0d44ea396 | ||
|
|
ad4712b593 | ||
|
|
92b8d9ad17 | ||
|
|
12ff9fd76b | ||
|
|
e26cf4e003 | ||
|
|
b753cd4503 | ||
|
|
ee29a92021 | ||
|
|
c3916e3a7f | ||
|
|
ec0baefc48 | ||
|
|
2a3d79f055 | ||
|
|
1c01799a4b | ||
|
|
4ef330ba8b | ||
|
|
cd2bf04a6b | ||
|
|
f7a71f4be7 | ||
|
|
e5c24ff32b | ||
|
|
f87054bde4 | ||
|
|
e954cc0d67 | ||
|
|
43c887f2b6 | ||
|
|
1cf9b9a67f | ||
|
|
7dd25c3ac5 | ||
|
|
241c3fa673 | ||
|
|
785eeb1eee | ||
|
|
30d82ba962 | ||
|
|
002d021eb7 | ||
|
|
71eb41b9aa | ||
|
|
f06369166e | ||
|
|
5129fed7c8 | ||
|
|
f06794ae84 | ||
|
|
1cabecedee | ||
|
|
f17c32c593 | ||
|
|
b59f88324c | ||
|
|
0c4db8cf6b | ||
|
|
9c020e54b5 | ||
|
|
9811375d18 | ||
|
|
2632621f7e | ||
|
|
d742efe165 | ||
|
|
492ffac913 | ||
|
|
4acf0c7ec0 | ||
|
|
fa69adf45c | ||
|
|
fa04da2995 | ||
|
|
e2a554c2e6 | ||
|
|
91da81c8bc | ||
|
|
7bd18290db | ||
|
|
8e55c91cd2 | ||
|
|
514339e855 | ||
|
|
9f8ecb0ac4 | ||
|
|
be1bbe88b0 | ||
|
|
f1ccbe496a | ||
|
|
495554e565 | ||
|
|
17c378c18a | ||
|
|
6e63ea6cce | ||
|
|
10753f14d0 | ||
|
|
0af7cd1448 | ||
|
|
de3edc2ec7 | ||
|
|
d0eb4278ae | ||
|
|
b807bdbea0 | ||
|
|
386b818d16 | ||
|
|
8639409f74 | ||
|
|
b372881e91 | ||
|
|
fc351d08b0 | ||
|
|
eb325e6814 | ||
|
|
7232e5481c | ||
|
|
f26a336afb | ||
|
|
70e690dac0 | ||
|
|
78e0c96f22 | ||
|
|
d6615b6286 | ||
|
|
4604b60fb1 | ||
|
|
75041b96e4 | ||
|
|
8544bda14a | ||
|
|
745fba7d1f | ||
|
|
6986204657 | ||
|
|
3f9cde28fc | ||
|
|
aa682a377d | ||
|
|
af1d54501f | ||
|
|
009cd92010 | ||
|
|
6386107b80 | ||
|
|
218b2b82c1 | ||
|
|
b06b0147a9 | ||
|
|
b74e8f5922 | ||
|
|
94a7ef1c10 | ||
|
|
02afd7d71f | ||
|
|
a10690359c | ||
|
|
fa4ff89dca | ||
|
|
bcd84cbe9d | ||
|
|
61daaa774b | ||
|
|
d5346f8326 | ||
|
|
8ce6921b18 | ||
|
|
c8f28103f3 | ||
|
|
3cd3785385 | ||
|
|
9089aadbbf | ||
|
|
02ca1937f8 | ||
|
|
6897110fe5 | ||
|
|
b799af3e9a | ||
|
|
9641d93615 | ||
|
|
da6768c94d | ||
|
|
54a8b88d6c | ||
|
|
ba6217cc2c | ||
|
|
314da26da3 | ||
|
|
646800b8a8 | ||
|
|
92d58ab191 | ||
|
|
5531f27798 | ||
|
|
cc98117df2 | ||
|
|
ffd340086e | ||
|
|
805686be2e | ||
|
|
0d3f602d58 | ||
|
|
83436842c5 | ||
|
|
bafb922ff7 | ||
|
|
6e024d9994 | ||
|
|
d597c3fb0d | ||
|
|
24cebb8b2f | ||
|
|
0cc8446a79 | ||
|
|
3e383d909a | ||
|
|
3264a9faad | ||
|
|
c52b75d59e | ||
|
|
652c257763 | ||
|
|
060f23d748 | ||
|
|
e68ab286f6 | ||
|
|
92e5cc5ad7 | ||
|
|
6831ca9e03 | ||
|
|
f7325a69c1 | ||
|
|
bb78292faf | ||
|
|
eeca031525 | ||
|
|
f82e0e61e1 | ||
|
|
75e47db520 | ||
|
|
3da1a0d8cc | ||
|
|
a293bd798f | ||
|
|
ae60001dcc | ||
|
|
cea7c41023 | ||
|
|
0fe7a0b2e3 | ||
|
|
267368d56c | ||
|
|
f5451ad455 | ||
|
|
555537c528 | ||
|
|
cc5875c6bd | ||
|
|
c54d050cb7 | ||
|
|
cb88237305 | ||
|
|
cc44167f2c | ||
|
|
78c656e4c1 | ||
|
|
607bcc401c | ||
|
|
7fd481ea6f | ||
|
|
9c91daf19a | ||
|
|
c1ef9d1731 | ||
|
|
eaf69b160c | ||
|
|
269286e587 | ||
|
|
f99c5416ce | ||
|
|
8f6c3c2cc7 | ||
|
|
a2e25897e9 | ||
|
|
fc9e046ca7 | ||
|
|
5730d46179 | ||
|
|
9165f14693 | ||
|
|
9305eca97c | ||
|
|
0c2e4e2d4f | ||
|
|
59725b3af3 | ||
|
|
a0ab3483ed | ||
|
|
e6f3b79b23 | ||
|
|
1ed6183344 | ||
|
|
29b1ac964b | ||
|
|
8d637c515a | ||
|
|
5220a61fc5 | ||
|
|
d9502693f0 | ||
|
|
9a0d0511c7 | ||
|
|
72eb32ae3c | ||
|
|
cf9e576028 | ||
|
|
9804bd3c4c | ||
|
|
30e2642f4d | ||
|
|
54b3eafd6d | ||
|
|
f6589407c1 | ||
|
|
5c73602d24 | ||
|
|
70657e35ba | ||
|
|
908053015b | ||
|
|
8bae22ef61 | ||
|
|
1012a64110 | ||
|
|
9eb2399539 | ||
|
|
d539be4875 | ||
|
|
13fc3f2f54 | ||
|
|
33ec4d332b | ||
|
|
d6bb0500df | ||
|
|
b90666b293 | ||
|
|
173a72f374 | ||
|
|
0ae0e89ddd | ||
|
|
c4d01c04a4 | ||
|
|
0b56ca3c21 | ||
|
|
022348f426 | ||
|
|
ad108d6051 | ||
|
|
dbe2a1e2cd | ||
|
|
f86a2ced06 | ||
|
|
f7a45f6c12 | ||
|
|
658f78d75f | ||
|
|
e9eaee6ef8 | ||
|
|
505e30c7b2 | ||
|
|
1ac6f3fa33 | ||
|
|
88fa9726cc | ||
|
|
af87920b6f | ||
|
|
881b0517b1 | ||
|
|
9b2b72819b | ||
|
|
2e74e1d2ae | ||
|
|
edae6a3ae8 | ||
|
|
987571dd8c | ||
|
|
934b2df763 | ||
|
|
81bc159b3e | ||
|
|
50e05ae1ba | ||
|
|
432c69c616 | ||
|
|
e714294273 | ||
|
|
c3a144bcb6 | ||
|
|
dd86a289ce | ||
|
|
6e0dac06f4 | ||
|
|
5bd0e92068 | ||
|
|
b032d3524b | ||
|
|
6933df918a | ||
|
|
d1997b5857 | ||
|
|
aafa00abe4 | ||
|
|
d3eb808ff4 | ||
|
|
d009b70171 | ||
|
|
d358da43f7 | ||
|
|
6cfc7e3fa0 | ||
|
|
b5cb1fe1e0 | ||
|
|
17dace9086 | ||
|
|
50fae56baf | ||
|
|
42269e17cc | ||
|
|
a9689d8345 | ||
|
|
32dad4d43b | ||
|
|
a88700bef4 | ||
|
|
8d85aedeff | ||
|
|
744ae23c2c | ||
|
|
4e13d284b7 | ||
|
|
0533cf22e7 | ||
|
|
17e969bc4a | ||
|
|
8b0c0a9439 | ||
|
|
7d2462ce6b | ||
|
|
e34b20b839 | ||
|
|
363f575e6c | ||
|
|
2f272d2703 | ||
|
|
9a21b75c66 | ||
|
|
bbd2fbc434 | ||
|
|
b3fc18c988 | ||
|
|
4a8e45a88c | ||
|
|
e12e2b4e4e | ||
|
|
40972762df | ||
|
|
4f624465c2 | ||
|
|
41c019b3d2 | ||
|
|
ea6121a951 | ||
|
|
427cb1b14d | ||
|
|
27fd150491 | ||
|
|
c2acfb5c31 |
+18
-33
@@ -1,6 +1,6 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
go: gotest/tools@0.0.9
|
||||
go: gotest/tools@0.0.13
|
||||
|
||||
executors:
|
||||
golang:
|
||||
@@ -79,7 +79,6 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- go/mod-tidy-check
|
||||
|
||||
build-all:
|
||||
@@ -87,12 +86,8 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install npm
|
||||
- restore_cache:
|
||||
name: restore go mod cache
|
||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
||||
- run:
|
||||
command: make buildall
|
||||
- store_artifacts:
|
||||
@@ -112,10 +107,6 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- restore_cache:
|
||||
name: restore go mod cache
|
||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
||||
- run:
|
||||
command: make debug
|
||||
|
||||
@@ -134,6 +125,9 @@ jobs:
|
||||
type: string
|
||||
default: "./..."
|
||||
description: Import paths of packages to be tested.
|
||||
winpost-test:
|
||||
type: string
|
||||
default: "0"
|
||||
test-suite-name:
|
||||
type: string
|
||||
default: unit
|
||||
@@ -156,10 +150,6 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- restore_cache:
|
||||
name: restore go mod cache
|
||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
||||
- run:
|
||||
command: make deps lotus
|
||||
no_output_timeout: 30m
|
||||
@@ -171,6 +161,7 @@ jobs:
|
||||
environment:
|
||||
GOTESTSUM_JUNITFILE: /tmp/test-reports/<< parameters.test-suite-name >>/junit.xml
|
||||
GOTESTSUM_FORMAT: << parameters.gotestsum-format >>
|
||||
LOTUS_TEST_WINDOW_POST: << parameters.winpost-test >>
|
||||
command: |
|
||||
mkdir -p /tmp/test-reports/<< parameters.test-suite-name >>
|
||||
gotestsum -- \
|
||||
@@ -189,16 +180,11 @@ jobs:
|
||||
shell: /bin/bash -eo pipefail
|
||||
command: |
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- save_cache:
|
||||
name: save go mod cache
|
||||
key: v1-go-deps-{{ arch }}-{{ checksum "/home/circleci/project/go.mod" }}
|
||||
paths:
|
||||
- "~/go/pkg"
|
||||
- "~/go/src/github.com"
|
||||
- "~/go/src/golang.org"
|
||||
|
||||
test-short:
|
||||
<<: *test
|
||||
test-window-post:
|
||||
<<: *test
|
||||
|
||||
build-macos:
|
||||
description: build darwin lotus binary
|
||||
@@ -225,14 +211,12 @@ jobs:
|
||||
- run:
|
||||
name: Install jq
|
||||
command: |
|
||||
mkdir $HOME/.bin
|
||||
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output $HOME/.bin/jq
|
||||
chmod +x $HOME/.bin/jq
|
||||
curl --location https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 --output /usr/local/bin/jq
|
||||
chmod +x /usr/local/bin/jq
|
||||
- restore_cache:
|
||||
name: restore go mod and cargo cache
|
||||
name: restore cargo cache
|
||||
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
|
||||
- install-deps
|
||||
- go/mod-download
|
||||
- run:
|
||||
command: make build
|
||||
no_output_timeout: 30m
|
||||
@@ -259,7 +243,6 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- run:
|
||||
command: "! go fmt ./... 2>&1 | read"
|
||||
|
||||
@@ -272,7 +255,7 @@ jobs:
|
||||
default: golang
|
||||
golangci-lint-version:
|
||||
type: string
|
||||
default: 1.23.8
|
||||
default: 1.27.0
|
||||
concurrency:
|
||||
type: string
|
||||
default: '2'
|
||||
@@ -288,7 +271,6 @@ jobs:
|
||||
steps:
|
||||
- install-deps
|
||||
- prepare
|
||||
- go/mod-download
|
||||
- run:
|
||||
command: make deps
|
||||
no_output_timeout: 30m
|
||||
@@ -298,7 +280,7 @@ jobs:
|
||||
- run:
|
||||
name: Lint
|
||||
command: |
|
||||
$HOME/.local/bin/golangci-lint run -v \
|
||||
$HOME/.local/bin/golangci-lint run -v --timeout 2m \
|
||||
--concurrency << parameters.concurrency >> << parameters.args >>
|
||||
lint-changes:
|
||||
<<: *lint
|
||||
@@ -332,11 +314,14 @@ workflows:
|
||||
ci:
|
||||
jobs:
|
||||
- lint-changes:
|
||||
args: "--new-from-rev origin/master"
|
||||
- test:
|
||||
codecov-upload: true
|
||||
args: "--new-from-rev origin/next"
|
||||
- mod-tidy-check
|
||||
- gofmt
|
||||
- test:
|
||||
codecov-upload: true
|
||||
- test-window-post:
|
||||
go-test-flags: "-run=TestWindowedPost"
|
||||
winpost-test: "1"
|
||||
- test-short:
|
||||
go-test-flags: "--timeout 10m --short"
|
||||
filters:
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Sealing Issues
|
||||
about: Create a report for help with sealing (commit) failures.
|
||||
title: ''
|
||||
labels: 'sealing'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please provide all the information requested here to help us troubleshoot "commit failed" issues.
|
||||
If the information requested is missing, we will probably have to just ask you to provide it anyway,
|
||||
before we can help debug.
|
||||
|
||||
**Describe the problem**
|
||||
|
||||
A brief description of the problem you encountered while proving (sealing) a sector.
|
||||
|
||||
Including what commands you ran, and a description of your setup, is very helpful.
|
||||
|
||||
**Sectors list**
|
||||
|
||||
The output of `./lotus-storage-miner sectors list`.
|
||||
|
||||
**Sectors status**
|
||||
|
||||
The output of `./lotus-storage-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
|
||||
**Lotus storage miner logs**
|
||||
|
||||
Please go through the logs of your storage miner, and include screenshots of any error-like messages you find.
|
||||
|
||||
**Version**
|
||||
|
||||
The output of `./lotus --version`.
|
||||
+15
-1
@@ -22,13 +22,27 @@ issues:
|
||||
- "func name will be used as test\\.Test.* by other packages, and that stutters; consider calling this"
|
||||
- "Potential file inclusion via variable"
|
||||
- "should have( a package)? comment"
|
||||
- "Error return value of `logging.SetLogLevel` is not checked"
|
||||
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
- path: lotuspond
|
||||
linters:
|
||||
- errcheck
|
||||
|
||||
- path: node/modules/lp2p
|
||||
linters:
|
||||
- golint
|
||||
- path: ".*_test.go"
|
||||
|
||||
- path: build/params_.*\.go
|
||||
linters:
|
||||
- golint
|
||||
|
||||
- path: api/apistruct/struct.go
|
||||
linters:
|
||||
- golint
|
||||
|
||||
- path: .*_test.go
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ MODULES:=
|
||||
CLEAN:=
|
||||
BINS:=
|
||||
|
||||
ldflags=-X=github.com/filecoin-project/lotus/build.CurrentCommit='+git$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))'
|
||||
ldflags=-X=github.com/filecoin-project/lotus/build.CurrentCommit=+git.$(subst -,.,$(shell git describe --always --match=NeVeRmAtCh --dirty 2>/dev/null || git rev-parse --short HEAD 2>/dev/null))
|
||||
ifneq ($(strip $(LDFLAGS)),)
|
||||
ldflags+=-extldflags=$(LDFLAGS)
|
||||
endif
|
||||
@@ -103,6 +103,19 @@ install:
|
||||
install -C ./lotus-storage-miner /usr/local/bin/lotus-storage-miner
|
||||
install -C ./lotus-seal-worker /usr/local/bin/lotus-seal-worker
|
||||
|
||||
install-services: install
|
||||
mkdir -p /usr/local/lib/systemd/system
|
||||
install -C -m 0644 ./scripts/lotus-daemon.service /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
install -C -m 0644 ./scripts/lotus-miner.service /usr/local/lib/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "lotus and lotus-miner services installed. Don't forget to 'systemctl enable lotus|lotus-miner' for it to be enabled on startup."
|
||||
|
||||
clean-services:
|
||||
rm -f /usr/local/lib/systemd/system/lotus-daemon.service
|
||||
rm -f /usr/local/lib/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
|
||||
# TOOLS
|
||||
|
||||
lotus-seed: $(BUILD_DEPS)
|
||||
@@ -119,7 +132,7 @@ benchmarks:
|
||||
@curl -X POST 'http://benchmark.kittyhawk.wtf/benchmark' -d '@bench.json' -u "${benchmark_http_cred}"
|
||||
.PHONY: benchmarks
|
||||
|
||||
pond: build
|
||||
pond: 2k
|
||||
go build -o pond ./lotuspond
|
||||
(cd lotuspond/front && npm i && CI=false npm run build)
|
||||
.PHONY: pond
|
||||
|
||||
+10
-5
@@ -4,17 +4,18 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
)
|
||||
|
||||
type Permission = string
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
type Common interface {
|
||||
// Auth
|
||||
AuthVerify(ctx context.Context, token string) ([]Permission, error)
|
||||
AuthNew(ctx context.Context, perms []Permission) ([]byte, error)
|
||||
AuthVerify(ctx context.Context, token string) ([]auth.Permission, error)
|
||||
AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error)
|
||||
|
||||
// network
|
||||
|
||||
@@ -24,6 +25,7 @@ type Common interface {
|
||||
NetAddrsListen(context.Context) (peer.AddrInfo, error)
|
||||
NetDisconnect(context.Context, peer.ID) error
|
||||
NetFindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||
NetPubsubScores(context.Context) ([]PubsubScore, error)
|
||||
|
||||
// ID returns peerID of libp2p node backing this API
|
||||
ID(context.Context) (peer.ID, error)
|
||||
@@ -33,6 +35,9 @@ type Common interface {
|
||||
|
||||
LogList(context.Context) ([]string, error)
|
||||
LogSetLevel(context.Context, string, string) error
|
||||
|
||||
// trigger graceful shutdown
|
||||
Shutdown(context.Context) error
|
||||
}
|
||||
|
||||
// Version provides various build-time information
|
||||
|
||||
+47
-10
@@ -28,13 +28,18 @@ type FullNode interface {
|
||||
|
||||
// TODO: TipSetKeys
|
||||
|
||||
// chain
|
||||
// MethodGroup: Chain
|
||||
// The Chain method group contains methods for interacting with the
|
||||
// blockchain, but that do not require any form of state computation
|
||||
|
||||
// ChainNotify returns channel with chain head updates
|
||||
// First message is guaranteed to be of len == 1, and type == 'current'
|
||||
ChainNotify(context.Context) (<-chan []*HeadChange, error)
|
||||
// ChainHead returns the current head of the chain
|
||||
ChainHead(context.Context) (*types.TipSet, error)
|
||||
// ChainGetRandomness is used to sample the chain for randomness
|
||||
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
||||
// ChainGetBlock returns the block specified by the given CID
|
||||
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
|
||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
|
||||
@@ -52,14 +57,23 @@ type FullNode interface {
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error)
|
||||
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// syncer
|
||||
// MethodGroup: Sync
|
||||
// The Sync method group contains methods for interacting with and
|
||||
// observing the lotus sync service
|
||||
|
||||
// SyncState returns the current status of the lotus sync system
|
||||
SyncState(context.Context) (*SyncState, error)
|
||||
// SyncSubmitBlock can be used to submit a newly created block to the
|
||||
// network through this node
|
||||
SyncSubmitBlock(ctx context.Context, blk *types.BlockMsg) error
|
||||
SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error)
|
||||
SyncMarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||
|
||||
// messages
|
||||
// MethodGroup: Mpool
|
||||
// The Mpool methods are for interacting with the message pool. The message pool
|
||||
// manages all incoming and outgoing 'messages' going over the network.
|
||||
|
||||
MpoolPending(context.Context, types.TipSetKey) ([]*types.SignedMessage, error)
|
||||
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) // get nonce, sign, push
|
||||
@@ -67,16 +81,14 @@ type FullNode interface {
|
||||
MpoolSub(context.Context) (<-chan MpoolUpdate, error)
|
||||
MpoolEstimateGasPrice(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
// FullNodeStruct
|
||||
|
||||
// miner
|
||||
// MethodGroup: Miner
|
||||
|
||||
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
|
||||
MinerCreateBlock(context.Context, *BlockTemplate) (*types.BlockMsg, error)
|
||||
|
||||
// // UX ?
|
||||
|
||||
// wallet
|
||||
// MethodGroup: Wallet
|
||||
|
||||
WalletNew(context.Context, crypto.SigType) (address.Address, error)
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
@@ -92,14 +104,20 @@ type FullNode interface {
|
||||
|
||||
// Other
|
||||
|
||||
// MethodGroup: Client
|
||||
// The Client methods all have to do with interacting with the storage and
|
||||
// retrieval markets as a client
|
||||
|
||||
// ClientImport imports file under the specified path into filestore
|
||||
ClientImport(ctx context.Context, ref FileRef) (cid.Cid, error)
|
||||
// ClientStartDeal proposes a deal with a miner
|
||||
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error)
|
||||
// ClientGetDeal info returns the latest information about a given deal
|
||||
ClientGetDealInfo(context.Context, cid.Cid) (*DealInfo, error)
|
||||
ClientListDeals(ctx context.Context) ([]DealInfo, error)
|
||||
ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error)
|
||||
ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error)
|
||||
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref FileRef) error
|
||||
ClientRetrieve(ctx context.Context, order RetrievalOrder, ref *FileRef) error
|
||||
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
|
||||
ClientCalcCommP(ctx context.Context, inpath string, miner address.Address) (*CommPRet, error)
|
||||
ClientGenCar(ctx context.Context, ref FileRef, outpath string) error
|
||||
@@ -112,6 +130,9 @@ type FullNode interface {
|
||||
|
||||
//ClientListAsks() []Ask
|
||||
|
||||
// MethodGroup: State
|
||||
// The State methods are used to query, inspect, and interact with chain state
|
||||
|
||||
// if tipset is nil, we'll use heaviest
|
||||
StateCall(context.Context, *types.Message, types.TipSetKey) (*InvocResult, error)
|
||||
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*InvocResult, error)
|
||||
@@ -126,12 +147,16 @@ type FullNode interface {
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error)
|
||||
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
|
||||
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error)
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) ([]abi.SectorNumber, error)
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
// Returns all non-expired Faults that occur within lookback epochs of the given tipset
|
||||
StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error)
|
||||
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error)
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error)
|
||||
StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
||||
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
||||
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
StateWaitMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
@@ -146,6 +171,10 @@ type FullNode interface {
|
||||
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
|
||||
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
|
||||
|
||||
// MethodGroup: Msig
|
||||
// The Msig methods are used to interact with multisig wallets on the
|
||||
// filecoin network
|
||||
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
MsigCreate(context.Context, int64, []address.Address, types.BigInt, address.Address, types.BigInt) (cid.Cid, error)
|
||||
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
@@ -155,6 +184,9 @@ type FullNode interface {
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MarketFreeBalance
|
||||
|
||||
// MethodGroup: Paych
|
||||
// The Paych methods are for interacting with and managing payment channels
|
||||
|
||||
PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error)
|
||||
PaychList(context.Context) ([]address.Address, error)
|
||||
PaychStatus(context.Context, address.Address) (*PaychStatus, error)
|
||||
@@ -424,3 +456,8 @@ const (
|
||||
MsigApprove MsigProposeResponse = iota
|
||||
MsigCancel
|
||||
)
|
||||
|
||||
type Fault struct {
|
||||
Miner address.Address
|
||||
Epoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
+1
-2
@@ -8,11 +8,10 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// StorageMiner is a low-level interface to the Filecoin network storage miner node
|
||||
|
||||
+11
-2
@@ -2,6 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
@@ -12,7 +15,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
type WorkerApi interface {
|
||||
type WorkerAPI interface {
|
||||
Version(context.Context) (build.Version, error)
|
||||
// TODO: Info() (name, ...) ?
|
||||
|
||||
@@ -21,7 +24,13 @@ type WorkerApi interface {
|
||||
Info(context.Context) (storiface.WorkerInfo, error)
|
||||
|
||||
storage.Sealer
|
||||
Fetch(context.Context, abi.SectorID, stores.SectorFileType, bool) error
|
||||
|
||||
MoveStorage(ctx context.Context, sector abi.SectorID) error
|
||||
|
||||
UnsealPiece(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error
|
||||
ReadPiece(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error
|
||||
|
||||
Fetch(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error
|
||||
|
||||
Closing(context.Context) (<-chan struct{}, error)
|
||||
}
|
||||
|
||||
@@ -1,111 +1,38 @@
|
||||
package apistruct
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
)
|
||||
|
||||
type permKey int
|
||||
|
||||
var permCtxKey permKey
|
||||
|
||||
const (
|
||||
// When changing these, update docs/API.md too
|
||||
|
||||
PermRead api.Permission = "read" // default
|
||||
PermWrite api.Permission = "write"
|
||||
PermSign api.Permission = "sign" // Use wallet keys for signing
|
||||
PermAdmin api.Permission = "admin" // Manage permissions
|
||||
PermRead auth.Permission = "read" // default
|
||||
PermWrite auth.Permission = "write"
|
||||
PermSign auth.Permission = "sign" // Use wallet keys for signing
|
||||
PermAdmin auth.Permission = "admin" // Manage permissions
|
||||
)
|
||||
|
||||
var AllPermissions = []api.Permission{PermRead, PermWrite, PermSign, PermAdmin}
|
||||
var defaultPerms = []api.Permission{PermRead}
|
||||
|
||||
func WithPerm(ctx context.Context, perms []api.Permission) context.Context {
|
||||
return context.WithValue(ctx, permCtxKey, perms)
|
||||
}
|
||||
var AllPermissions = []auth.Permission{PermRead, PermWrite, PermSign, PermAdmin}
|
||||
var DefaultPerms = []auth.Permission{PermRead}
|
||||
|
||||
func PermissionedStorMinerAPI(a api.StorageMiner) api.StorageMiner {
|
||||
var out StorageMinerStruct
|
||||
permissionedAny(a, &out.Internal)
|
||||
permissionedAny(a, &out.CommonStruct.Internal)
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
func PermissionedFullAPI(a api.FullNode) api.FullNode {
|
||||
var out FullNodeStruct
|
||||
permissionedAny(a, &out.Internal)
|
||||
permissionedAny(a, &out.CommonStruct.Internal)
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.CommonStruct.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
func PermissionedWorkerAPI(a api.WorkerApi) api.WorkerApi {
|
||||
func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
|
||||
var out WorkerStruct
|
||||
permissionedAny(a, &out.Internal)
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
func HasPerm(ctx context.Context, perm api.Permission) bool {
|
||||
callerPerms, ok := ctx.Value(permCtxKey).([]api.Permission)
|
||||
if !ok {
|
||||
callerPerms = defaultPerms
|
||||
}
|
||||
|
||||
for _, callerPerm := range callerPerms {
|
||||
if callerPerm == perm {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func permissionedAny(in interface{}, out interface{}) {
|
||||
rint := reflect.ValueOf(out).Elem()
|
||||
ra := reflect.ValueOf(in)
|
||||
|
||||
for f := 0; f < rint.NumField(); f++ {
|
||||
field := rint.Type().Field(f)
|
||||
requiredPerm := api.Permission(field.Tag.Get("perm"))
|
||||
if requiredPerm == "" {
|
||||
panic("missing 'perm' tag on " + field.Name) // ok
|
||||
}
|
||||
|
||||
// Validate perm tag
|
||||
ok := false
|
||||
for _, perm := range AllPermissions {
|
||||
if requiredPerm == perm {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
panic("unknown 'perm' tag on " + field.Name) // ok
|
||||
}
|
||||
|
||||
fn := ra.MethodByName(field.Name)
|
||||
|
||||
rint.Field(f).Set(reflect.MakeFunc(field.Type, func(args []reflect.Value) (results []reflect.Value) {
|
||||
ctx := args[0].Interface().(context.Context)
|
||||
if HasPerm(ctx, requiredPerm) {
|
||||
return fn.Call(args)
|
||||
}
|
||||
|
||||
err := xerrors.Errorf("missing permission to invoke '%s' (need '%s')", field.Name, requiredPerm)
|
||||
rerr := reflect.ValueOf(&err).Elem()
|
||||
|
||||
if field.Type.NumOut() == 2 {
|
||||
return []reflect.Value{
|
||||
reflect.Zero(field.Type.Out(0)),
|
||||
rerr,
|
||||
}
|
||||
} else {
|
||||
return []reflect.Value{rerr}
|
||||
}
|
||||
}))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+79
-30
@@ -2,6 +2,7 @@ package apistruct
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
@@ -9,6 +10,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/sealtasks"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
"github.com/filecoin-project/sector-storage/storiface"
|
||||
@@ -30,8 +33,8 @@ var _ = AllPermissions
|
||||
|
||||
type CommonStruct struct {
|
||||
Internal struct {
|
||||
AuthVerify func(ctx context.Context, token string) ([]api.Permission, error) `perm:"read"`
|
||||
AuthNew func(ctx context.Context, perms []api.Permission) ([]byte, error) `perm:"admin"`
|
||||
AuthVerify func(ctx context.Context, token string) ([]auth.Permission, error) `perm:"read"`
|
||||
AuthNew func(ctx context.Context, perms []auth.Permission) ([]byte, error) `perm:"admin"`
|
||||
|
||||
NetConnectedness func(context.Context, peer.ID) (network.Connectedness, error) `perm:"read"`
|
||||
NetPeers func(context.Context) ([]peer.AddrInfo, error) `perm:"read"`
|
||||
@@ -39,12 +42,15 @@ type CommonStruct struct {
|
||||
NetAddrsListen func(context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetDisconnect func(context.Context, peer.ID) error `perm:"write"`
|
||||
NetFindPeer func(context.Context, peer.ID) (peer.AddrInfo, error) `perm:"read"`
|
||||
NetPubsubScores func(context.Context) ([]api.PubsubScore, error) `perm:"read"`
|
||||
|
||||
ID func(context.Context) (peer.ID, error) `perm:"read"`
|
||||
Version func(context.Context) (api.Version, error) `perm:"read"`
|
||||
|
||||
LogList func(context.Context) ([]string, error) `perm:"write"`
|
||||
LogSetLevel func(context.Context, string, string) error `perm:"write"`
|
||||
|
||||
Shutdown func(context.Context) error `perm:"admin"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +114,7 @@ type FullNodeStruct struct {
|
||||
ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"`
|
||||
ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"`
|
||||
ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref api.FileRef) error `perm:"admin"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
ClientCalcCommP func(ctx context.Context, inpath string, miner address.Address) (*api.CommPRet, error) `perm:"read"`
|
||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||
@@ -120,16 +126,19 @@ type FullNodeStruct struct {
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
|
||||
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"`
|
||||
StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) (*miner.Deadlines, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) ([]abi.SectorNumber, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"`
|
||||
StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (*abi.BitField, error) `perm:"read"`
|
||||
StateMinerInitialPledgeCollateral func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateSectorPreCommitInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) `perm:"read"`
|
||||
StateSectorGetInfo func(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) `perm:"read"`
|
||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.InvocResult, error) `perm:"read"`
|
||||
StateGetActor func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||
StateReadState func(context.Context, *types.Actor, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StatePledgeCollateral func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
StateWaitMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -197,16 +206,17 @@ type StorageMinerStruct struct {
|
||||
WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm
|
||||
WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"`
|
||||
|
||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing bool) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||
StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"`
|
||||
StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"`
|
||||
StorageStat func(context.Context, stores.ID) (stores.FsStat, error) `perm:"admin"`
|
||||
StorageAttach func(context.Context, stores.StorageInfo, stores.FsStat) error `perm:"admin"`
|
||||
StorageDeclareSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||
StorageDropSector func(context.Context, stores.ID, abi.SectorID, stores.SectorFileType) error `perm:"admin"`
|
||||
StorageFindSector func(context.Context, abi.SectorID, stores.SectorFileType, bool) ([]stores.SectorStorageInfo, error) `perm:"admin"`
|
||||
StorageInfo func(context.Context, stores.ID) (stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageBestAlloc func(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing stores.PathType) ([]stores.StorageInfo, error) `perm:"admin"`
|
||||
StorageReportHealth func(ctx context.Context, id stores.ID, report stores.HealthReport) error `perm:"admin"`
|
||||
StorageLock func(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error `perm:"admin"`
|
||||
|
||||
DealsImportData func(ctx context.Context, dealPropCid cid.Cid, file string) error `perm:"write"`
|
||||
DealsList func(ctx context.Context) ([]storagemarket.StorageDeal, error) `perm:"read"`
|
||||
@@ -230,8 +240,12 @@ type WorkerStruct struct {
|
||||
SealCommit1 func(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness, pieces []abi.PieceInfo, cids storage.SectorCids) (storage.Commit1Out, error) `perm:"admin"`
|
||||
SealCommit2 func(context.Context, abi.SectorID, storage.Commit1Out) (storage.Proof, error) `perm:"admin"`
|
||||
FinalizeSector func(context.Context, abi.SectorID) error `perm:"admin"`
|
||||
MoveStorage func(ctx context.Context, sector abi.SectorID) error `perm:"admin"`
|
||||
|
||||
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, bool) error `perm:"admin"`
|
||||
UnsealPiece func(context.Context, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize, abi.SealRandomness, cid.Cid) error `perm:"admin"`
|
||||
ReadPiece func(context.Context, io.Writer, abi.SectorID, storiface.UnpaddedByteIndex, abi.UnpaddedPieceSize) error `perm:"admin"`
|
||||
|
||||
Fetch func(context.Context, abi.SectorID, stores.SectorFileType, stores.PathType, stores.AcquireMode) error `perm:"admin"`
|
||||
|
||||
Closing func(context.Context) (<-chan struct{}, error) `perm:"admin"`
|
||||
}
|
||||
@@ -239,14 +253,17 @@ type WorkerStruct struct {
|
||||
|
||||
// CommonStruct
|
||||
|
||||
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]api.Permission, error) {
|
||||
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
|
||||
return c.Internal.AuthVerify(ctx, token)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) AuthNew(ctx context.Context, perms []api.Permission) ([]byte, error) {
|
||||
func (c *CommonStruct) AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) {
|
||||
return c.Internal.AuthNew(ctx, perms)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) NetPubsubScores(ctx context.Context) ([]api.PubsubScore, error) {
|
||||
return c.Internal.NetPubsubScores(ctx)
|
||||
}
|
||||
func (c *CommonStruct) NetConnectedness(ctx context.Context, pid peer.ID) (network.Connectedness, error) {
|
||||
return c.Internal.NetConnectedness(ctx, pid)
|
||||
}
|
||||
@@ -289,6 +306,10 @@ func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) err
|
||||
return c.Internal.LogSetLevel(ctx, group, level)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) Shutdown(ctx context.Context) error {
|
||||
return c.Internal.Shutdown(ctx)
|
||||
}
|
||||
|
||||
// FullNodeStruct
|
||||
|
||||
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
|
||||
@@ -318,7 +339,7 @@ func (c *FullNodeStruct) ClientListDeals(ctx context.Context) ([]api.DealInfo, e
|
||||
return c.Internal.ClientListDeals(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref api.FileRef) error {
|
||||
func (c *FullNodeStruct) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error {
|
||||
return c.Internal.ClientRetrieve(ctx, order, ref)
|
||||
}
|
||||
|
||||
@@ -533,10 +554,18 @@ func (c *FullNodeStruct) StateMinerDeadlines(ctx context.Context, m address.Addr
|
||||
return c.Internal.StateMinerDeadlines(ctx, m, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) ([]abi.SectorNumber, error) {
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
|
||||
return c.Internal.StateMinerFaults(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateAllMinerFaults(ctx context.Context, cutoff abi.ChainEpoch, endTsk types.TipSetKey) ([]*api.Fault, error) {
|
||||
return c.Internal.StateAllMinerFaults(ctx, cutoff, endTsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*abi.BitField, error) {
|
||||
return c.Internal.StateMinerRecoveries(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, snum abi.SectorNumber, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StateMinerInitialPledgeCollateral(ctx, maddr, snum, tsk)
|
||||
}
|
||||
@@ -549,6 +578,10 @@ func (c *FullNodeStruct) StateSectorPreCommitInfo(ctx context.Context, maddr add
|
||||
return c.Internal.StateSectorPreCommitInfo(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) {
|
||||
return c.Internal.StateSectorGetInfo(ctx, maddr, n, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
|
||||
return c.Internal.StateCall(ctx, msg, tsk)
|
||||
}
|
||||
@@ -569,8 +602,8 @@ func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.Ti
|
||||
return c.Internal.StatePledgeCollateral(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc)
|
||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||
@@ -745,15 +778,15 @@ func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.Storag
|
||||
return c.Internal.StorageAttach(ctx, si, st)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageDeclareSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType) error {
|
||||
return c.Internal.StorageDeclareSector(ctx, storageId, s, ft)
|
||||
func (c *StorageMinerStruct) StorageDeclareSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType, primary bool) error {
|
||||
return c.Internal.StorageDeclareSector(ctx, storageId, s, ft, primary)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageDropSector(ctx context.Context, storageId stores.ID, s abi.SectorID, ft stores.SectorFileType) error {
|
||||
return c.Internal.StorageDropSector(ctx, storageId, s, ft)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, allowFetch bool) ([]stores.StorageInfo, error) {
|
||||
func (c *StorageMinerStruct) StorageFindSector(ctx context.Context, si abi.SectorID, types stores.SectorFileType, allowFetch bool) ([]stores.SectorStorageInfo, error) {
|
||||
return c.Internal.StorageFindSector(ctx, si, types, allowFetch)
|
||||
}
|
||||
|
||||
@@ -773,14 +806,18 @@ func (c *StorageMinerStruct) StorageInfo(ctx context.Context, id stores.ID) (sto
|
||||
return c.Internal.StorageInfo(ctx, id)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, sealing bool) ([]stores.StorageInfo, error) {
|
||||
return c.Internal.StorageBestAlloc(ctx, allocate, spt, sealing)
|
||||
func (c *StorageMinerStruct) StorageBestAlloc(ctx context.Context, allocate stores.SectorFileType, spt abi.RegisteredProof, pt stores.PathType) ([]stores.StorageInfo, error) {
|
||||
return c.Internal.StorageBestAlloc(ctx, allocate, spt, pt)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageReportHealth(ctx context.Context, id stores.ID, report stores.HealthReport) error {
|
||||
return c.Internal.StorageReportHealth(ctx, id, report)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) StorageLock(ctx context.Context, sector abi.SectorID, read stores.SectorFileType, write stores.SectorFileType) error {
|
||||
return c.Internal.StorageLock(ctx, sector, read, write)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) MarketImportDealData(ctx context.Context, propcid cid.Cid, path string) error {
|
||||
return c.Internal.MarketImportDealData(ctx, propcid, path)
|
||||
}
|
||||
@@ -847,8 +884,20 @@ func (w *WorkerStruct) FinalizeSector(ctx context.Context, sector abi.SectorID)
|
||||
return w.Internal.FinalizeSector(ctx, sector)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, b bool) error {
|
||||
return w.Internal.Fetch(ctx, id, fileType, b)
|
||||
func (w *WorkerStruct) MoveStorage(ctx context.Context, sector abi.SectorID) error {
|
||||
return w.Internal.MoveStorage(ctx, sector)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) UnsealPiece(ctx context.Context, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, c cid.Cid) error {
|
||||
return w.Internal.UnsealPiece(ctx, id, index, size, randomness, c)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) ReadPiece(ctx context.Context, writer io.Writer, id abi.SectorID, index storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize) error {
|
||||
return w.Internal.ReadPiece(ctx, writer, id, index, size)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) Fetch(ctx context.Context, id abi.SectorID, fileType stores.SectorFileType, ptype stores.PathType, am stores.AcquireMode) error {
|
||||
return w.Internal.Fetch(ctx, id, fileType, ptype, am)
|
||||
}
|
||||
|
||||
func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||
@@ -858,4 +907,4 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||
var _ api.Common = &CommonStruct{}
|
||||
var _ api.FullNode = &FullNodeStruct{}
|
||||
var _ api.StorageMiner = &StorageMinerStruct{}
|
||||
var _ api.WorkerApi = &WorkerStruct{}
|
||||
var _ api.WorkerAPI = &WorkerStruct{}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"net/http"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/lib/jsonrpc"
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
)
|
||||
|
||||
// NewCommonRPC creates a new http jsonrpc client.
|
||||
@@ -47,7 +48,7 @@ func NewStorageMinerRPC(addr string, requestHeader http.Header) (api.StorageMine
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerApi, jsonrpc.ClientCloser, error) {
|
||||
func NewWorkerRPC(addr string, requestHeader http.Header) (api.WorkerAPI, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.WorkerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(addr, "Filecoin",
|
||||
[]interface{}{
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var ExampleValues = map[reflect.Type]interface{}{
|
||||
reflect.TypeOf(auth.Permission("")): auth.Permission("write"),
|
||||
reflect.TypeOf(""): "string value",
|
||||
reflect.TypeOf(uint64(42)): uint64(42),
|
||||
reflect.TypeOf(byte(7)): byte(7),
|
||||
reflect.TypeOf([]byte{}): []byte("byte array"),
|
||||
}
|
||||
|
||||
func addExample(v interface{}) {
|
||||
ExampleValues[reflect.TypeOf(v)] = v
|
||||
}
|
||||
|
||||
func init() {
|
||||
c, err := cid.Decode("bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ExampleValues[reflect.TypeOf(c)] = c
|
||||
|
||||
c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
tsk := types.NewTipSetKey(c, c2)
|
||||
|
||||
ExampleValues[reflect.TypeOf(tsk)] = tsk
|
||||
|
||||
addr, err := address.NewIDAddress(1234)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ExampleValues[reflect.TypeOf(addr)] = addr
|
||||
|
||||
pid, err := peer.IDB58Decode("12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
addExample(pid)
|
||||
|
||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||
addExample(abi.RegisteredProof_StackedDRG32GiBPoSt)
|
||||
addExample(abi.ChainEpoch(10101))
|
||||
addExample(crypto.SigTypeBLS)
|
||||
addExample(int64(9))
|
||||
addExample(abi.MethodNum(1))
|
||||
addExample(exitcode.ExitCode(0))
|
||||
addExample(crypto.DomainSeparationTag_ElectionProofProduction)
|
||||
addExample(true)
|
||||
addExample(abi.UnpaddedPieceSize(1024))
|
||||
addExample(abi.UnpaddedPieceSize(1024).Padded())
|
||||
addExample(abi.DealID(5432))
|
||||
addExample(filestore.StatusFileChanged)
|
||||
addExample(abi.SectorNumber(9))
|
||||
addExample(abi.SectorSize(32 * 1024 * 1024 * 1024))
|
||||
addExample(api.MpoolChange(0))
|
||||
addExample(network.Connected)
|
||||
addExample(dtypes.NetworkName("lotus"))
|
||||
addExample(api.SyncStateStage(1))
|
||||
addExample(build.APIVersion)
|
||||
addExample(api.PCHInbound)
|
||||
addExample(time.Minute)
|
||||
addExample(&types.ExecutionResult{
|
||||
Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message),
|
||||
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt),
|
||||
})
|
||||
addExample(map[string]types.Actor{
|
||||
"t01236": exampleValue(reflect.TypeOf(types.Actor{})).(types.Actor),
|
||||
})
|
||||
addExample(map[string]api.MarketDeal{
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketDeal{})).(api.MarketDeal),
|
||||
})
|
||||
addExample(map[string]api.MarketBalance{
|
||||
"t026363": exampleValue(reflect.TypeOf(api.MarketBalance{})).(api.MarketBalance),
|
||||
})
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// because reflect.TypeOf(maddr) returns the concrete type...
|
||||
ExampleValues[reflect.TypeOf(struct{ A multiaddr.Multiaddr }{}).Field(0).Type] = maddr
|
||||
|
||||
}
|
||||
|
||||
func exampleValue(t reflect.Type) interface{} {
|
||||
v, ok := ExampleValues[t]
|
||||
if ok {
|
||||
return v
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
out := reflect.New(t).Elem()
|
||||
reflect.Append(out, reflect.ValueOf(exampleValue(t.Elem())))
|
||||
return out.Interface()
|
||||
case reflect.Chan:
|
||||
return exampleValue(t.Elem())
|
||||
case reflect.Struct:
|
||||
es := exampleStruct(t)
|
||||
v := reflect.ValueOf(es).Elem().Interface()
|
||||
ExampleValues[t] = v
|
||||
return v
|
||||
case reflect.Array:
|
||||
out := reflect.New(t).Elem()
|
||||
for i := 0; i < t.Len(); i++ {
|
||||
out.Index(i).Set(reflect.ValueOf(exampleValue(t.Elem())))
|
||||
}
|
||||
return out.Interface()
|
||||
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct {
|
||||
es := exampleStruct(t.Elem())
|
||||
//ExampleValues[t] = es
|
||||
return es
|
||||
}
|
||||
case reflect.Interface:
|
||||
return struct{}{}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("No example value for type: %s", t))
|
||||
}
|
||||
|
||||
func exampleStruct(t reflect.Type) interface{} {
|
||||
ns := reflect.New(t)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
if strings.Title(f.Name) == f.Name {
|
||||
ns.Elem().Field(i).Set(reflect.ValueOf(exampleValue(f.Type)))
|
||||
}
|
||||
}
|
||||
|
||||
return ns.Interface()
|
||||
}
|
||||
|
||||
type Visitor struct {
|
||||
Methods map[string]ast.Node
|
||||
}
|
||||
|
||||
func (v *Visitor) Visit(node ast.Node) ast.Visitor {
|
||||
st, ok := node.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
|
||||
if st.Name.Name != "FullNode" {
|
||||
return nil
|
||||
}
|
||||
|
||||
iface := st.Type.(*ast.InterfaceType)
|
||||
for _, m := range iface.Methods.List {
|
||||
if len(m.Names) > 0 {
|
||||
v.Methods[m.Names[0].Name] = m
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
const noComment = "There are not yet any comments for this method."
|
||||
|
||||
func parseApiASTInfo() (map[string]string, map[string]string) { //nolint:golint
|
||||
fset := token.NewFileSet()
|
||||
pkgs, err := parser.ParseDir(fset, "./api", nil, parser.AllErrors|parser.ParseComments)
|
||||
if err != nil {
|
||||
fmt.Println("parse error: ", err)
|
||||
}
|
||||
|
||||
ap := pkgs["api"]
|
||||
|
||||
f := ap.Files["api/api_full.go"]
|
||||
|
||||
cmap := ast.NewCommentMap(fset, f, f.Comments)
|
||||
|
||||
v := &Visitor{make(map[string]ast.Node)}
|
||||
ast.Walk(v, pkgs["api"])
|
||||
|
||||
groupDocs := make(map[string]string)
|
||||
out := make(map[string]string)
|
||||
for mn, node := range v.Methods {
|
||||
cs := cmap.Filter(node).Comments()
|
||||
if len(cs) == 0 {
|
||||
out[mn] = noComment
|
||||
} else {
|
||||
for _, c := range cs {
|
||||
if strings.HasPrefix(c.Text(), "MethodGroup:") {
|
||||
parts := strings.Split(c.Text(), "\n")
|
||||
groupName := strings.TrimSpace(parts[0][12:])
|
||||
comment := strings.Join(parts[1:], "\n")
|
||||
groupDocs[groupName] = comment
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
last := cs[len(cs)-1].Text()
|
||||
if !strings.HasPrefix(last, "MethodGroup:") {
|
||||
out[mn] = last
|
||||
} else {
|
||||
out[mn] = noComment
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, groupDocs
|
||||
}
|
||||
|
||||
type MethodGroup struct {
|
||||
GroupName string
|
||||
Header string
|
||||
Methods []*Method
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
Comment string
|
||||
Name string
|
||||
InputExample string
|
||||
ResponseExample string
|
||||
}
|
||||
|
||||
func methodGroupFromName(mn string) string {
|
||||
i := strings.IndexFunc(mn[1:], func(r rune) bool {
|
||||
return unicode.IsUpper(r)
|
||||
})
|
||||
if i < 0 {
|
||||
return ""
|
||||
}
|
||||
return mn[:i+1]
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
comments, groupComments := parseApiASTInfo()
|
||||
|
||||
groups := make(map[string]*MethodGroup)
|
||||
|
||||
var api struct{ api.FullNode }
|
||||
t := reflect.TypeOf(api)
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
m := t.Method(i)
|
||||
|
||||
groupName := methodGroupFromName(m.Name)
|
||||
|
||||
g, ok := groups[groupName]
|
||||
if !ok {
|
||||
g = new(MethodGroup)
|
||||
g.Header = groupComments[groupName]
|
||||
g.GroupName = groupName
|
||||
groups[groupName] = g
|
||||
}
|
||||
|
||||
var args []interface{}
|
||||
ft := m.Func.Type()
|
||||
for j := 2; j < ft.NumIn(); j++ {
|
||||
inp := ft.In(j)
|
||||
args = append(args, exampleValue(inp))
|
||||
}
|
||||
|
||||
v, err := json.Marshal(args)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
outv := exampleValue(ft.Out(0))
|
||||
|
||||
ov, err := json.Marshal(outv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
g.Methods = append(g.Methods, &Method{
|
||||
Name: m.Name,
|
||||
Comment: comments[m.Name],
|
||||
InputExample: string(v),
|
||||
ResponseExample: string(ov),
|
||||
})
|
||||
}
|
||||
|
||||
var groupslice []*MethodGroup
|
||||
for _, g := range groups {
|
||||
groupslice = append(groupslice, g)
|
||||
}
|
||||
|
||||
sort.Slice(groupslice, func(i, j int) bool {
|
||||
return groupslice[i].GroupName < groupslice[j].GroupName
|
||||
})
|
||||
|
||||
for _, g := range groupslice {
|
||||
g := g
|
||||
fmt.Printf("## %s\n", g.GroupName)
|
||||
fmt.Printf("%s\n\n", g.Header)
|
||||
|
||||
sort.Slice(g.Methods, func(i, j int) bool {
|
||||
return g.Methods[i].Name < g.Methods[j].Name
|
||||
})
|
||||
|
||||
for _, m := range g.Methods {
|
||||
fmt.Printf("### %s\n", m.Name)
|
||||
fmt.Printf("%s\n\n", m.Comment)
|
||||
|
||||
fmt.Printf("Inputs: `%s`\n\n", m.InputExample)
|
||||
fmt.Printf("Response: `%s`\n\n", m.ResponseExample)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -35,7 +35,7 @@ func init() {
|
||||
}
|
||||
|
||||
func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
@@ -72,7 +72,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
}
|
||||
|
||||
func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
@@ -193,14 +193,14 @@ func testRetrieval(t *testing.T, ctx context.Context, err error, client *impl.Fu
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(rpath)
|
||||
defer os.RemoveAll(rpath) //nolint:errcheck
|
||||
|
||||
caddr, err := client.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ref := api.FileRef{
|
||||
ref := &api.FileRef{
|
||||
Path: filepath.Join(rpath, "ret"),
|
||||
IsCAR: carExport,
|
||||
}
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExport bool) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
// test making a deal with a fresh miner, and see if it starts to mine
|
||||
|
||||
|
||||
+6
-4
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
@@ -21,6 +23,8 @@ type TestStorageNode struct {
|
||||
|
||||
var PresealGenesis = -1
|
||||
|
||||
const GenesisPreseals = 2
|
||||
|
||||
type StorageMiner struct {
|
||||
Full int
|
||||
Preseal int
|
||||
@@ -60,9 +64,7 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v.Version != build.BuildVersion {
|
||||
t.Error("Version didn't work properly")
|
||||
}
|
||||
require.Equal(t, v.Version, build.BuildVersion)
|
||||
}
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
sealing "github.com/filecoin-project/storage-fsm"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
addrinfo, err := client.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
|
||||
mine = false
|
||||
<-done
|
||||
}
|
||||
|
||||
func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
err := miner.PledgeSector(ctx)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for {
|
||||
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
||||
require.NoError(t, err)
|
||||
fmt.Printf("Sectors: %d\n", len(s))
|
||||
if len(s) >= n {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fmt.Printf("All sectors is fsm\n")
|
||||
|
||||
s, err := miner.SectorsList(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
toCheck := map[abi.SectorNumber]struct{}{}
|
||||
for _, number := range s {
|
||||
toCheck[number] = struct{}{}
|
||||
}
|
||||
|
||||
for len(toCheck) > 0 {
|
||||
for n := range toCheck {
|
||||
st, err := miner.SectorsStatus(ctx, n)
|
||||
require.NoError(t, err)
|
||||
if st.State == api.SectorState(sealing.Proving) {
|
||||
delete(toCheck, n)
|
||||
}
|
||||
if strings.Contains(string(st.State), "Fail") {
|
||||
t.Fatal("sector in a failed state", st.State)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Printf("WaitSeal: %d\n", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, oneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
addrinfo, err := client.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, func(bool) {}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors)
|
||||
|
||||
maddr, err := miner.ActorAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
di, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Running one proving periods\n")
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 {
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
time.Sleep(blocktime)
|
||||
}
|
||||
|
||||
p, err := client.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
ssz, err := miner.ActorSectorSize(ctx, maddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, p.MinerPower, p.TotalPower)
|
||||
require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+GenesisPreseals)))
|
||||
|
||||
// TODO: Inject faults here
|
||||
|
||||
mine = false
|
||||
<-done
|
||||
}
|
||||
@@ -3,10 +3,12 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// TODO: check if this exists anywhere else
|
||||
|
||||
type MultiaddrSlice []ma.Multiaddr
|
||||
|
||||
func (m *MultiaddrSlice) UnmarshalJSON(raw []byte) (err error) {
|
||||
@@ -32,3 +34,8 @@ type ObjStat struct {
|
||||
Size uint64
|
||||
Links uint64
|
||||
}
|
||||
|
||||
type PubsubScore struct {
|
||||
ID peer.ID
|
||||
Score float64
|
||||
}
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
/dns4/t01000.miner.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf
|
||||
/ip4/52.36.61.156/tcp/1347/p2p/12D3KooWFETiESTf1v4PGUvtnxMAcEFMzLZbJGg4tjWfGEimYior
|
||||
/dns4/t01000.miner.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWALjK9ai1gzssE4H9kwmS7CVqkENedeJJzmgVS9YMtLii
|
||||
/ip4/34.217.110.132/tcp/1347/p2p/12D3KooWALjK9ai1gzssE4H9kwmS7CVqkENedeJJzmgVS9YMtLii
|
||||
/dns4/peer0.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWSJYjQMi2MGaeyRAWvDnEAAC7GdFSRXk5Lns6G1ajSMA7
|
||||
/ip4/54.187.182.170/tcp/1347/p2p/12D3KooWSJYjQMi2MGaeyRAWvDnEAAC7GdFSRXk5Lns6G1ajSMA7
|
||||
/dns4/peer1.interopnet.kittyhawk.wtf/tcp/1347/p2p/12D3KooWPdeoNGcaGTxWdENfzEYJ9WqGVkJAxi2aHpX4TjkbeGkj
|
||||
/ip4/52.24.84.39/tcp/1347/p2p/12D3KooWPdeoNGcaGTxWdENfzEYJ9WqGVkJAxi2aHpX4TjkbeGkj
|
||||
|
||||
Binary file not shown.
+1
-1
@@ -2,6 +2,6 @@ package build
|
||||
|
||||
import rice "github.com/GeertJohan/go.rice"
|
||||
|
||||
func ParametersJson() []byte {
|
||||
func ParametersJSON() []byte {
|
||||
return rice.MustFindBox("proof-params").MustBytes("parameters.json")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -14,6 +15,9 @@ func init() {
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
}
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
// Seconds
|
||||
|
||||
@@ -4,6 +4,7 @@ package build
|
||||
|
||||
func init() {
|
||||
InsecurePoStValidation = true
|
||||
BuildType |= BuildDebug
|
||||
}
|
||||
|
||||
// NOTE: Also includes settings from params_2k
|
||||
|
||||
@@ -25,7 +25,7 @@ func DefaultSectorSize() abi.SectorSize {
|
||||
}
|
||||
|
||||
sort.Slice(szs, func(i, j int) bool {
|
||||
return szs[i] < szs[i]
|
||||
return szs[i] < szs[j]
|
||||
})
|
||||
|
||||
return szs[0]
|
||||
@@ -59,6 +59,7 @@ var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
|
||||
// Epochs
|
||||
const Finality = miner.ChainFinalityish
|
||||
const MessageConfidence = 5
|
||||
|
||||
// constants for Weight calculation
|
||||
// The ratio of weight contributed by short-term vs long-term factors in a given round
|
||||
@@ -109,16 +110,15 @@ const BadBlockCacheSize = 1 << 15
|
||||
// 10 block reorg.
|
||||
const BlsSignatureCacheSize = 40000
|
||||
|
||||
// Size of signature verification cache
|
||||
// 32k keeps the cache around 10MB in size, max
|
||||
const VerifSigCacheSize = 32000
|
||||
|
||||
// ///////
|
||||
// Limits
|
||||
|
||||
// TODO: If this is gonna stay, it should move to specs-actors
|
||||
const BlockMessageLimit = 512
|
||||
const BlockGasLimit = 100_000_000
|
||||
const BlockGasLimit = 100_000_000_000
|
||||
|
||||
var DrandCoeffs = []string{
|
||||
"82c279cce744450e68de98ee08f9698a01dd38f8e3be3c53f2b840fb9d09ad62a0b6b87981e179e1b14bc9a2d284c985",
|
||||
"82d51308ad346c686f81b8094551597d7b963295cbf313401a93df9baf52d5ae98a87745bee70839a4d6e65c342bd15b",
|
||||
"94eebfd53f4ba6a3b8304236400a12e73885e5a781509a5c8d41d2e8b476923d8ea6052649b3c17282f596217f96c5de",
|
||||
"8dc4231e42b4edf39e86ef1579401692480647918275da767d3e558c520d6375ad953530610fd27daf110187877a65d0",
|
||||
}
|
||||
var DrandChain = `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
power.ConsensusMinerMinPower = big.NewInt(2 << 30)
|
||||
power.ConsensusMinerMinPower = big.NewInt(1024 << 20)
|
||||
miner.SupportedProofTypes = map[abi.RegisteredProof]struct{}{
|
||||
abi.RegisteredProof_StackedDRG512MiBSeal: {},
|
||||
abi.RegisteredProof_StackedDRG32GiBSeal: {},
|
||||
|
||||
+25
-2
@@ -3,11 +3,33 @@ package build
|
||||
import "fmt"
|
||||
|
||||
var CurrentCommit string
|
||||
var BuildType int
|
||||
|
||||
const (
|
||||
BuildDefault = 0
|
||||
Build2k = 0x1
|
||||
BuildDebug = 0x3
|
||||
)
|
||||
|
||||
func buildType() string {
|
||||
switch BuildType {
|
||||
case BuildDefault:
|
||||
return ""
|
||||
case BuildDebug:
|
||||
return "+debug"
|
||||
case Build2k:
|
||||
return "+2k"
|
||||
default:
|
||||
return "+huh?"
|
||||
}
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.3.0"
|
||||
const BuildVersion = "0.4.0"
|
||||
|
||||
var UserVersion = BuildVersion + CurrentCommit
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
}
|
||||
|
||||
type Version uint32
|
||||
|
||||
@@ -33,6 +55,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
|
||||
// APIVersion is a semver version of the rpc api exposed
|
||||
var APIVersion Version = newVer(0, 3, 0)
|
||||
|
||||
//nolint:varcheck,deadcode
|
||||
const (
|
||||
majorMask = 0xff0000
|
||||
minorMask = 0xffff00
|
||||
|
||||
@@ -50,6 +50,7 @@ func Newf(retCode exitcode.ExitCode, format string, args ...interface{}) ActorEr
|
||||
}
|
||||
|
||||
// todo: bit hacky
|
||||
|
||||
func NewfSkip(skip int, retCode exitcode.ExitCode, format string, args ...interface{}) ActorError {
|
||||
if retCode == 0 {
|
||||
return &actorError{
|
||||
|
||||
+74
-116
@@ -1,45 +1,45 @@
|
||||
package drand
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
dchain "github.com/drand/drand/chain"
|
||||
dclient "github.com/drand/drand/client"
|
||||
gclient "github.com/drand/drand/cmd/relay-gossip/client"
|
||||
dlog "github.com/drand/drand/log"
|
||||
"github.com/drand/kyber"
|
||||
kzap "github.com/go-kit/kit/log/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
dbeacon "github.com/drand/drand/beacon"
|
||||
"github.com/drand/drand/core"
|
||||
dkey "github.com/drand/drand/key"
|
||||
dnet "github.com/drand/drand/net"
|
||||
dproto "github.com/drand/drand/protobuf/drand"
|
||||
)
|
||||
|
||||
var log = logging.Logger("drand")
|
||||
|
||||
var drandServers = []string{
|
||||
"nicolas.drand.fil-test.net:443",
|
||||
"philipp.drand.fil-test.net:443",
|
||||
"mathilde.drand.fil-test.net:443",
|
||||
"ludovic.drand.fil-test.net:443",
|
||||
"gabbi.drand.fil-test.net:443",
|
||||
"linus.drand.fil-test.net:443",
|
||||
"jeff.drand.fil-test.net:443",
|
||||
"https://pl-eu.testnet.drand.sh",
|
||||
"https://pl-us.testnet.drand.sh",
|
||||
"https://pl-sin.testnet.drand.sh",
|
||||
}
|
||||
|
||||
var drandPubKey *dkey.DistPublic
|
||||
var drandChain *dchain.Info
|
||||
|
||||
func init() {
|
||||
drandPubKey = new(dkey.DistPublic)
|
||||
err := drandPubKey.FromTOML(&dkey.DistPublicTOML{Coefficients: build.DrandCoeffs})
|
||||
|
||||
var err error
|
||||
drandChain, err = dchain.InfoFromJSON(bytes.NewReader([]byte(build.DrandChain)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic("could not unmarshal chain info: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +57,9 @@ func (dp *drandPeer) IsTLS() bool {
|
||||
}
|
||||
|
||||
type DrandBeacon struct {
|
||||
client dnet.Client
|
||||
client dclient.Client
|
||||
|
||||
peers []dnet.Peer
|
||||
peersIndex int
|
||||
peersIndexMtx sync.Mutex
|
||||
|
||||
pubkey *dkey.DistPublic
|
||||
pubkey kyber.Point
|
||||
|
||||
// seconds
|
||||
interval time.Duration
|
||||
@@ -76,120 +72,83 @@ type DrandBeacon struct {
|
||||
localCache map[uint64]types.BeaconEntry
|
||||
}
|
||||
|
||||
func NewDrandBeacon(genesisTs, interval uint64) (*DrandBeacon, error) {
|
||||
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon, error) {
|
||||
if genesisTs == 0 {
|
||||
panic("what are you doing this cant be zero")
|
||||
}
|
||||
|
||||
dlogger := dlog.NewKitLoggerFrom(kzap.NewZapSugarLogger(
|
||||
log.SugaredLogger.Desugar(), zapcore.InfoLevel))
|
||||
opts := []dclient.Option{
|
||||
dclient.WithChainInfo(drandChain),
|
||||
dclient.WithHTTPEndpoints(drandServers),
|
||||
dclient.WithCacheSize(1024),
|
||||
dclient.WithLogger(dlogger),
|
||||
}
|
||||
|
||||
if ps != nil {
|
||||
opts = append(opts, gclient.WithPubsub(ps))
|
||||
} else {
|
||||
log.Info("drand beacon without pubsub")
|
||||
}
|
||||
|
||||
client, err := dclient.New(opts...)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("creating drand client")
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Explicitly Watch until that is fixed in drand
|
||||
ch := client.Watch(context.Background())
|
||||
for range ch {
|
||||
}
|
||||
log.Error("dranch Watch bork")
|
||||
}()
|
||||
|
||||
db := &DrandBeacon{
|
||||
client: dnet.NewGrpcClient(),
|
||||
client: client,
|
||||
localCache: make(map[uint64]types.BeaconEntry),
|
||||
}
|
||||
for _, ds := range drandServers {
|
||||
db.peers = append(db.peers, &drandPeer{addr: ds, tls: true})
|
||||
}
|
||||
|
||||
db.peersIndex = rand.Intn(len(db.peers))
|
||||
|
||||
groupResp, err := db.client.Group(context.TODO(), db.peers[db.peersIndex], &dproto.GroupRequest{})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get group response from beacon peer: %w", err)
|
||||
}
|
||||
|
||||
kgroup, err := core.ProtoToGroup(groupResp)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to parse group response: %w", err)
|
||||
}
|
||||
|
||||
// TODO: verify these values are what we expect them to be
|
||||
if !kgroup.PublicKey.Equal(drandPubKey) {
|
||||
return nil, xerrors.Errorf("public key does not match")
|
||||
}
|
||||
// fmt.Printf("Drand Pubkey:\n%#v\n", kgroup.PublicKey.TOML()) // use to print public key
|
||||
db.pubkey = drandPubKey
|
||||
db.interval = kgroup.Period
|
||||
db.drandGenTime = uint64(kgroup.GenesisTime)
|
||||
db.pubkey = drandChain.PublicKey
|
||||
db.interval = drandChain.Period
|
||||
db.drandGenTime = uint64(drandChain.GenesisTime)
|
||||
db.filRoundTime = interval
|
||||
db.filGenTime = genesisTs
|
||||
|
||||
// TODO: the stream currently gives you back *all* values since drand genesis.
|
||||
// Having the stream in the background is merely an optimization, so not a big deal to disable it for now
|
||||
// go db.handleStreamingUpdates()
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) rotatePeersIndex() {
|
||||
db.peersIndexMtx.Lock()
|
||||
nval := rand.Intn(len(db.peers))
|
||||
db.peersIndex = nval
|
||||
db.peersIndexMtx.Unlock()
|
||||
|
||||
log.Warnf("rotated to drand peer %d, %q", nval, db.peers[nval].Address())
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) getPeerIndex() int {
|
||||
db.peersIndexMtx.Lock()
|
||||
defer db.peersIndexMtx.Unlock()
|
||||
return db.peersIndex
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) handleStreamingUpdates() {
|
||||
for {
|
||||
p := db.peers[db.getPeerIndex()]
|
||||
ch, err := db.client.PublicRandStream(context.Background(), p, &dproto.PublicRandRequest{})
|
||||
if err != nil {
|
||||
log.Warnf("failed to get public rand stream to peer %q: %s", p.Address(), err)
|
||||
log.Warnf("trying again in 10 seconds")
|
||||
db.rotatePeersIndex()
|
||||
time.Sleep(time.Second * 10)
|
||||
continue
|
||||
}
|
||||
|
||||
for e := range ch {
|
||||
db.cacheValue(types.BeaconEntry{
|
||||
Round: e.Round,
|
||||
Data: e.Signature,
|
||||
})
|
||||
}
|
||||
|
||||
log.Warnf("drand beacon stream to peer %q broke, reconnecting in 10 seconds", p.Address())
|
||||
db.rotatePeersIndex()
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.Response {
|
||||
// check cache, it it if there, otherwise query the endpoint
|
||||
cres := db.getCachedValue(round)
|
||||
if cres != nil {
|
||||
out := make(chan beacon.Response, 1)
|
||||
out <- beacon.Response{Entry: *cres}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
|
||||
out := make(chan beacon.Response, 1)
|
||||
if round != 0 {
|
||||
be := db.getCachedValue(round)
|
||||
if be != nil {
|
||||
out <- beacon.Response{Entry: *be}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
p := db.peers[db.getPeerIndex()]
|
||||
resp, err := db.client.PublicRand(ctx, p, &dproto.PublicRandRequest{Round: round})
|
||||
start := time.Now()
|
||||
log.Infow("start fetching randomness", "round", round)
|
||||
resp, err := db.client.Get(ctx, round)
|
||||
|
||||
var br beacon.Response
|
||||
if err != nil {
|
||||
db.rotatePeersIndex()
|
||||
br.Err = xerrors.Errorf("drand peer %q failed publicRand request: %w", p.Address(), err)
|
||||
br.Err = xerrors.Errorf("drand failed Get request: %w", err)
|
||||
} else {
|
||||
br.Entry.Round = resp.GetRound()
|
||||
br.Entry.Data = resp.GetSignature()
|
||||
br.Entry.Round = resp.Round()
|
||||
br.Entry.Data = resp.Signature()
|
||||
}
|
||||
|
||||
log.Infow("done fetching randomness", "round", round, "took", time.Since(start))
|
||||
out <- br
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) cacheValue(e types.BeaconEntry) {
|
||||
db.cacheLk.Lock()
|
||||
defer db.cacheLk.Unlock()
|
||||
@@ -211,13 +170,12 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr
|
||||
// TODO handle genesis better
|
||||
return nil
|
||||
}
|
||||
b := &dbeacon.Beacon{
|
||||
b := &dchain.Beacon{
|
||||
PreviousSig: prev.Data,
|
||||
Round: curr.Round,
|
||||
Signature: curr.Data,
|
||||
}
|
||||
//log.Warnw("VerifyEntry", "beacon", b)
|
||||
err := dbeacon.VerifyBeacon(db.pubkey.Key(), b)
|
||||
err := dchain.VerifyBeacon(db.pubkey, b)
|
||||
if err == nil {
|
||||
db.cacheValue(curr)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
package drand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
dchain "github.com/drand/drand/chain"
|
||||
dclient "github.com/drand/drand/client"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPrintDrandPubkey(t *testing.T) {
|
||||
bc, err := NewDrandBeacon(1, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("Drand Pubkey:\n%#v\n", bc.pubkey.TOML())
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
c, err := dclient.NewHTTPClient(drandServers[0], nil, nil)
|
||||
assert.NoError(t, err)
|
||||
cg := c.(interface {
|
||||
FetchChainInfo(groupHash []byte) (*dchain.Info, error)
|
||||
})
|
||||
chain, err := cg.FetchChainInfo(nil)
|
||||
assert.NoError(t, err)
|
||||
err = chain.ToJSON(os.Stdout)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
|
||||
ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream")
|
||||
defer span.End()
|
||||
|
||||
defer s.Close()
|
||||
defer s.Close() //nolint:errcheck
|
||||
|
||||
var req BlockSyncRequest
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(s), &req); err != nil {
|
||||
@@ -107,7 +107,7 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
|
||||
}
|
||||
|
||||
writeDeadline := 60 * time.Second
|
||||
s.SetDeadline(time.Now().Add(writeDeadline))
|
||||
_ = s.SetDeadline(time.Now().Add(writeDeadline))
|
||||
if err := cborutil.WriteCborRPC(s, resp); err != nil {
|
||||
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
|
||||
return
|
||||
|
||||
@@ -283,14 +283,14 @@ func (bs *BlockSync) fetchBlocksBlockSync(ctx context.Context, p peer.ID, req *B
|
||||
bs.RemovePeer(p)
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
s.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
_ = s.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
|
||||
if err := cborutil.WriteCborRPC(s, req); err != nil {
|
||||
s.SetWriteDeadline(time.Time{})
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
s.SetWriteDeadline(time.Time{})
|
||||
_ = s.SetWriteDeadline(time.Time{})
|
||||
|
||||
var res BlockSyncResponse
|
||||
r := incrt.New(s, 50<<10, 5*time.Second)
|
||||
@@ -561,26 +561,30 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
|
||||
if pi, ok := bpt.peers[p]; !ok {
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warnw("log success called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
} else {
|
||||
pi.successes++
|
||||
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
pi.successes++
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) {
|
||||
bpt.lk.Lock()
|
||||
defer bpt.lk.Unlock()
|
||||
if pi, ok := bpt.peers[p]; !ok {
|
||||
|
||||
var pi *peerStats
|
||||
var ok bool
|
||||
if pi, ok = bpt.peers[p]; !ok {
|
||||
log.Warn("log failure called on peer not in tracker", "peerid", p.String())
|
||||
return
|
||||
} else {
|
||||
pi.failures++
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
pi.failures++
|
||||
logTime(pi, dur)
|
||||
}
|
||||
|
||||
func (bpt *bsPeerTracker) removePeer(p peer.ID) {
|
||||
|
||||
+14
-8
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
var log = logging.Logger("events")
|
||||
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
// HeightHandler `curH`-`ts.Height` = `confidence`
|
||||
type HeightHandler func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error
|
||||
type RevertHandler func(ctx context.Context, ts *types.TipSet) error
|
||||
|
||||
@@ -31,17 +31,18 @@ type heightHandler struct {
|
||||
revert RevertHandler
|
||||
}
|
||||
|
||||
type eventApi interface {
|
||||
type eventAPI interface {
|
||||
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
||||
ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) // optional / for CalledMsg
|
||||
}
|
||||
|
||||
type Events struct {
|
||||
api eventApi
|
||||
api eventAPI
|
||||
|
||||
tsc *tipSetCache
|
||||
lk sync.Mutex
|
||||
@@ -53,7 +54,7 @@ type Events struct {
|
||||
calledEvents
|
||||
}
|
||||
|
||||
func NewEvents(ctx context.Context, api eventApi) *Events {
|
||||
func NewEvents(ctx context.Context, api eventAPI) *Events {
|
||||
gcConfidence := 2 * build.ForkLengthThreshold
|
||||
|
||||
tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight)
|
||||
@@ -66,7 +67,7 @@ func NewEvents(ctx context.Context, api eventApi) *Events {
|
||||
heightEvents: heightEvents{
|
||||
tsc: tsc,
|
||||
ctx: ctx,
|
||||
gcConfidence: abi.ChainEpoch(gcConfidence),
|
||||
gcConfidence: gcConfidence,
|
||||
|
||||
heightTriggers: map[uint64]*heightHandler{},
|
||||
htTriggerHeights: map[abi.ChainEpoch][]uint64{},
|
||||
@@ -81,9 +82,9 @@ func NewEvents(ctx context.Context, api eventApi) *Events {
|
||||
|
||||
confQueue: map[triggerH]map[msgH][]*queuedEvent{},
|
||||
revertQueue: map[msgH][]triggerH{},
|
||||
triggers: map[triggerId]*callHandler{},
|
||||
matchers: map[triggerId][]MatchFunc{},
|
||||
timeouts: map[abi.ChainEpoch]map[triggerId]int{},
|
||||
triggers: map[triggerID]*callHandler{},
|
||||
matchers: map[triggerID][]MatchFunc{},
|
||||
timeouts: map[abi.ChainEpoch]map[triggerID]int{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -163,6 +164,11 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error {
|
||||
if err := e.headChange(rev, app); err != nil {
|
||||
log.Warnf("headChange failed: %s", err)
|
||||
}
|
||||
|
||||
// sync with fake chainstore (for tests)
|
||||
if fcs, ok := e.api.(interface{ notifDone() }); ok {
|
||||
fcs.notifDone()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
const NoTimeout = math.MaxInt64
|
||||
|
||||
type triggerId = uint64
|
||||
type triggerID = uint64
|
||||
|
||||
// msgH is the block height at which a message was present / event has happened
|
||||
type msgH = abi.ChainEpoch
|
||||
@@ -23,6 +23,7 @@ type msgH = abi.ChainEpoch
|
||||
// message (msgH+confidence)
|
||||
type triggerH = abi.ChainEpoch
|
||||
|
||||
// CalledHandler arguments:
|
||||
// `ts` is the tipset, in which the `msg` is included.
|
||||
// `curH`-`ts.Height` = `confidence`
|
||||
type CalledHandler func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error)
|
||||
@@ -48,7 +49,7 @@ type callHandler struct {
|
||||
}
|
||||
|
||||
type queuedEvent struct {
|
||||
trigger triggerId
|
||||
trigger triggerID
|
||||
|
||||
h abi.ChainEpoch
|
||||
msg *types.Message
|
||||
@@ -57,7 +58,7 @@ type queuedEvent struct {
|
||||
}
|
||||
|
||||
type calledEvents struct {
|
||||
cs eventApi
|
||||
cs eventAPI
|
||||
tsc *tipSetCache
|
||||
ctx context.Context
|
||||
gcConfidence uint64
|
||||
@@ -66,10 +67,10 @@ type calledEvents struct {
|
||||
|
||||
lk sync.Mutex
|
||||
|
||||
ctr triggerId
|
||||
ctr triggerID
|
||||
|
||||
triggers map[triggerId]*callHandler
|
||||
matchers map[triggerId][]MatchFunc
|
||||
triggers map[triggerID]*callHandler
|
||||
matchers map[triggerID][]MatchFunc
|
||||
|
||||
// maps block heights to events
|
||||
// [triggerH][msgH][event]
|
||||
@@ -78,8 +79,8 @@ type calledEvents struct {
|
||||
// [msgH][triggerH]
|
||||
revertQueue map[msgH][]triggerH
|
||||
|
||||
// [timeoutH+confidence][triggerId]{calls}
|
||||
timeouts map[abi.ChainEpoch]map[triggerId]int
|
||||
// [timeoutH+confidence][triggerID]{calls}
|
||||
timeouts map[abi.ChainEpoch]map[triggerID]int
|
||||
}
|
||||
|
||||
func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error {
|
||||
@@ -125,7 +126,13 @@ func (e *calledEvents) handleReverts(ts *types.TipSet) {
|
||||
}
|
||||
|
||||
func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
|
||||
e.messagesForTs(ts, func(msg *types.Message) {
|
||||
pts, err := e.cs.ChainGetTipSet(e.ctx, ts.Parents()) // we actually care about messages in the parent tipset here
|
||||
if err != nil {
|
||||
log.Errorf("getting parent tipset in checkNewCalls: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
e.messagesForTs(pts, func(msg *types.Message) {
|
||||
// TODO: provide receipts
|
||||
|
||||
for tid, matchFns := range e.matchers {
|
||||
@@ -151,11 +158,10 @@ func (e *calledEvents) checkNewCalls(ts *types.TipSet) {
|
||||
})
|
||||
}
|
||||
|
||||
func (e *calledEvents) queueForConfidence(triggerId uint64, msg *types.Message, ts *types.TipSet) {
|
||||
trigger := e.triggers[triggerId]
|
||||
func (e *calledEvents) queueForConfidence(trigID uint64, msg *types.Message, ts *types.TipSet) {
|
||||
trigger := e.triggers[trigID]
|
||||
|
||||
// messages are not applied in the tipset they are included in
|
||||
appliedH := ts.Height() + 1
|
||||
appliedH := ts.Height()
|
||||
|
||||
triggerH := appliedH + abi.ChainEpoch(trigger.confidence)
|
||||
|
||||
@@ -166,7 +172,7 @@ func (e *calledEvents) queueForConfidence(triggerId uint64, msg *types.Message,
|
||||
}
|
||||
|
||||
byOrigH[appliedH] = append(byOrigH[appliedH], &queuedEvent{
|
||||
trigger: triggerId,
|
||||
trigger: trigID,
|
||||
h: appliedH,
|
||||
msg: msg,
|
||||
})
|
||||
@@ -226,11 +232,11 @@ func (e *calledEvents) applyTimeouts(ts *types.TipSet) {
|
||||
return // nothing to do
|
||||
}
|
||||
|
||||
for triggerId, calls := range triggers {
|
||||
for triggerID, calls := range triggers {
|
||||
if calls > 0 {
|
||||
continue // don't timeout if the method was called
|
||||
}
|
||||
trigger := e.triggers[triggerId]
|
||||
trigger := e.triggers[triggerID]
|
||||
if trigger.disabled {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ type heightEvents struct {
|
||||
tsc *tipSetCache
|
||||
gcConfidence abi.ChainEpoch
|
||||
|
||||
ctr triggerId
|
||||
ctr triggerID
|
||||
|
||||
heightTriggers map[triggerId]*heightHandler
|
||||
heightTriggers map[triggerID]*heightHandler
|
||||
|
||||
htTriggerHeights map[triggerH][]triggerId
|
||||
htHeights map[msgH][]triggerId
|
||||
htTriggerHeights map[triggerH][]triggerID
|
||||
htHeights map[msgH][]triggerID
|
||||
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
+149
-31
@@ -3,21 +3,20 @@ package events
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -40,9 +39,17 @@ type fakeCS struct {
|
||||
msgs map[cid.Cid]fakeMsg
|
||||
blkMsgs map[cid.Cid]cid.Cid
|
||||
|
||||
sync sync.Mutex
|
||||
|
||||
tipsets map[types.TipSetKey]*types.TipSet
|
||||
|
||||
sub func(rev, app []*types.TipSet)
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
|
||||
return fcs.tipsets[key], nil
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -55,7 +62,7 @@ func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types
|
||||
panic("Not Implemented")
|
||||
}
|
||||
|
||||
func makeTs(t *testing.T, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
|
||||
func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
|
||||
a, _ := address.NewFromString("t00")
|
||||
b, _ := address.NewFromString("t02")
|
||||
var ts, err = types.NewTipSet([]*types.BlockHeader{
|
||||
@@ -63,6 +70,8 @@ func makeTs(t *testing.T, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
|
||||
Height: h,
|
||||
Miner: a,
|
||||
|
||||
Parents: parents,
|
||||
|
||||
Ticket: &types.Ticket{VRFProof: []byte{byte(h % 2)}},
|
||||
|
||||
ParentStateRoot: dummyCid,
|
||||
@@ -76,6 +85,8 @@ func makeTs(t *testing.T, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
|
||||
Height: h,
|
||||
Miner: b,
|
||||
|
||||
Parents: parents,
|
||||
|
||||
Ticket: &types.Ticket{VRFProof: []byte{byte((h + 1) % 2)}},
|
||||
|
||||
ParentStateRoot: dummyCid,
|
||||
@@ -87,6 +98,11 @@ func makeTs(t *testing.T, h abi.ChainEpoch, msgcid cid.Cid) *types.TipSet {
|
||||
},
|
||||
})
|
||||
|
||||
if fcs.tipsets == nil {
|
||||
fcs.tipsets = map[types.TipSetKey]*types.TipSet{}
|
||||
}
|
||||
fcs.tipsets[ts.Key()] = ts
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
return ts
|
||||
@@ -180,7 +196,7 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
|
||||
continue
|
||||
}
|
||||
|
||||
ts := makeTs(fcs.t, fcs.h, mc)
|
||||
ts := fcs.makeTs(fcs.t, fcs.tsc.best().Key().Cids(), fcs.h, mc)
|
||||
require.NoError(fcs.t, fcs.tsc.add(ts))
|
||||
|
||||
if hasMsgs {
|
||||
@@ -190,11 +206,19 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
|
||||
apps = append(apps, ts)
|
||||
}
|
||||
|
||||
fcs.sync.Lock()
|
||||
|
||||
fcs.sub(revs, apps)
|
||||
time.Sleep(100 * time.Millisecond) // TODO: :c
|
||||
|
||||
fcs.sync.Lock()
|
||||
fcs.sync.Unlock() //nolint:staticcheck
|
||||
}
|
||||
|
||||
var _ eventApi = &fakeCS{}
|
||||
func (fcs *fakeCS) notifDone() {
|
||||
fcs.sync.Unlock()
|
||||
}
|
||||
|
||||
var _ eventAPI = &fakeCS{}
|
||||
|
||||
func TestAt(t *testing.T) {
|
||||
fcs := &fakeCS{
|
||||
@@ -202,7 +226,7 @@ func TestAt(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -267,7 +291,7 @@ func TestAtDoubleTrigger(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -309,7 +333,7 @@ func TestAtNullTrigger(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -343,7 +367,7 @@ func TestAtNullConf(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -382,7 +406,7 @@ func TestAtStart(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -416,7 +440,7 @@ func TestAtStartConfidence(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -446,7 +470,7 @@ func TestAtChained(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -480,7 +504,7 @@ func TestAtChainedConfidence(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -514,7 +538,7 @@ func TestAtChainedConfidenceNull(t *testing.T) {
|
||||
h: 1,
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -552,7 +576,7 @@ func TestCalled(t *testing.T) {
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -628,7 +652,7 @@ func TestCalled(t *testing.T) {
|
||||
|
||||
// revert the message
|
||||
|
||||
fcs.advance(2, 1, nil) // H=7, we reverted ts with the msg
|
||||
fcs.advance(2, 1, nil) // H=7, we reverted ts with the msg execution, but not the msg itself
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, true, reverted)
|
||||
@@ -642,10 +666,17 @@ func TestCalled(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
fcs.advance(0, 5, map[int]cid.Cid{ // (confidence=3)
|
||||
fcs.advance(0, 3, map[int]cid.Cid{ // (n2msg confidence=1)
|
||||
0: n2msg,
|
||||
})
|
||||
|
||||
require.Equal(t, true, applied) // msg from H=7, which had reverted execution
|
||||
require.Equal(t, false, reverted)
|
||||
require.Equal(t, abi.ChainEpoch(10), appliedH)
|
||||
applied = false
|
||||
|
||||
fcs.advance(0, 2, nil) // (confidence=3)
|
||||
|
||||
require.Equal(t, true, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
applied = false
|
||||
@@ -659,7 +690,7 @@ func TestCalled(t *testing.T) {
|
||||
|
||||
// revert and apply at different height
|
||||
|
||||
fcs.advance(4, 6, map[int]cid.Cid{ // (confidence=3)
|
||||
fcs.advance(8, 6, map[int]cid.Cid{ // (confidence=3)
|
||||
1: n2msg,
|
||||
})
|
||||
|
||||
@@ -671,9 +702,9 @@ func TestCalled(t *testing.T) {
|
||||
reverted = false
|
||||
applied = false
|
||||
|
||||
require.Equal(t, abi.ChainEpoch(11), appliedTs.Height())
|
||||
require.Equal(t, abi.ChainEpoch(7), appliedTs.Height())
|
||||
require.Equal(t, "bafkqaaa", appliedTs.Blocks()[0].Messages.String())
|
||||
require.Equal(t, abi.ChainEpoch(14), appliedH)
|
||||
require.Equal(t, abi.ChainEpoch(10), appliedH)
|
||||
require.Equal(t, t0123, appliedMsg.To)
|
||||
require.Equal(t, uint64(2), appliedMsg.Nonce)
|
||||
require.Equal(t, abi.MethodNum(5), appliedMsg.Method)
|
||||
@@ -697,7 +728,7 @@ func TestCalled(t *testing.T) {
|
||||
}),
|
||||
})
|
||||
|
||||
fcs.advance(1, 4, nil) // H=19, but message reverted
|
||||
fcs.advance(2, 5, nil) // H=19, but message reverted
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
@@ -757,7 +788,7 @@ func TestCalledTimeout(t *testing.T) {
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -797,7 +828,7 @@ func TestCalledTimeout(t *testing.T) {
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events = NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -831,7 +862,7 @@ func TestCalledOrder(t *testing.T) {
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -894,7 +925,7 @@ func TestCalledNull(t *testing.T) {
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid)))
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
@@ -949,3 +980,90 @@ func TestCalledNull(t *testing.T) {
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, true, reverted)
|
||||
}
|
||||
|
||||
func TestRemoveTriggersOnMessage(t *testing.T) {
|
||||
fcs := &fakeCS{
|
||||
t: t,
|
||||
h: 1,
|
||||
|
||||
msgs: map[cid.Cid]fakeMsg{},
|
||||
blkMsgs: map[cid.Cid]cid.Cid{},
|
||||
tsc: newTSCache(2*build.ForkLengthThreshold, nil),
|
||||
}
|
||||
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
|
||||
|
||||
events := NewEvents(context.Background(), fcs)
|
||||
|
||||
t0123, err := address.NewFromString("t0123")
|
||||
require.NoError(t, err)
|
||||
|
||||
more := true
|
||||
var applied, reverted bool
|
||||
|
||||
err = events.Called(func(ts *types.TipSet) (d bool, m bool, e error) {
|
||||
return false, true, nil
|
||||
}, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) {
|
||||
require.Equal(t, false, applied)
|
||||
fmt.Println(msg == nil)
|
||||
fmt.Println(curH)
|
||||
applied = true
|
||||
return more, nil
|
||||
}, func(_ context.Context, ts *types.TipSet) error {
|
||||
reverted = true
|
||||
return nil
|
||||
}, 3, 20, matchAddrMethod(t0123, 5))
|
||||
require.NoError(t, err)
|
||||
|
||||
// create few blocks to make sure nothing get's randomly called
|
||||
|
||||
fcs.advance(0, 4, nil) // H=5
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create blocks with message (but below confidence threshold)
|
||||
|
||||
fcs.advance(0, 3, map[int]cid.Cid{ // msg occurs at H=5, applied at H=6; H=8 (confidence=2)
|
||||
0: fcs.fakeMsgs(fakeMsg{
|
||||
bmsgs: []*types.Message{
|
||||
{To: t0123, From: t0123, Method: 5, Nonce: 1},
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// revert applied TS & message TS
|
||||
fcs.advance(3, 1, nil) // H=6 (tipset message applied in reverted, AND message reverted)
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create additional blocks so we are above confidence threshold, but message not applied
|
||||
// as it was reverted
|
||||
fcs.advance(0, 5, nil) // H=11 (confidence=3, apply)
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create blocks with message again (but below confidence threshold)
|
||||
|
||||
fcs.advance(0, 3, map[int]cid.Cid{ // msg occurs at H=12, applied at H=13; H=15 (confidence=2)
|
||||
0: fcs.fakeMsgs(fakeMsg{
|
||||
bmsgs: []*types.Message{
|
||||
{To: t0123, From: t0123, Method: 5, Nonce: 2},
|
||||
},
|
||||
}),
|
||||
})
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// revert applied height TS, but don't remove message trigger
|
||||
fcs.advance(2, 1, nil) // H=13 (tipset message applied in reverted, by tipset with message not reverted)
|
||||
require.Equal(t, false, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
|
||||
// create additional blocks so we are above confidence threshold
|
||||
fcs.advance(0, 4, nil) // H=18 (confidence=3, apply)
|
||||
|
||||
require.Equal(t, true, applied)
|
||||
require.Equal(t, false, reverted)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg types.ChainMsg, hnd Ca
|
||||
func (e *calledEvents) MatchMsg(inmsg *types.Message) MatchFunc {
|
||||
return func(msg *types.Message) (bool, error) {
|
||||
if msg.From == inmsg.From && msg.Nonce == inmsg.Nonce && !inmsg.Equals(msg) {
|
||||
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %s", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
return false, xerrors.Errorf("matching msg %s from %s, nonce %d: got duplicate origin/nonce msg %d", inmsg.Cid(), inmsg.From, inmsg.Nonce, msg.Nonce)
|
||||
}
|
||||
|
||||
return inmsg.Equals(msg), nil
|
||||
|
||||
+6
-9
@@ -104,7 +104,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, xerrors.Errorf("failed to get metadata datastore: %w", err)
|
||||
}
|
||||
|
||||
bds, err := lr.Datastore("/blocks")
|
||||
bds, err := lr.Datastore("/chain")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get blocks datastore: %w", err)
|
||||
}
|
||||
@@ -219,6 +219,10 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
miners := []address.Address{maddr1, maddr2}
|
||||
|
||||
beac := beacon.NewMockBeacon(time.Second)
|
||||
//beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelay)
|
||||
//if err != nil {
|
||||
//return nil, xerrors.Errorf("creating drand beacon: %w", err)
|
||||
//}
|
||||
|
||||
gen := &ChainGen{
|
||||
bs: bs,
|
||||
@@ -427,7 +431,7 @@ func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticke
|
||||
return fblk, err
|
||||
}
|
||||
|
||||
// This function is awkward. It's used to deal with messages made when
|
||||
// ResyncBankerNonce is used for dealing with messages made when
|
||||
// simulating forks
|
||||
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
||||
act, err := cg.sm.GetActor(cg.banker, ts)
|
||||
@@ -534,13 +538,6 @@ func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoSt
|
||||
}}, nil
|
||||
}
|
||||
|
||||
type ProofInput struct {
|
||||
sectors []abi.SectorInfo
|
||||
hvrf []byte
|
||||
challengedSectors []uint64
|
||||
vrfout []byte
|
||||
}
|
||||
|
||||
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
|
||||
miner address.Address, brand types.BeaconEntry, mbi *api.MiningBaseInfo, a MiningCheckAPI) (*types.ElectionProof, error) {
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
@@ -17,6 +18,7 @@ func init() {
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
func testGeneration(t testing.TB, n int, msgs int, sectors int) {
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -20,6 +22,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
)
|
||||
|
||||
@@ -215,9 +218,72 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
}
|
||||
}
|
||||
|
||||
vregroot, err := address.NewIDAddress(80)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vrst, err := cst.Put(ctx, &account.State{Address: RootVerifierAddr})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = state.SetActor(vregroot, &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Balance: types.NewInt(0),
|
||||
Head: vrst,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setting account from actmap: %w", err)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template) (cid.Cid, error) {
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
for _, m := range template.Miners {
|
||||
for _, s := range m.Sectors {
|
||||
amt := s.Deal.PieceSize
|
||||
verifNeeds[s.Deal.Client] += amt
|
||||
sum += amt
|
||||
}
|
||||
}
|
||||
|
||||
verifier, err := address.NewIDAddress(80)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, RootVerifierAddr, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{
|
||||
Address: verifier,
|
||||
Allowance: abi.NewStoragePower(int64(sum)), // eh, close enough
|
||||
|
||||
}))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to failed to create verifier: %w", err)
|
||||
}
|
||||
|
||||
for c, amt := range verifNeeds {
|
||||
_, err := doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifier, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifiedClient, mustEnc(&verifreg.AddVerifiedClientParams{
|
||||
Address: c,
|
||||
Allowance: abi.NewStoragePower(int64(amt)),
|
||||
}))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to add verified client: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return vm.Flush(ctx)
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Syscalls, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
st, err := MakeInitialStateTree(ctx, bs, template)
|
||||
if err != nil {
|
||||
@@ -231,6 +297,13 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
|
||||
|
||||
// temp chainstore
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
|
||||
|
||||
// Verify PreSealed Data
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to verify presealed data: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup storage miners failed: %w", err)
|
||||
|
||||
@@ -58,6 +58,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
for i, m := range miners {
|
||||
// Create miner through power actor
|
||||
i := i
|
||||
m := m
|
||||
|
||||
spt, err := ffiwrapper.SealProofTypeFromSectorSize(m.SectorSize)
|
||||
if err != nil {
|
||||
@@ -69,7 +71,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
constructorParams := &power.CreateMinerParams{
|
||||
Owner: m.Worker,
|
||||
Worker: m.Worker,
|
||||
Peer: m.PeerId,
|
||||
Peer: []byte(m.PeerId),
|
||||
SealProofType: spt,
|
||||
}
|
||||
|
||||
@@ -130,6 +132,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
params := &market.PublishStorageDealsParams{}
|
||||
for _, preseal := range m.Sectors {
|
||||
preseal.Deal.VerifiedDeal = true
|
||||
params.Deals = append(params.Deals, market.ClientDealProposal{
|
||||
Proposal: preseal.Deal,
|
||||
ClientSignature: crypto.Signature{Type: crypto.SigTypeBLS}, // TODO: do we want to sign these? Or do we want to fake signatures for genesis setup?
|
||||
@@ -153,6 +156,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
// Commit sectors
|
||||
for pi, preseal := range m.Sectors {
|
||||
preseal := preseal
|
||||
// TODO: Maybe check seal (Can just be snark inputs, doesn't go into the genesis file)
|
||||
|
||||
// check deals, get dealWeight
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
@@ -45,6 +46,10 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi
|
||||
}
|
||||
}
|
||||
|
||||
if err := amap.Set(context.TODO(), string(RootVerifierAddr.Bytes()), 80); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := amap.Flush(context.TODO()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
@@ -15,6 +14,26 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var RootVerifierAddr address.Address
|
||||
|
||||
var RootVerifierID address.Address
|
||||
|
||||
func init() {
|
||||
k, err := address.NewFromString("t3qfoulel6fy6gn3hjmbhpdpf6fs5aqjb5fkurhtwvgssizq4jey5nw4ptq5up6h7jk7frdvvobv52qzmgjinq")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
RootVerifierAddr = k
|
||||
|
||||
idk, err := address.NewFromString("t080")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
RootVerifierID = idk
|
||||
}
|
||||
|
||||
func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
cst := cbor.NewCborStore(bs)
|
||||
|
||||
@@ -23,11 +42,7 @@ func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var r [32]byte // TODO: grab from genesis template
|
||||
_, _ = rand.Read(r[:])
|
||||
k, _ := address.NewSecp256k1Address(r[:])
|
||||
|
||||
sms := verifreg.ConstructState(h, k)
|
||||
sms := verifreg.ConstructState(h, RootVerifierID)
|
||||
|
||||
stcid, err := cst.Put(context.TODO(), sms)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
@@ -87,6 +88,8 @@ type MessagePool struct {
|
||||
localMsgs datastore.Datastore
|
||||
|
||||
netName dtypes.NetworkName
|
||||
|
||||
sigValCache *lru.TwoQueueCache
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
@@ -180,6 +183,8 @@ func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
|
||||
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||
|
||||
mp := &MessagePool{
|
||||
closer: make(chan struct{}),
|
||||
repubTk: time.NewTicker(build.BlockDelay * 10 * time.Second),
|
||||
@@ -188,6 +193,7 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
minGasPrice: types.NewInt(0),
|
||||
maxTxPoolSize: 5000,
|
||||
blsSigCache: cache,
|
||||
sigValCache: verifcache,
|
||||
changes: lps.New(50),
|
||||
localMsgs: namespace.Wrap(ds, datastore.NewKey(localMsgsDs)),
|
||||
api: api,
|
||||
@@ -313,12 +319,6 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
return mp.addTs(m, mp.curTs)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error {
|
||||
// big messages are bad, anti DOS
|
||||
if m.Size() > 32*1024 {
|
||||
return xerrors.Errorf("mpool message too large (%dB): %w", m.Size(), ErrMessageTooBig)
|
||||
@@ -332,11 +332,53 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error
|
||||
return ErrMessageValueTooHigh
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
if err := mp.VerifyMsgSig(m); err != nil {
|
||||
log.Warnf("mpooladd signature verification failed: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
return mp.addTs(m, mp.curTs)
|
||||
}
|
||||
|
||||
func sigCacheKey(m *types.SignedMessage) (string, error) {
|
||||
switch m.Signature.Type {
|
||||
case crypto.SigTypeBLS:
|
||||
if len(m.Signature.Data) < 90 {
|
||||
return "", fmt.Errorf("bls signature too short")
|
||||
}
|
||||
|
||||
return string(m.Cid().Bytes()) + string(m.Signature.Data[64:]), nil
|
||||
case crypto.SigTypeSecp256k1:
|
||||
return string(m.Cid().Bytes()), nil
|
||||
default:
|
||||
return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
sck, err := sigCacheKey(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ok := mp.sigValCache.Get(sck)
|
||||
if ok {
|
||||
// already validated, great
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mp.sigValCache.Add(sck, struct{}{})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error {
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrBroadcastAnyway)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/ipfs/go-datastore"
|
||||
)
|
||||
|
||||
type testMpoolApi struct {
|
||||
type testMpoolAPI struct {
|
||||
cb func(rev, app []*types.TipSet) error
|
||||
|
||||
bmsgs map[cid.Cid][]*types.SignedMessage
|
||||
@@ -25,68 +25,68 @@ type testMpoolApi struct {
|
||||
tipsets []*types.TipSet
|
||||
}
|
||||
|
||||
func newTestMpoolApi() *testMpoolApi {
|
||||
return &testMpoolApi{
|
||||
func newTestMpoolAPI() *testMpoolAPI {
|
||||
return &testMpoolAPI{
|
||||
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
|
||||
statenonce: make(map[address.Address]uint64),
|
||||
}
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
||||
t.Helper()
|
||||
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) revertBlock(t *testing.T, b *types.BlockHeader) {
|
||||
func (tma *testMpoolAPI) revertBlock(t *testing.T, b *types.BlockHeader) {
|
||||
t.Helper()
|
||||
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) setStateNonce(addr address.Address, v uint64) {
|
||||
func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) {
|
||||
tma.statenonce[addr] = v
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
||||
func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
||||
tma.bmsgs[h.Cid()] = msgs
|
||||
tma.tipsets = append(tma.tipsets, mock.TipSet(h))
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
||||
func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
||||
tma.cb = cb
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
func (tma *testMpoolAPI) PutMessage(m types.ChainMsg) (cid.Cid, error) {
|
||||
return cid.Undef, nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) PubSubPublish(string, []byte) error {
|
||||
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
return &types.Actor{
|
||||
Nonce: tma.statenonce[addr],
|
||||
Balance: types.NewInt(90000000),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
func (tma *testMpoolAPI) StateAccountKey(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
|
||||
return address.Undef, fmt.Errorf("given address was not a key addr")
|
||||
}
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
func (tma *testMpoolAPI) MessagesForBlock(h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
return nil, tma.bmsgs[h.Cid()], nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||
func (tma *testMpoolAPI) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||
if len(ts.Blocks()) != 1 {
|
||||
panic("cant deal with multiblock tipsets in this test")
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (tma *testMpoolApi) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolApi) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
for _, ts := range tma.tipsets {
|
||||
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
|
||||
return ts, nil
|
||||
@@ -138,7 +138,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
|
||||
}
|
||||
|
||||
func TestMessagePool(t *testing.T) {
|
||||
tma := newTestMpoolApi()
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
@@ -179,7 +179,7 @@ func TestMessagePool(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRevertMessages(t *testing.T) {
|
||||
tma := newTestMpoolApi()
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
if err != nil {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
var log = logging.Logger("statetree")
|
||||
|
||||
// Stores actors state by their ID.
|
||||
// StateTree stores actors state by their ID.
|
||||
type StateTree struct {
|
||||
root *hamt.Node
|
||||
Store cbor.IpldStore
|
||||
@@ -149,7 +149,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// `LookupID` gets the ID address of this actor's `addr` stored in the `InitActor`.
|
||||
// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`.
|
||||
func (st *StateTree) LookupID(addr address.Address) (address.Address, error) {
|
||||
if addr.Protocol() == address.ID {
|
||||
return addr, nil
|
||||
|
||||
@@ -255,12 +255,15 @@ func TestStateTreeConsistency(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, a := range addrs {
|
||||
st.SetActor(a, &types.Actor{
|
||||
err := st.SetActor(a, &types.Actor{
|
||||
Code: randomCid,
|
||||
Head: randomCid,
|
||||
Balance: types.NewInt(uint64(10000 + i)),
|
||||
Nonce: uint64(1000 - i),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("while setting actor: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := st.Flush(context.TODO())
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -40,6 +41,7 @@ func init() {
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
const testForkHeight = 40
|
||||
|
||||
+44
-13
@@ -326,7 +326,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
||||
blkmsgs = append(blkmsgs, bm)
|
||||
}
|
||||
|
||||
return sm.ApplyBlocks(ctx, pstate, blkmsgs, abi.ChainEpoch(blks[0].Height), r, cb)
|
||||
return sm.ApplyBlocks(ctx, pstate, blkmsgs, blks[0].Height, r, cb)
|
||||
}
|
||||
|
||||
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
||||
@@ -382,8 +382,8 @@ func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, o
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
if err := cst.Get(ctx, act.Head, out); err != nil {
|
||||
var r cbg.Deferred
|
||||
cst.Get(ctx, act.Head, &r)
|
||||
fmt.Printf("badhead %x\n", r.Raw)
|
||||
_ = cst.Get(ctx, act.Head, &r)
|
||||
log.Errorw("bad actor head", "error", err, "raw", r.Raw, "address", a)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@@ -405,8 +405,8 @@ func (sm *StateManager) LoadActorStateRaw(ctx context.Context, a address.Address
|
||||
return act, nil
|
||||
}
|
||||
|
||||
// Similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses. Uses the `TipSet` `ts`
|
||||
// to generate the VM state.
|
||||
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
|
||||
// Uses the `TipSet` `ts` to generate the VM state.
|
||||
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
switch addr.Protocol() {
|
||||
case address.BLS, address.SECP256K1:
|
||||
@@ -480,7 +480,10 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*types.TipSet, *types.MessageReceipt, error) {
|
||||
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
|
||||
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
|
||||
// before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -528,6 +531,11 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*type
|
||||
close(backSearchWait)
|
||||
}()
|
||||
|
||||
var candidateTs *types.TipSet
|
||||
var candidateRcp *types.MessageReceipt
|
||||
heightOfHead := head[0].Val.Height()
|
||||
reverts := map[types.TipSetKey]bool{}
|
||||
|
||||
for {
|
||||
select {
|
||||
case notif, ok := <-tsub:
|
||||
@@ -537,21 +545,44 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid) (*type
|
||||
for _, val := range notif {
|
||||
switch val.Type {
|
||||
case store.HCRevert:
|
||||
continue
|
||||
if val.Val.Equals(candidateTs) {
|
||||
candidateTs = nil
|
||||
candidateRcp = nil
|
||||
}
|
||||
if backSearchWait != nil {
|
||||
reverts[val.Val.Key()] = true
|
||||
}
|
||||
case store.HCApply:
|
||||
if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) {
|
||||
return candidateTs, candidateRcp, nil
|
||||
}
|
||||
r, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if r != nil {
|
||||
return val.Val, r, nil
|
||||
if confidence == 0 {
|
||||
return val.Val, r, err
|
||||
}
|
||||
candidateTs = val.Val
|
||||
candidateRcp = r
|
||||
}
|
||||
heightOfHead = val.Val.Height()
|
||||
}
|
||||
}
|
||||
case <-backSearchWait:
|
||||
if backTs != nil {
|
||||
return backTs, backRcp, nil
|
||||
// check if we found the message in the chain and that is hasn't been reverted since we started searching
|
||||
if backTs != nil && !reverts[backTs.Key()] {
|
||||
// if head is at or past confidence interval, return immediately
|
||||
if heightOfHead >= backTs.Height()+abi.ChainEpoch(confidence) {
|
||||
return backTs, backRcp, nil
|
||||
}
|
||||
|
||||
// wait for confidence interval
|
||||
candidateTs = backTs
|
||||
candidateRcp = backRcp
|
||||
}
|
||||
reverts = nil
|
||||
backSearchWait = nil
|
||||
case <-ctx.Done():
|
||||
return nil, nil, ctx.Err()
|
||||
@@ -610,9 +641,9 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if act.Nonce < m.VMMessage().Nonce {
|
||||
// nonce on chain is before message nonce we're looking for, its
|
||||
// not going to be here
|
||||
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||
// either way, no reason to lookback, it ain't there
|
||||
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
|
||||
+34
-16
@@ -138,6 +138,24 @@ func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address,
|
||||
return *i, nil
|
||||
}
|
||||
|
||||
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
sectorInfo, ok, err := mas.GetSector(sm.cs.Store(ctx), sid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, xerrors.New("sector not found")
|
||||
}
|
||||
|
||||
return sectorInfo, nil
|
||||
}
|
||||
|
||||
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
@@ -248,27 +266,27 @@ func GetMinerDeadlines(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
||||
return mas.LoadDeadlines(sm.cs.Store(ctx))
|
||||
}
|
||||
|
||||
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]abi.SectorNumber, error) {
|
||||
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
|
||||
return nil, xerrors.Errorf("(get faults) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
faults, err := mas.Faults.All(miner.SectorsMax)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("reading fault bit set: %w", err)
|
||||
}
|
||||
|
||||
out := make([]abi.SectorNumber, len(faults))
|
||||
for i, fault := range faults {
|
||||
out[i] = abi.SectorNumber(fault)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
return mas.Faults, nil
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
func GetMinerRecoveries(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*abi.BitField, error) {
|
||||
var mas miner.State
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get recoveries) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.Recoveries, nil
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
var state market.State
|
||||
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
|
||||
return nil, err
|
||||
@@ -280,7 +298,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts
|
||||
}
|
||||
|
||||
var dp market.DealProposal
|
||||
if err := da.Get(ctx, uint64(dealId), &dp); err != nil {
|
||||
if err := da.Get(ctx, uint64(dealID), &dp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -289,7 +307,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, found, err := sa.Get(dealId)
|
||||
st, found, err := sa.Get(dealID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type ChainIndex struct {
|
||||
skipCache *lru.ARCCache
|
||||
|
||||
loadTipSet loadTipSetFunc
|
||||
|
||||
skipLength abi.ChainEpoch
|
||||
}
|
||||
type loadTipSetFunc func(types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
func NewChainIndex(lts loadTipSetFunc) *ChainIndex {
|
||||
sc, _ := lru.NewARC(8192)
|
||||
return &ChainIndex{
|
||||
skipCache: sc,
|
||||
loadTipSet: lts,
|
||||
skipLength: 20,
|
||||
}
|
||||
}
|
||||
|
||||
type lbEntry struct {
|
||||
ts *types.TipSet
|
||||
parentHeight abi.ChainEpoch
|
||||
targetHeight abi.ChainEpoch
|
||||
target types.TipSetKey
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) GetTipsetByHeight(ctx context.Context, from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||
if from.Height()-to <= ci.skipLength {
|
||||
return ci.walkBack(from, to)
|
||||
}
|
||||
|
||||
rounded, err := ci.roundDown(from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cur := rounded.Key()
|
||||
for {
|
||||
cval, ok := ci.skipCache.Get(cur)
|
||||
if !ok {
|
||||
fc, err := ci.fillCache(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cval = fc
|
||||
}
|
||||
|
||||
lbe := cval.(*lbEntry)
|
||||
if lbe.ts.Height() == to || lbe.parentHeight < to {
|
||||
return lbe.ts, nil
|
||||
} else if to > lbe.targetHeight {
|
||||
return ci.walkBack(lbe.ts, to)
|
||||
}
|
||||
|
||||
cur = lbe.target
|
||||
}
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) GetTipsetByHeightWithoutCache(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||
return ci.walkBack(from, to)
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) fillCache(tsk types.TipSetKey) (*lbEntry, error) {
|
||||
ts, err := ci.loadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ts.Height() == 0 {
|
||||
return &lbEntry{
|
||||
ts: ts,
|
||||
parentHeight: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// will either be equal to ts.Height, or at least > ts.Parent.Height()
|
||||
rheight := ci.roundHeight(ts.Height())
|
||||
|
||||
parent, err := ci.loadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parent.Height() > rheight {
|
||||
return nil, xerrors.Errorf("cache is inconsistent")
|
||||
}
|
||||
|
||||
rheight -= ci.skipLength
|
||||
|
||||
skipTarget, err := ci.walkBack(parent, rheight)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lbe := &lbEntry{
|
||||
ts: ts,
|
||||
parentHeight: parent.Height(),
|
||||
targetHeight: skipTarget.Height(),
|
||||
target: skipTarget.Key(),
|
||||
}
|
||||
ci.skipCache.Add(tsk, lbe)
|
||||
|
||||
return lbe, nil
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) roundHeight(h abi.ChainEpoch) abi.ChainEpoch {
|
||||
return abi.ChainEpoch(h/ci.skipLength) * ci.skipLength
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) roundDown(ts *types.TipSet) (*types.TipSet, error) {
|
||||
target := ci.roundHeight(ts.Height())
|
||||
|
||||
rounded, err := ci.walkBack(ts, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rounded, nil
|
||||
}
|
||||
|
||||
func (ci *ChainIndex) walkBack(from *types.TipSet, to abi.ChainEpoch) (*types.TipSet, error) {
|
||||
if to > from.Height() {
|
||||
return nil, xerrors.Errorf("looking for tipset with height greater than start point")
|
||||
}
|
||||
|
||||
if to == from.Height() {
|
||||
return from, nil
|
||||
}
|
||||
|
||||
ts := from
|
||||
|
||||
for {
|
||||
pts, err := ci.loadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if to > pts.Height() {
|
||||
return ts, nil
|
||||
}
|
||||
if to == pts.Height() {
|
||||
return pts, nil
|
||||
}
|
||||
|
||||
ts = pts
|
||||
}
|
||||
}
|
||||
+55
-39
@@ -62,6 +62,8 @@ type ChainStore struct {
|
||||
tstLk sync.Mutex
|
||||
tipsets map[abi.ChainEpoch][]cid.Cid
|
||||
|
||||
cindex *ChainIndex
|
||||
|
||||
reorgCh chan<- reorg
|
||||
headChangeNotifs []func(rev, app []*types.TipSet) error
|
||||
|
||||
@@ -84,6 +86,10 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Sys
|
||||
vmcalls: vmcalls,
|
||||
}
|
||||
|
||||
ci := NewChainIndex(cs.LoadTipSet)
|
||||
|
||||
cs.cindex = ci
|
||||
|
||||
cs.reorgCh = cs.reorgWorker(context.TODO())
|
||||
|
||||
hcnf := func(rev, app []*types.TipSet) error {
|
||||
@@ -387,7 +393,7 @@ func (cs *ChainStore) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
// returns true if 'a' is an ancestor of 'b'
|
||||
// IsAncestorOf returns true if 'a' is an ancestor of 'b'
|
||||
func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) {
|
||||
if b.Height() <= a.Height() {
|
||||
return false, nil
|
||||
@@ -895,39 +901,50 @@ func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.Cha
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
VRFDigest := blake2b.Sum256(rbase)
|
||||
h.Write(VRFDigest[:])
|
||||
_, err := h.Write(VRFDigest[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||
}
|
||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
h.Write(entropy)
|
||||
_, err = h.Write(entropy)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing entropy: %w", err)
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) (out []byte, err error) {
|
||||
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
//defer func() {
|
||||
//log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
|
||||
//}()
|
||||
for {
|
||||
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := nts.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
if nts.Height() <= round || mtb.Height == 0 {
|
||||
return DrawRandomness(nts.MinTicketBlock().Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
blks = mtb.Parents
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := randTs.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
// GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given
|
||||
@@ -940,7 +957,7 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
||||
}
|
||||
|
||||
if h > ts.Height() {
|
||||
return nil, xerrors.Errorf("looking for tipset with height less than start point")
|
||||
return nil, xerrors.Errorf("looking for tipset with height greater than start point")
|
||||
}
|
||||
|
||||
if h == ts.Height() {
|
||||
@@ -951,24 +968,24 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
||||
log.Warnf("expensive call to GetTipsetByHeight, seeking %d levels", ts.Height()-h)
|
||||
}
|
||||
|
||||
for {
|
||||
pts, err := cs.LoadTipSet(ts.Parents())
|
||||
lbts, err := cs.cindex.GetTipsetByHeight(ctx, ts, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if lbts.Height() < h {
|
||||
log.Warnf("chain index returned the wrong tipset at height %d, using slow retrieval", h)
|
||||
lbts, err = cs.cindex.GetTipsetByHeightWithoutCache(ts, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if h > pts.Height() {
|
||||
if prev {
|
||||
return pts, nil
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
if h == pts.Height() {
|
||||
return pts, nil
|
||||
}
|
||||
|
||||
ts = pts
|
||||
}
|
||||
|
||||
if lbts.Height() == h || !prev {
|
||||
return lbts, nil
|
||||
}
|
||||
|
||||
return cs.LoadTipSet(lbts.Parents())
|
||||
}
|
||||
|
||||
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
@@ -1148,7 +1165,6 @@ func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSepara
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
} else {
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
@@ -25,6 +26,7 @@ func init() {
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
func BenchmarkGetRandomness(b *testing.B) {
|
||||
@@ -53,7 +55,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
bds, err := lr.Datastore("/blocks")
|
||||
bds, err := lr.Datastore("/chain")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
+197
-17
@@ -1,30 +1,45 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/ipfs/go-cid"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/tag"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"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/lib/bufbstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
)
|
||||
|
||||
var log = logging.Logger("sub")
|
||||
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, cmgr connmgr.ConnManager, bv *BlockValidator) {
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, cmgr connmgr.ConnManager) {
|
||||
for {
|
||||
msg, err := bsub.Next(ctx)
|
||||
if err != nil {
|
||||
@@ -42,8 +57,7 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
return
|
||||
}
|
||||
|
||||
//nolint:golint
|
||||
src := peer.ID(msg.GetFrom())
|
||||
src := msg.GetFrom()
|
||||
|
||||
go func() {
|
||||
log.Infof("New block over pubsub: %s", blk.Cid())
|
||||
@@ -52,15 +66,13 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
log.Debug("about to fetch messages for block from pubsub")
|
||||
bmsgs, err := s.Bsync.FetchMessagesByCids(context.TODO(), blk.BlsMessages)
|
||||
if err != nil {
|
||||
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; flagging source %s", err, src)
|
||||
bv.flagPeer(src)
|
||||
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; source: %s", err, src)
|
||||
return
|
||||
}
|
||||
|
||||
smsgs, err := s.Bsync.FetchSignedMessagesByCids(context.TODO(), blk.SecpkMessages)
|
||||
if err != nil {
|
||||
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; flagging source %s", err, src)
|
||||
bv.flagPeer(src)
|
||||
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; source: %s", err, src)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -89,15 +101,25 @@ type BlockValidator struct {
|
||||
recvBlocks *blockReceiptCache
|
||||
|
||||
blacklist func(peer.ID)
|
||||
|
||||
// necessary for block validation
|
||||
chain *store.ChainStore
|
||||
stmgr *stmgr.StateManager
|
||||
|
||||
mx sync.Mutex
|
||||
keycache map[string]address.Address
|
||||
}
|
||||
|
||||
func NewBlockValidator(blacklist func(peer.ID)) *BlockValidator {
|
||||
func NewBlockValidator(chain *store.ChainStore, stmgr *stmgr.StateManager, blacklist func(peer.ID)) *BlockValidator {
|
||||
p, _ := lru.New2Q(4096)
|
||||
return &BlockValidator{
|
||||
peers: p,
|
||||
killThresh: 10,
|
||||
blacklist: blacklist,
|
||||
recvBlocks: newBlockReceiptCache(),
|
||||
chain: chain,
|
||||
stmgr: stmgr,
|
||||
keycache: make(map[string]address.Address),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,35 +142,191 @@ func (bv *BlockValidator) flagPeer(p peer.ID) {
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) pubsub.ValidationResult {
|
||||
// track validation time
|
||||
begin := time.Now()
|
||||
defer func() {
|
||||
end := time.Now()
|
||||
log.Infof("block validation time: %s", end.Sub(begin))
|
||||
}()
|
||||
|
||||
stats.Record(ctx, metrics.BlockReceived.M(1))
|
||||
|
||||
recordFailure := func(what string) {
|
||||
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, what))
|
||||
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
|
||||
bv.flagPeer(pid)
|
||||
}
|
||||
|
||||
// make sure the block can be decoded
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, "invalid"))
|
||||
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
|
||||
bv.flagPeer(pid)
|
||||
recordFailure("invalid")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// check the message limit constraints
|
||||
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
|
||||
log.Warnf("received block with too many messages over pubsub")
|
||||
ctx, _ = tag.New(ctx, tag.Insert(metrics.FailureType, "too_many_messages"))
|
||||
stats.Record(ctx, metrics.BlockValidationFailure.M(1))
|
||||
bv.flagPeer(pid)
|
||||
recordFailure("too_many_messages")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// make sure we have a signature
|
||||
if blk.Header.BlockSig == nil {
|
||||
log.Warnf("received block without a signature over pubsub")
|
||||
recordFailure("missing_signature")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// validate the block meta: the Message CID in the header must match the included messages
|
||||
err = bv.validateMsgMeta(ctx, blk)
|
||||
if err != nil {
|
||||
log.Warnf("error validating message metadata: %s", err)
|
||||
recordFailure("invalid_block_meta")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// we want to ensure that it is a block from a known miner; we reject blocks from unknown miners
|
||||
// to prevent spam attacks.
|
||||
// the logic works as follows: we lookup the miner in the chain for its key.
|
||||
// if we can find it then it's a known miner and we can validate the signature.
|
||||
// if we can't find it, we check whether we are (near) synced in the chain.
|
||||
// if we are not synced we cannot validate the block and we must ignore it.
|
||||
// if we are synced and the miner is unknown, then the block is rejcected.
|
||||
key, err := bv.getMinerWorkerKey(ctx, blk)
|
||||
if err != nil {
|
||||
if bv.isChainNearSynced() {
|
||||
log.Warnf("received block message from unknown miner over pubsub; rejecting message")
|
||||
recordFailure("unknown_miner")
|
||||
return pubsub.ValidationReject
|
||||
} else {
|
||||
log.Warnf("cannot validate block message; unknown miner in unsynced chain")
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
}
|
||||
|
||||
err = sigs.CheckBlockSignature(ctx, blk.Header, key)
|
||||
if err != nil {
|
||||
log.Errorf("block signature verification failed: %s", err)
|
||||
recordFailure("signature_verification_failed")
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
|
||||
// it's a good block! make sure we've only seen it once
|
||||
if bv.recvBlocks.add(blk.Header.Cid()) > 0 {
|
||||
// TODO: once these changes propagate to the network, we can consider
|
||||
// dropping peers who send us the same block multiple times
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
|
||||
// all good, accept the block
|
||||
msg.ValidatorData = blk
|
||||
stats.Record(ctx, metrics.BlockValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) isChainNearSynced() bool {
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
timestamp := ts.MinTimestamp()
|
||||
now := time.Now().UnixNano()
|
||||
cutoff := uint64(now) - uint64(6*time.Hour)
|
||||
return timestamp > cutoff
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||
var bcids, scids []cbg.CBORMarshaler
|
||||
for _, m := range msg.BlsMessages {
|
||||
c := cbg.CborCid(m)
|
||||
bcids = append(bcids, &c)
|
||||
}
|
||||
|
||||
for _, m := range msg.SecpkMessages {
|
||||
c := cbg.CborCid(m)
|
||||
scids = append(scids, &c)
|
||||
}
|
||||
|
||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||
bs := cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore()))
|
||||
|
||||
bmroot, err := amt.FromArray(ctx, bs, bcids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
smroot, err := amt.FromArray(ctx, bs, scids)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mrcid, err := bs.Put(ctx, &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 (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.BlockMsg) (address.Address, error) {
|
||||
addr := msg.Header.Miner
|
||||
|
||||
bv.mx.Lock()
|
||||
key, ok := bv.keycache[addr.String()]
|
||||
bv.mx.Unlock()
|
||||
if ok {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// TODO I have a feeling all this can be simplified by cleverer DI to use the API
|
||||
ts := bv.chain.GetHeaviestTipSet()
|
||||
st, _, err := bv.stmgr.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
buf := bufbstore.NewBufferedBstore(bv.chain.Blockstore())
|
||||
cst := cbor.NewCborStore(buf)
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
act, err := state.GetActor(addr)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
blk, err := bv.chain.Blockstore().Get(act.Head)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
aso := blk.RawData()
|
||||
|
||||
var mst miner.State
|
||||
err = mst.UnmarshalCBOR(bytes.NewReader(aso))
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
worker := mst.Info.Worker
|
||||
key, err = bv.stmgr.ResolveToKeyAddress(ctx, worker, ts)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
bv.mx.Lock()
|
||||
bv.keycache[addr.String()] = key
|
||||
bv.mx.Unlock()
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
type blockReceiptCache struct {
|
||||
blocks *lru.TwoQueueCache
|
||||
}
|
||||
@@ -197,10 +375,12 @@ func (mv *MessageValidator) Validate(ctx context.Context, pid peer.ID, msg *pubs
|
||||
tag.Insert(metrics.FailureType, "add"),
|
||||
)
|
||||
stats.Record(ctx, metrics.MessageValidationFailure.M(1))
|
||||
if xerrors.Is(err, messagepool.ErrBroadcastAnyway) {
|
||||
return pubsub.ValidationAccept
|
||||
switch {
|
||||
case xerrors.Is(err, messagepool.ErrBroadcastAnyway):
|
||||
return pubsub.ValidationIgnore
|
||||
default:
|
||||
return pubsub.ValidationReject
|
||||
}
|
||||
return pubsub.ValidationIgnore
|
||||
}
|
||||
stats.Record(ctx, metrics.MessageValidationSuccess.M(1))
|
||||
return pubsub.ValidationAccept
|
||||
|
||||
+9
-41
@@ -31,7 +31,6 @@ import (
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
@@ -527,7 +526,7 @@ func blockSanityChecks(h *types.BlockHeader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Should match up with 'Semantical Validation' in validation.md in the spec
|
||||
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validateBlock")
|
||||
defer span.End()
|
||||
@@ -666,7 +665,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
})
|
||||
|
||||
blockSigCheck := async.Err(func() error {
|
||||
if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
|
||||
if err := sigs.CheckBlockSignature(ctx, h, waddr); err != nil {
|
||||
return xerrors.Errorf("check block signature failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -842,44 +841,13 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return xerrors.Errorf("failed to load base state tree: %w", err)
|
||||
}
|
||||
|
||||
checkMsg := func(m *types.Message) error {
|
||||
checkMsg := func(msg types.ChainMsg) error {
|
||||
m := msg.VMMessage()
|
||||
|
||||
// Phase 1: syntactic validation, as defined in the spec
|
||||
|
||||
if m.Version != 0 {
|
||||
return xerrors.New("'Version' unsupported")
|
||||
}
|
||||
|
||||
if m.To == address.Undef {
|
||||
return xerrors.New("'To' address cannot be empty")
|
||||
}
|
||||
|
||||
if m.From == address.Undef {
|
||||
return xerrors.New("'From' address cannot be empty")
|
||||
}
|
||||
|
||||
if m.Value.LessThan(big.Zero()) {
|
||||
return xerrors.New("'Value' field cannot be negative")
|
||||
}
|
||||
|
||||
if m.Value.GreaterThan(types.TotalFilecoinInt) {
|
||||
return xerrors.New("'Value' field cannot be greater than total filecoin supply")
|
||||
}
|
||||
|
||||
if len(m.Params) != 0 && m.Method == 0 {
|
||||
return xerrors.New("'Params' field should be empty if no 'Method' is being called")
|
||||
}
|
||||
|
||||
if m.GasPrice.LessThan(big.Zero()) {
|
||||
return xerrors.New("'GasPrice' field cannot be negative")
|
||||
}
|
||||
|
||||
if m.GasLimit > build.BlockGasLimit {
|
||||
return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
|
||||
}
|
||||
|
||||
// since prices might vary with time, this is technically semantic validation
|
||||
if m.GasLimit < vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(m.ChainLength()) {
|
||||
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
|
||||
minGas := vm.PricelistByEpoch(baseTs.Height()).OnChainMessage(msg.ChainLength())
|
||||
if err := m.ValidForBlockInclusion(minGas); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Phase 2: (Partial) semantic validation:
|
||||
@@ -919,7 +887,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
|
||||
var secpkCids []cbg.CBORMarshaler
|
||||
for i, m := range b.SecpkMessages {
|
||||
if err := checkMsg(&m.Message); err != nil {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -37,6 +38,7 @@ func init() {
|
||||
abi.RegisteredProof_StackedDRG2KiBSeal: {},
|
||||
}
|
||||
power.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg.MinVerifiedDealSize = big.NewInt(256)
|
||||
}
|
||||
|
||||
const source = 0
|
||||
@@ -415,7 +417,7 @@ func TestSyncBadTimestamp(t *testing.T) {
|
||||
a1 := tu.mineOnBlock(base, 0, nil, false, true)
|
||||
|
||||
tu.g.Timestamper = nil
|
||||
tu.g.ResyncBankerNonce(a1.TipSet())
|
||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||
|
||||
fmt.Println("After mine bad block!")
|
||||
tu.printHeads()
|
||||
@@ -477,7 +479,7 @@ func TestSyncFork(t *testing.T) {
|
||||
a := tu.mineOnBlock(a1, p1, []int{0}, true, false)
|
||||
a = tu.mineOnBlock(a, p1, []int{0}, true, false)
|
||||
|
||||
tu.g.ResyncBankerNonce(a1.TipSet())
|
||||
require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet()))
|
||||
// chain B will now be heaviest
|
||||
b := tu.mineOnBlock(base, p2, []int{1}, true, false)
|
||||
b = tu.mineOnBlock(b, p2, []int{1}, true, false)
|
||||
|
||||
@@ -69,10 +69,13 @@ type BlockHeader struct {
|
||||
BlockSig *crypto.Signature // 13
|
||||
|
||||
ForkSignaling uint64 // 14
|
||||
|
||||
// internal
|
||||
validated bool // true if the signature has been validated
|
||||
}
|
||||
|
||||
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
data, err := b.Serialize()
|
||||
func (blk *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
data, err := blk.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -86,8 +89,8 @@ func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
return block.NewBlockWithCid(data, c)
|
||||
}
|
||||
|
||||
func (b *BlockHeader) Cid() cid.Cid {
|
||||
sb, err := b.ToStorageBlock()
|
||||
func (blk *BlockHeader) Cid() cid.Cid {
|
||||
sb, err := blk.ToStorageBlock()
|
||||
if err != nil {
|
||||
panic(err) // Not sure i'm entirely comfortable with this one, needs to be checked
|
||||
}
|
||||
@@ -124,6 +127,14 @@ func (blk *BlockHeader) SigningBytes() ([]byte, error) {
|
||||
return blkcopy.Serialize()
|
||||
}
|
||||
|
||||
func (blk *BlockHeader) SetValidated() {
|
||||
blk.validated = true
|
||||
}
|
||||
|
||||
func (blk *BlockHeader) IsValidated() bool {
|
||||
return blk.validated
|
||||
}
|
||||
|
||||
type MsgMeta struct {
|
||||
BlsMessages cid.Cid
|
||||
SecpkMessages cid.Cid
|
||||
|
||||
@@ -2,13 +2,16 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
)
|
||||
|
||||
func testBlockHeader(t testing.TB) *BlockHeader {
|
||||
@@ -63,6 +66,62 @@ func TestBlockHeaderSerialization(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInteropBH(t *testing.T) {
|
||||
newAddr, err := address.NewSecp256k1Address([]byte("address0"))
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mcid, err := cid.Parse("bafy2bzaceaxyj7xq27gc2747adjcirpxx52tt7owqx6z6kckun7tqivvoym4y")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
posts := []abi.PoStProof{
|
||||
{abi.RegisteredProof_StackedDRG2KiBWinningPoSt, []byte{0x07}},
|
||||
}
|
||||
|
||||
bh := &BlockHeader{
|
||||
Miner: newAddr,
|
||||
Ticket: &Ticket{[]byte{0x01, 0x02, 0x03}},
|
||||
ElectionProof: &ElectionProof{[]byte{0x0a, 0x0b}},
|
||||
BeaconEntries: []BeaconEntry{
|
||||
{
|
||||
Round: 5,
|
||||
Data: []byte{0x0c},
|
||||
//prevRound: 0,
|
||||
},
|
||||
},
|
||||
Height: 2,
|
||||
Messages: mcid,
|
||||
ParentMessageReceipts: mcid,
|
||||
Parents: []cid.Cid{mcid},
|
||||
ParentWeight: NewInt(1000),
|
||||
ForkSignaling: 3,
|
||||
ParentStateRoot: mcid,
|
||||
Timestamp: 1,
|
||||
WinPoStProof: posts,
|
||||
BlockSig: &crypto.Signature{
|
||||
Type: crypto.SigTypeBLS,
|
||||
Data: []byte{0x3},
|
||||
},
|
||||
BLSAggregate: &crypto.Signature{},
|
||||
}
|
||||
|
||||
bhsb, err := bh.SigningBytes()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// acquired from go-filecoin
|
||||
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad22814301020381420a0b818205410c818209410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603"
|
||||
if gfc != hex.EncodeToString(bhsb) {
|
||||
t.Fatal("not equal!")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBlockHeaderMarshal(b *testing.B) {
|
||||
bh := testBlockHeader(b)
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
type ExecutionResult struct {
|
||||
Msg *Message
|
||||
MsgRct *MessageReceipt
|
||||
Error string
|
||||
Msg *Message
|
||||
MsgRct *MessageReceipt
|
||||
Error string
|
||||
Duration time.Duration
|
||||
|
||||
Subcalls []*ExecutionResult
|
||||
}
|
||||
|
||||
+46
-10
@@ -4,10 +4,13 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
)
|
||||
@@ -38,20 +41,16 @@ type Message struct {
|
||||
Params []byte
|
||||
}
|
||||
|
||||
func (t *Message) BlockMiner() address.Address {
|
||||
panic("implement me")
|
||||
func (m *Message) Caller() address.Address {
|
||||
return m.From
|
||||
}
|
||||
|
||||
func (t *Message) Caller() address.Address {
|
||||
return t.From
|
||||
func (m *Message) Receiver() address.Address {
|
||||
return m.To
|
||||
}
|
||||
|
||||
func (t *Message) Receiver() address.Address {
|
||||
return t.To
|
||||
}
|
||||
|
||||
func (t *Message) ValueReceived() abi.TokenAmount {
|
||||
return t.Value
|
||||
func (m *Message) ValueReceived() abi.TokenAmount {
|
||||
return m.Value
|
||||
}
|
||||
|
||||
func DecodeMessage(b []byte) (*Message, error) {
|
||||
@@ -121,3 +120,40 @@ func (m *Message) VMMessage() *Message {
|
||||
func (m *Message) Equals(o *Message) bool {
|
||||
return m.Cid() == o.Cid()
|
||||
}
|
||||
|
||||
func (m *Message) ValidForBlockInclusion(minGas int64) error {
|
||||
if m.Version != 0 {
|
||||
return xerrors.New("'Version' unsupported")
|
||||
}
|
||||
|
||||
if m.To == address.Undef {
|
||||
return xerrors.New("'To' address cannot be empty")
|
||||
}
|
||||
|
||||
if m.From == address.Undef {
|
||||
return xerrors.New("'From' address cannot be empty")
|
||||
}
|
||||
|
||||
if m.Value.LessThan(big.Zero()) {
|
||||
return xerrors.New("'Value' field cannot be negative")
|
||||
}
|
||||
|
||||
if m.Value.GreaterThan(TotalFilecoinInt) {
|
||||
return xerrors.New("'Value' field cannot be greater than total filecoin supply")
|
||||
}
|
||||
|
||||
if m.GasPrice.LessThan(big.Zero()) {
|
||||
return xerrors.New("'GasPrice' field cannot be negative")
|
||||
}
|
||||
|
||||
if m.GasLimit > build.BlockGasLimit {
|
||||
return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
|
||||
}
|
||||
|
||||
// since prices might vary with time, this is technically semantic validation
|
||||
if m.GasLimit < minGas {
|
||||
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
|
||||
if m.Signature.Type == crypto.SigTypeBLS {
|
||||
return m.Message.ToStorageBlock()
|
||||
func (sm *SignedMessage) ToStorageBlock() (block.Block, error) {
|
||||
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||
return sm.Message.ToStorageBlock()
|
||||
}
|
||||
|
||||
data, err := m.Serialize()
|
||||
data, err := sm.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -28,12 +28,12 @@ func (m *SignedMessage) ToStorageBlock() (block.Block, error) {
|
||||
return block.NewBlockWithCid(data, c)
|
||||
}
|
||||
|
||||
func (m *SignedMessage) Cid() cid.Cid {
|
||||
if m.Signature.Type == crypto.SigTypeBLS {
|
||||
return m.Message.Cid()
|
||||
func (sm *SignedMessage) Cid() cid.Cid {
|
||||
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||
return sm.Message.Cid()
|
||||
}
|
||||
|
||||
sb, err := m.ToStorageBlock()
|
||||
sb, err := sm.ToStorageBlock()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ type TipSet struct {
|
||||
height abi.ChainEpoch
|
||||
}
|
||||
|
||||
// why didnt i just export the fields? Because the struct has methods with the
|
||||
// same names already
|
||||
type ExpTipSet struct {
|
||||
Cids []cid.Cid
|
||||
Blocks []*BlockHeader
|
||||
@@ -32,6 +30,8 @@ type ExpTipSet struct {
|
||||
}
|
||||
|
||||
func (ts *TipSet) MarshalJSON() ([]byte, error) {
|
||||
// why didnt i just export the fields? Because the struct has methods with the
|
||||
// same names already
|
||||
return json.Marshal(ExpTipSet{
|
||||
Cids: ts.cids,
|
||||
Blocks: ts.blks,
|
||||
|
||||
@@ -61,9 +61,9 @@ func TestTipSetKey(t *testing.T) {
|
||||
|
||||
t.Run("JSON", func(t *testing.T) {
|
||||
k0 := NewTipSetKey()
|
||||
verifyJson(t, "[]", k0)
|
||||
verifyJSON(t, "[]", k0)
|
||||
k3 := NewTipSetKey(c1, c2, c3)
|
||||
verifyJson(t, `[`+
|
||||
verifyJSON(t, `[`+
|
||||
`{"/":"bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki"},`+
|
||||
`{"/":"bafy2bzacebxfyh2fzoxrt6kcgc5dkaodpcstgwxxdizrww225vrhsizsfcg4g"},`+
|
||||
`{"/":"bafy2bzacedwviarjtjraqakob5pslltmuo5n3xev3nt5zylezofkbbv5jclyu"}`+
|
||||
@@ -71,7 +71,7 @@ func TestTipSetKey(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func verifyJson(t *testing.T, expected string, k TipSetKey) {
|
||||
func verifyJSON(t *testing.T, expected string, k TipSetKey) {
|
||||
bytes, err := json.Marshal(k)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expected, string(bytes))
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/puppet"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
vtypes "github.com/filecoin-project/chain-validation/chain/types"
|
||||
vdrivers "github.com/filecoin-project/chain-validation/drivers"
|
||||
vstate "github.com/filecoin-project/chain-validation/state"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -24,12 +24,13 @@ import (
|
||||
// Applier applies messages to state trees and storage.
|
||||
type Applier struct {
|
||||
stateWrapper *StateWrapper
|
||||
syscalls runtime.Syscalls
|
||||
}
|
||||
|
||||
var _ vstate.Applier = &Applier{}
|
||||
|
||||
func NewApplier(sw *StateWrapper) *Applier {
|
||||
return &Applier{sw}
|
||||
func NewApplier(sw *StateWrapper, syscalls runtime.Syscalls) *Applier {
|
||||
return &Applier{sw, syscalls}
|
||||
}
|
||||
|
||||
func (a *Applier) ApplyMessage(epoch abi.ChainEpoch, message *vtypes.Message) (vtypes.ApplyMessageResult, error) {
|
||||
@@ -65,7 +66,7 @@ func (a *Applier) ApplySignedMessage(epoch abi.ChainEpoch, msg *vtypes.SignedMes
|
||||
}
|
||||
|
||||
func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.BlockMessagesInfo, rnd vstate.RandomnessSource) (vtypes.ApplyTipSetResult, error) {
|
||||
cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, vdrivers.NewChainValidationSyscalls())
|
||||
cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls)
|
||||
sm := stmgr.NewStateManager(cs)
|
||||
|
||||
var bms []stmgr.BlockMessages
|
||||
@@ -134,7 +135,7 @@ func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.
|
||||
ctx := context.TODO()
|
||||
base := a.stateWrapper.Root()
|
||||
|
||||
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, vdrivers.NewChainValidationSyscalls())
|
||||
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, a.syscalls)
|
||||
// need to modify the VM invoker to add the puppet actor
|
||||
chainValInvoker := vm.NewInvoker()
|
||||
chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{})
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package validation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
|
||||
vstate "github.com/filecoin-project/chain-validation/state"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
acrypto "github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
)
|
||||
|
||||
type Factories struct {
|
||||
@@ -18,26 +16,15 @@ func NewFactories() *Factories {
|
||||
return &Factories{}
|
||||
}
|
||||
|
||||
func (f *Factories) NewStateAndApplier() (vstate.VMWrapper, vstate.Applier) {
|
||||
func (f *Factories) NewStateAndApplier(syscalls runtime.Syscalls) (vstate.VMWrapper, vstate.Applier) {
|
||||
st := NewState()
|
||||
return st, NewApplier(st)
|
||||
return st, NewApplier(st, syscalls)
|
||||
}
|
||||
|
||||
func (f *Factories) NewKeyManager() vstate.KeyManager {
|
||||
return newKeyManager()
|
||||
}
|
||||
|
||||
type fakeRandSrc struct {
|
||||
}
|
||||
|
||||
func (r fakeRandSrc) Randomness(_ context.Context, _ acrypto.DomainSeparationTag, _ abi.ChainEpoch, _ []byte) (abi.Randomness, error) {
|
||||
return abi.Randomness("sausages"), nil
|
||||
}
|
||||
|
||||
func (f *Factories) NewRandomnessSource() vstate.RandomnessSource {
|
||||
return &fakeRandSrc{}
|
||||
}
|
||||
|
||||
func (f *Factories) NewValidationConfig() vstate.ValidationConfig {
|
||||
trackGas := true
|
||||
checkExit := true
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -173,14 +174,18 @@ func WriteJsonToFile(fname string, obj interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
defer fi.Close() //nolint:errcheck
|
||||
|
||||
out, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fi.Write(out)
|
||||
_, err = fi.Write(out)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing json: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package vectors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func LoadVector(t *testing.T, f string, out interface{}) {
|
||||
@@ -42,5 +46,40 @@ func TestBlockHeaderVectors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMessageSigningVectors(t *testing.T) {
|
||||
// TODO:
|
||||
var msvs []MessageSigningVector
|
||||
LoadVector(t, "message_signing.json", &msvs)
|
||||
|
||||
for i, msv := range msvs {
|
||||
smsg := &types.SignedMessage{
|
||||
Message: *msv.Unsigned,
|
||||
Signature: *msv.Signature,
|
||||
}
|
||||
|
||||
if smsg.Cid().String() != msv.Cid {
|
||||
t.Fatalf("cid of message in vector %d mismatches", i)
|
||||
}
|
||||
|
||||
// TODO: check signature
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsignedMessageVectors(t *testing.T) {
|
||||
var msvs []UnsignedMessageVector
|
||||
LoadVector(t, "unsigned_messages.json", &msvs)
|
||||
|
||||
for i, msv := range msvs {
|
||||
b, err := msv.Message.Serialize()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dec, err := hex.DecodeString(msv.HexCbor)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, dec) {
|
||||
t.Fatalf("serialization vector %d mismatches bytes", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package vm
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
addr "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
@@ -143,3 +144,8 @@ func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte
|
||||
ps.chargeGas(ps.pl.OnVerifyConsensusFault())
|
||||
return ps.under.VerifyConsensusFault(h1, h2, extra)
|
||||
}
|
||||
|
||||
func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||
ps.chargeGas(0) // TODO: this is only called by the cron actor. Should we even charge gas?
|
||||
return ps.under.BatchVerifySeals(inp)
|
||||
}
|
||||
|
||||
+6
-8
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
)
|
||||
|
||||
type invoker struct {
|
||||
type Invoker struct {
|
||||
builtInCode map[cid.Cid]nativeCode
|
||||
builtInState map[cid.Cid]reflect.Type
|
||||
}
|
||||
@@ -40,8 +40,8 @@ type invoker struct {
|
||||
type invokeFunc func(rt runtime.Runtime, params []byte) ([]byte, aerrors.ActorError)
|
||||
type nativeCode []invokeFunc
|
||||
|
||||
func NewInvoker() *invoker {
|
||||
inv := &invoker{
|
||||
func NewInvoker() *Invoker {
|
||||
inv := &Invoker{
|
||||
builtInCode: make(map[cid.Cid]nativeCode),
|
||||
builtInState: make(map[cid.Cid]reflect.Type),
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func NewInvoker() *invoker {
|
||||
return inv
|
||||
}
|
||||
|
||||
func (inv *invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||
func (inv *Invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.MethodNum, params []byte) ([]byte, aerrors.ActorError) {
|
||||
|
||||
code, ok := inv.builtInCode[codeCid]
|
||||
if !ok {
|
||||
@@ -76,7 +76,7 @@ func (inv *invoker) Invoke(codeCid cid.Cid, rt runtime.Runtime, method abi.Metho
|
||||
|
||||
}
|
||||
|
||||
func (inv *invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
|
||||
func (inv *Invoker) Register(c cid.Cid, instance Invokee, state interface{}) {
|
||||
code, err := inv.transform(instance)
|
||||
if err != nil {
|
||||
panic(xerrors.Errorf("%s: %w", string(c.Hash()), err))
|
||||
@@ -89,9 +89,7 @@ type Invokee interface {
|
||||
Exports() []interface{}
|
||||
}
|
||||
|
||||
var tAError = reflect.TypeOf((*aerrors.ActorError)(nil)).Elem()
|
||||
|
||||
func (*invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
func (*Invoker) transform(instance Invokee) (nativeCode, error) {
|
||||
itype := reflect.TypeOf(instance)
|
||||
exports := instance.Exports()
|
||||
for i, m := range exports {
|
||||
|
||||
@@ -76,7 +76,7 @@ func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams)
|
||||
}
|
||||
|
||||
func TestInvokerBasic(t *testing.T) {
|
||||
inv := invoker{}
|
||||
inv := Invoker{}
|
||||
code, err := inv.transform(basicContract{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
@@ -27,7 +28,7 @@ func init() {
|
||||
|
||||
var EmptyObjectCid cid.Cid
|
||||
|
||||
// Creates account actors from only BLS/SECP256K1 addresses.
|
||||
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
|
||||
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, aerrors.ActorError) {
|
||||
addrID, err := rt.state.RegisterNewAddress(addr)
|
||||
if err != nil {
|
||||
|
||||
+63
-55
@@ -5,6 +5,8 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
@@ -105,8 +107,8 @@ type notFoundErr interface {
|
||||
IsNotFound() bool
|
||||
}
|
||||
|
||||
func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
if err := rs.cst.Get(context.TODO(), c, o); err != nil {
|
||||
func (rt *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
if err := rt.cst.Get(context.TODO(), c, o); err != nil {
|
||||
var nfe notFoundErr
|
||||
if xerrors.As(err, &nfe) && nfe.IsNotFound() {
|
||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||
@@ -120,8 +122,8 @@ func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
c, err := rs.cst.Put(context.TODO(), x)
|
||||
func (rt *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
c, err := rt.cst.Put(context.TODO(), x)
|
||||
if err != nil {
|
||||
if xerrors.As(err, new(cbor.SerializationError)) {
|
||||
panic(aerrors.Newf(exitcode.ErrSerialization, "failed to marshal cbor object %s", err))
|
||||
@@ -133,7 +135,7 @@ func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid {
|
||||
|
||||
var _ vmr.Runtime = (*Runtime)(nil)
|
||||
|
||||
func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||
func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.ActorError) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if ar, ok := r.(aerrors.ActorError); ok {
|
||||
@@ -148,8 +150,8 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
|
||||
ret := f()
|
||||
|
||||
if !rs.callerValidated {
|
||||
rs.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
|
||||
if !rt.callerValidated {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "Caller MUST be validated during method execution")
|
||||
}
|
||||
|
||||
switch ret := ret.(type) {
|
||||
@@ -170,25 +172,25 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *Runtime) Message() vmr.Message {
|
||||
return rs.vmsg
|
||||
func (rt *Runtime) Message() vmr.Message {
|
||||
return rt.vmsg
|
||||
}
|
||||
|
||||
func (rs *Runtime) ValidateImmediateCallerAcceptAny() {
|
||||
rs.abortIfAlreadyValidated()
|
||||
func (rt *Runtime) ValidateImmediateCallerAcceptAny() {
|
||||
rt.abortIfAlreadyValidated()
|
||||
return
|
||||
}
|
||||
|
||||
func (rs *Runtime) CurrentBalance() abi.TokenAmount {
|
||||
b, err := rs.GetBalance(rs.Message().Receiver())
|
||||
func (rt *Runtime) CurrentBalance() abi.TokenAmount {
|
||||
b, err := rt.GetBalance(rt.Message().Receiver())
|
||||
if err != nil {
|
||||
rs.Abortf(exitcode.ExitCode(err.RetCode()), "get current balance: %v", err)
|
||||
rt.Abortf(err.RetCode(), "get current balance: %v", err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
|
||||
act, err := rs.state.GetActor(addr)
|
||||
func (rt *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) {
|
||||
act, err := rt.state.GetActor(addr)
|
||||
if err != nil {
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
return cid.Undef, false
|
||||
@@ -208,8 +210,8 @@ func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, ran
|
||||
return res
|
||||
}
|
||||
|
||||
func (rs *Runtime) Store() vmr.Store {
|
||||
return rs
|
||||
func (rt *Runtime) Store() vmr.Store {
|
||||
return rt
|
||||
}
|
||||
|
||||
func (rt *Runtime) NewActorAddress() address.Address {
|
||||
@@ -234,12 +236,12 @@ func (rt *Runtime) NewActorAddress() address.Address {
|
||||
return addr
|
||||
}
|
||||
|
||||
func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
if !builtin.IsBuiltinActor(codeId) {
|
||||
func (rt *Runtime) CreateActor(codeID cid.Cid, address address.Address) {
|
||||
if !builtin.IsBuiltinActor(codeID) {
|
||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.")
|
||||
}
|
||||
|
||||
if builtin.IsSingletonActor(codeId) {
|
||||
if builtin.IsSingletonActor(codeID) {
|
||||
rt.Abortf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.")
|
||||
}
|
||||
|
||||
@@ -251,7 +253,7 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) {
|
||||
rt.ChargeGas(rt.Pricelist().OnCreateActor())
|
||||
|
||||
err = rt.state.SetActor(address, &types.Actor{
|
||||
Code: codeId,
|
||||
Code: codeID,
|
||||
Head: EmptyObjectCid,
|
||||
Nonce: 0,
|
||||
Balance: big.Zero(),
|
||||
@@ -271,7 +273,9 @@ func (rt *Runtime) DeleteActor(addr address.Address) {
|
||||
panic(aerrors.Fatalf("failed to get actor: %s", err))
|
||||
}
|
||||
if !act.Balance.IsZero() {
|
||||
rt.vm.transfer(rt.Message().Receiver(), builtin.BurntFundsActorAddr, act.Balance)
|
||||
if err := rt.vm.transfer(rt.Message().Receiver(), builtin.BurntFundsActorAddr, act.Balance); err != nil {
|
||||
panic(aerrors.Fatalf("failed to transfer balance to burnt funds actor: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil {
|
||||
@@ -279,12 +283,12 @@ func (rt *Runtime) DeleteActor(addr address.Address) {
|
||||
}
|
||||
}
|
||||
|
||||
func (rs *Runtime) Syscalls() vmr.Syscalls {
|
||||
func (rt *Runtime) Syscalls() vmr.Syscalls {
|
||||
// TODO: Make sure this is wrapped in something that charges gas for each of the calls
|
||||
return rs.sys
|
||||
return rt.sys
|
||||
}
|
||||
|
||||
func (rs *Runtime) StartSpan(name string) vmr.TraceSpan {
|
||||
func (rt *Runtime) StartSpan(name string) vmr.TraceSpan {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -304,12 +308,12 @@ func (rt *Runtime) Context() context.Context {
|
||||
return rt.ctx
|
||||
}
|
||||
|
||||
func (rs *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
|
||||
func (rt *Runtime) Abortf(code exitcode.ExitCode, msg string, args ...interface{}) {
|
||||
log.Error("Abortf: ", fmt.Sprintf(msg, args...))
|
||||
panic(aerrors.NewfSkip(2, code, msg, args...))
|
||||
}
|
||||
|
||||
func (rs *Runtime) AbortStateMsg(msg string) {
|
||||
func (rt *Runtime) AbortStateMsg(msg string) {
|
||||
panic(aerrors.NewfSkip(3, 101, msg))
|
||||
}
|
||||
|
||||
@@ -327,8 +331,8 @@ func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) {
|
||||
rt.Abortf(exitcode.SysErrForbidden, "caller cid type %q was not one of %v", callerCid, ts)
|
||||
}
|
||||
|
||||
func (rs *Runtime) CurrEpoch() abi.ChainEpoch {
|
||||
return rs.height
|
||||
func (rt *Runtime) CurrEpoch() abi.ChainEpoch {
|
||||
return rt.height
|
||||
}
|
||||
|
||||
type dumbWrapperType struct {
|
||||
@@ -339,31 +343,32 @@ func (dwt *dumbWrapperType) Into(um vmr.CBORUnmarshaler) error {
|
||||
return um.UnmarshalCBOR(bytes.NewReader(dwt.val))
|
||||
}
|
||||
|
||||
func (rs *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
||||
if !rs.allowInternal {
|
||||
rs.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
||||
func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMarshaler, value abi.TokenAmount) (vmr.SendReturn, exitcode.ExitCode) {
|
||||
if !rt.allowInternal {
|
||||
rt.Abortf(exitcode.SysErrorIllegalActor, "runtime.Send() is currently disallowed")
|
||||
}
|
||||
var params []byte
|
||||
if m != nil {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := m.MarshalCBOR(buf); err != nil {
|
||||
rs.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
||||
rt.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err)
|
||||
}
|
||||
params = buf.Bytes()
|
||||
}
|
||||
|
||||
ret, err := rs.internalSend(rs.Message().Receiver(), to, method, types.BigInt(value), params)
|
||||
ret, err := rt.internalSend(rt.Message().Receiver(), to, method, value, params)
|
||||
if err != nil {
|
||||
if err.IsFatal() {
|
||||
panic(err)
|
||||
}
|
||||
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
|
||||
return nil, exitcode.ExitCode(err.RetCode())
|
||||
return nil, err.RetCode()
|
||||
}
|
||||
return &dumbWrapperType{ret}, 0
|
||||
}
|
||||
|
||||
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
|
||||
start := time.Now()
|
||||
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
@@ -397,14 +402,15 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
|
||||
}
|
||||
|
||||
mr := types.MessageReceipt{
|
||||
ExitCode: exitcode.ExitCode(aerrors.RetCode(errSend)),
|
||||
ExitCode: aerrors.RetCode(errSend),
|
||||
Return: ret,
|
||||
GasUsed: 0,
|
||||
}
|
||||
|
||||
er := types.ExecutionResult{
|
||||
Msg: msg,
|
||||
MsgRct: &mr,
|
||||
Msg: msg,
|
||||
MsgRct: &mr,
|
||||
Duration: time.Since(start),
|
||||
}
|
||||
|
||||
if errSend != nil {
|
||||
@@ -419,46 +425,48 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
|
||||
return ret, errSend
|
||||
}
|
||||
|
||||
func (rs *Runtime) State() vmr.StateHandle {
|
||||
return &shimStateHandle{rs: rs}
|
||||
func (rt *Runtime) State() vmr.StateHandle {
|
||||
return &shimStateHandle{rt: rt}
|
||||
}
|
||||
|
||||
type shimStateHandle struct {
|
||||
rs *Runtime
|
||||
rt *Runtime
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Create(obj vmr.CBORMarshaler) {
|
||||
c := ssh.rs.Put(obj)
|
||||
ssh.rs.stateCommit(EmptyObjectCid, c)
|
||||
c := ssh.rt.Put(obj)
|
||||
// TODO: handle error below
|
||||
ssh.rt.stateCommit(EmptyObjectCid, c)
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Readonly(obj vmr.CBORUnmarshaler) {
|
||||
act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
if err != nil {
|
||||
ssh.rs.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalArgument, "failed to get actor for Readonly state: %s", err)
|
||||
}
|
||||
ssh.rs.Get(act.Head, obj)
|
||||
ssh.rt.Get(act.Head, obj)
|
||||
}
|
||||
|
||||
func (ssh *shimStateHandle) Transaction(obj vmr.CBORer, f func() interface{}) interface{} {
|
||||
if obj == nil {
|
||||
ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "Must not pass nil to Transaction()")
|
||||
}
|
||||
|
||||
act, err := ssh.rs.state.GetActor(ssh.rs.Message().Receiver())
|
||||
act, err := ssh.rt.state.GetActor(ssh.rt.Message().Receiver())
|
||||
if err != nil {
|
||||
ssh.rs.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
ssh.rt.Abortf(exitcode.SysErrorIllegalActor, "failed to get actor for Transaction: %s", err)
|
||||
}
|
||||
baseState := act.Head
|
||||
ssh.rs.Get(baseState, obj)
|
||||
ssh.rt.Get(baseState, obj)
|
||||
|
||||
ssh.rs.allowInternal = false
|
||||
ssh.rt.allowInternal = false
|
||||
out := f()
|
||||
ssh.rs.allowInternal = true
|
||||
ssh.rt.allowInternal = true
|
||||
|
||||
c := ssh.rs.Put(obj)
|
||||
c := ssh.rt.Put(obj)
|
||||
|
||||
ssh.rs.stateCommit(baseState, c)
|
||||
// TODO: handle error below
|
||||
ssh.rt.stateCommit(baseState, c)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
+37
-17
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
goruntime "runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -183,7 +185,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sigs.CheckBlockSignature(blk, ss.ctx, waddr); err != nil {
|
||||
if err := sigs.CheckBlockSignature(ss.ctx, blk, waddr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -201,20 +203,6 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cidToCommD(c cid.Cid) [32]byte {
|
||||
b := c.Bytes()
|
||||
var out [32]byte
|
||||
copy(out[:], b[len(b)-32:])
|
||||
return out
|
||||
}
|
||||
|
||||
func cidToCommR(c cid.Cid) [32]byte {
|
||||
b := c.Bytes()
|
||||
var out [32]byte
|
||||
copy(out[:], b[len(b)-32:])
|
||||
return out
|
||||
}
|
||||
|
||||
func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
|
||||
//_, span := trace.StartSpan(ctx, "ValidatePoRep")
|
||||
//defer span.End()
|
||||
@@ -225,10 +213,10 @@ func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error {
|
||||
}
|
||||
|
||||
ticket := []byte(info.Randomness)
|
||||
proof := []byte(info.OnChain.Proof)
|
||||
proof := info.Proof
|
||||
seed := []byte(info.InteractiveRandomness)
|
||||
|
||||
log.Debugf("Verif r:%x; d:%x; m:%s; t:%x; s:%x; N:%d; p:%x", info.OnChain.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof)
|
||||
log.Debugf("Verif r:%x; d:%x; m:%s; t:%x; s:%x; N:%d; p:%x", info.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof)
|
||||
|
||||
//func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber)
|
||||
ok, err := ss.verifier.VerifySeal(info)
|
||||
@@ -252,3 +240,35 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres
|
||||
|
||||
return sigs.Verify(&sig, kaddr, input)
|
||||
}
|
||||
|
||||
func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) {
|
||||
out := make(map[address.Address][]bool)
|
||||
|
||||
sema := make(chan struct{}, goruntime.NumCPU())
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for addr, seals := range inp {
|
||||
results := make([]bool, len(seals))
|
||||
out[addr] = results
|
||||
|
||||
for i, s := range seals {
|
||||
wg.Add(1)
|
||||
go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) {
|
||||
defer wg.Done()
|
||||
sema <- struct{}{}
|
||||
|
||||
if err := ss.VerifySeal(svi); err != nil {
|
||||
log.Warnw("seal verify in batch failed", "miner", ma, "index", ix, "err", err)
|
||||
res[ix] = false
|
||||
} else {
|
||||
res[ix] = true
|
||||
}
|
||||
|
||||
<-sema
|
||||
}(addr, i, s, results)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ func init() {
|
||||
func TestChainValidationMessageSuite(t *testing.T) {
|
||||
f := factory.NewFactories()
|
||||
for _, testCase := range suites.MessageTestCases() {
|
||||
testCase := testCase
|
||||
if TestSuiteSkipper.Skip(testCase) {
|
||||
continue
|
||||
}
|
||||
@@ -53,6 +54,7 @@ func TestChainValidationMessageSuite(t *testing.T) {
|
||||
func TestChainValidationTipSetSuite(t *testing.T) {
|
||||
f := factory.NewFactories()
|
||||
for _, testCase := range suites.TipSetTestCases() {
|
||||
testCase := testCase
|
||||
if TestSuiteSkipper.Skip(testCase) {
|
||||
continue
|
||||
}
|
||||
|
||||
+31
-17
@@ -131,7 +131,7 @@ type VM struct {
|
||||
cst *cbor.BasicIpldStore
|
||||
buf *bufbstore.BufferedBS
|
||||
blockHeight abi.ChainEpoch
|
||||
inv *invoker
|
||||
inv *Invoker
|
||||
rand Rand
|
||||
|
||||
Syscalls runtime.Syscalls
|
||||
@@ -210,7 +210,7 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
|
||||
|
||||
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
|
||||
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
|
||||
return nil, aerrors.Absorb(err, 1, "failed to transfer funds"), nil
|
||||
return nil, aerrors.Wrap(err, "failed to transfer funds"), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
|
||||
ret, actorErr, rt := vm.send(ctx, msg, nil, 0)
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.ExitCode(aerrors.RetCode(actorErr)),
|
||||
ExitCode: aerrors.RetCode(actorErr),
|
||||
Return: ret,
|
||||
GasUsed: 0,
|
||||
},
|
||||
@@ -415,7 +415,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
|
||||
return &ApplyRet{
|
||||
MessageReceipt: types.MessageReceipt{
|
||||
ExitCode: exitcode.ExitCode(errcode),
|
||||
ExitCode: errcode,
|
||||
Return: ret,
|
||||
GasUsed: gasUsed,
|
||||
},
|
||||
@@ -454,7 +454,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// vm.MutateState(idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...})
|
||||
// MutateState usage: MutateState(ctx, idAddr, func(cst cbor.IpldStore, st *ActorStateType) error {...})
|
||||
func (vm *VM) MutateState(ctx context.Context, addr address.Address, fn interface{}) error {
|
||||
act, err := vm.cstate.GetActor(addr)
|
||||
if err != nil {
|
||||
@@ -591,7 +591,7 @@ func (vm *VM) Invoke(act *types.Actor, rt *Runtime, method abi.MethodNum, params
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (vm *VM) SetInvoker(i *invoker) {
|
||||
func (vm *VM) SetInvoker(i *Invoker) {
|
||||
vm.inv = i
|
||||
}
|
||||
|
||||
@@ -602,36 +602,50 @@ func (vm *VM) incrementNonce(addr address.Address) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (vm *VM) transfer(from, to address.Address, amt types.BigInt) error {
|
||||
func (vm *VM) transfer(from, to address.Address, amt types.BigInt) aerrors.ActorError {
|
||||
if from == to {
|
||||
return nil
|
||||
}
|
||||
|
||||
fromID, err := vm.cstate.LookupID(from)
|
||||
if err != nil {
|
||||
return aerrors.Fatalf("transfer failed when resolving sender address: %s", err)
|
||||
}
|
||||
|
||||
toID, err := vm.cstate.LookupID(to)
|
||||
if err != nil {
|
||||
return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err)
|
||||
}
|
||||
|
||||
if fromID == toID {
|
||||
return nil
|
||||
}
|
||||
|
||||
if amt.LessThan(types.NewInt(0)) {
|
||||
return xerrors.Errorf("attempted to transfer negative value")
|
||||
return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt)
|
||||
}
|
||||
|
||||
f, err := vm.cstate.GetActor(from)
|
||||
f, err := vm.cstate.GetActor(fromID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("transfer failed when retrieving sender actor")
|
||||
return aerrors.Fatalf("transfer failed when retrieving sender actor: %s", err)
|
||||
}
|
||||
|
||||
t, err := vm.cstate.GetActor(to)
|
||||
t, err := vm.cstate.GetActor(toID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("transfer failed when retrieving receiver actor")
|
||||
return aerrors.Fatalf("transfer failed when retrieving receiver actor: %s", err)
|
||||
}
|
||||
|
||||
if err := deductFunds(f, amt); err != nil {
|
||||
return err
|
||||
return aerrors.Newf(exitcode.SysErrInsufficientFunds, "transfer failed when deducting funds: %s", err)
|
||||
}
|
||||
depositFunds(t, amt)
|
||||
|
||||
if err := vm.cstate.SetActor(from, f); err != nil {
|
||||
return err
|
||||
if err := vm.cstate.SetActor(fromID, f); err != nil {
|
||||
return aerrors.Fatalf("transfer failed when setting receiver actor: %s", err)
|
||||
}
|
||||
|
||||
if err := vm.cstate.SetActor(to, t); err != nil {
|
||||
return err
|
||||
if err := vm.cstate.SetActor(toID, t); err != nil {
|
||||
return aerrors.Fatalf("transfer failed when setting sender actor: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
|
||||
+5
-3
@@ -3,8 +3,10 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
@@ -45,7 +47,7 @@ var authCreateAdminToken = &cli.Command{
|
||||
perm := cctx.String("perm")
|
||||
idx := 0
|
||||
for i, p := range apistruct.AllPermissions {
|
||||
if perm == p {
|
||||
if auth.Permission(perm) == p {
|
||||
idx = i + 1
|
||||
}
|
||||
}
|
||||
@@ -93,7 +95,7 @@ var authApiInfoToken = &cli.Command{
|
||||
perm := cctx.String("perm")
|
||||
idx := 0
|
||||
for i, p := range apistruct.AllPermissions {
|
||||
if perm == p {
|
||||
if auth.Permission(perm) == p {
|
||||
idx = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
+16
-3
@@ -18,13 +18,14 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
@@ -441,7 +442,8 @@ var chainGetCmd = &cli.Command{
|
||||
- /ipfs/[cid]/@Hi:123 - get varint elem 123 from hamt
|
||||
- /ipfs/[cid]/@Hu:123 - get uvarint elem 123 from hamt
|
||||
- /ipfs/[cid]/@Ha:t01 - get element under Addr(t01).Bytes
|
||||
- /ipfs/[cid]/@A:10 - get 10th amt element
|
||||
- /ipfs/[cid]/@A:10 - get 10th amt element
|
||||
- .../@Ha:t01/@state - get pretty map-based actor state
|
||||
|
||||
List of --as-type types:
|
||||
- raw
|
||||
@@ -521,6 +523,12 @@ var chainGetCmd = &cli.Command{
|
||||
cbu = new(power.CronEvent)
|
||||
case "account-state":
|
||||
cbu = new(account.State)
|
||||
case "miner-state":
|
||||
cbu = new(miner.State)
|
||||
case "power-state":
|
||||
cbu = new(power.State)
|
||||
case "market-state":
|
||||
cbu = new(market.State)
|
||||
default:
|
||||
return fmt.Errorf("unknown type: %q", t)
|
||||
}
|
||||
@@ -797,7 +805,12 @@ var chainExportCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
defer func() {
|
||||
err := fi.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("error closing output file: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
|
||||
+89
-18
@@ -8,9 +8,11 @@ import (
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cidutil/cidenc"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/multiformats/go-multibase"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
@@ -21,6 +23,32 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var CidBaseFlag = cli.StringFlag{
|
||||
Name: "cid-base",
|
||||
Hidden: true,
|
||||
Value: "base32",
|
||||
Usage: "Multibase encoding used for version 1 CIDs in output.",
|
||||
DefaultText: "base32",
|
||||
}
|
||||
|
||||
// GetCidEncoder returns an encoder using the `cid-base` flag if provided, or
|
||||
// the default (Base32) encoder if not.
|
||||
func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) {
|
||||
val := cctx.String("cid-base")
|
||||
|
||||
e := cidenc.Encoder{Base: multibase.MustNewEncoder(multibase.Base32)}
|
||||
|
||||
if val != "" {
|
||||
var err error
|
||||
e.Base, err = multibase.EncoderByName(val)
|
||||
if err != nil {
|
||||
return e, err
|
||||
}
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
var clientCmd = &cli.Command{
|
||||
Name: "client",
|
||||
Usage: "Make deals, store data, retrieve data",
|
||||
@@ -46,6 +74,7 @@ var clientImportCmd = &cli.Command{
|
||||
Name: "car",
|
||||
Usage: "import from a car file instead of a regular file",
|
||||
},
|
||||
&CidBaseFlag,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -67,7 +96,14 @@ var clientImportCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(c.String())
|
||||
|
||||
encoder, err := GetCidEncoder(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(encoder.Encode(c))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -76,6 +112,9 @@ var clientCommPCmd = &cli.Command{
|
||||
Name: "commP",
|
||||
Usage: "calculate the piece-cid (commP) of a CAR file",
|
||||
ArgsUsage: "[inputFile minerAddress]",
|
||||
Flags: []cli.Flag{
|
||||
&CidBaseFlag,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -94,11 +133,16 @@ var clientCommPCmd = &cli.Command{
|
||||
}
|
||||
|
||||
ret, err := api.ClientCalcCommP(ctx, cctx.Args().Get(0), miner)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("CID: ", ret.Root)
|
||||
|
||||
encoder, err := GetCidEncoder(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("CID: ", encoder.Encode(ret.Root))
|
||||
fmt.Println("Piece size: ", ret.Size)
|
||||
return nil
|
||||
},
|
||||
@@ -137,6 +181,9 @@ var clientCarGenCmd = &cli.Command{
|
||||
var clientLocalCmd = &cli.Command{
|
||||
Name: "local",
|
||||
Usage: "List locally imported data",
|
||||
Flags: []cli.Flag{
|
||||
&CidBaseFlag,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -149,8 +196,14 @@ var clientLocalCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encoder, err := GetCidEncoder(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, v := range list {
|
||||
fmt.Printf("%s %s %d %s\n", v.Key, v.FilePath, v.Size, v.Status)
|
||||
fmt.Printf("%s %s %d %s\n", encoder.Encode(v.Key), v.FilePath, v.Size, v.Status)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -178,6 +231,7 @@ var clientDealCmd = &cli.Command{
|
||||
Usage: "specify the epoch that the deal should start at",
|
||||
Value: -1,
|
||||
},
|
||||
&CidBaseFlag,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -263,7 +317,13 @@ var clientDealCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(proposal)
|
||||
encoder, err := GetCidEncoder(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(encoder.Encode(*proposal))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -384,7 +444,7 @@ var clientRetrieveCmd = &cli.Command{
|
||||
return nil
|
||||
}
|
||||
|
||||
ref := lapi.FileRef{
|
||||
ref := &lapi.FileRef{
|
||||
Path: cctx.Args().Get(1),
|
||||
IsCAR: cctx.Bool("car"),
|
||||
}
|
||||
@@ -446,11 +506,11 @@ var clientQueryAskCmd = &cli.Command{
|
||||
return xerrors.Errorf("failed to get peerID for miner: %w", err)
|
||||
}
|
||||
|
||||
if mi.PeerId == peer.ID("SETME") {
|
||||
if peer.ID(mi.PeerId) == peer.ID("SETME") {
|
||||
return fmt.Errorf("the miner hasn't initialized yet")
|
||||
}
|
||||
|
||||
pid = mi.PeerId
|
||||
pid = peer.ID(mi.PeerId)
|
||||
}
|
||||
|
||||
ask, err := api.ClientQueryAsk(ctx, pid, maddr)
|
||||
@@ -501,16 +561,27 @@ var clientListDeals = &cli.Command{
|
||||
}
|
||||
|
||||
var deals []deal
|
||||
for idx := range localDeals {
|
||||
onChain, err := api.StateMarketStorageDeal(ctx, localDeals[idx].DealID, head.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range localDeals {
|
||||
if v.DealID == 0 {
|
||||
deals = append(deals, deal{
|
||||
LocalDeal: v,
|
||||
OnChainDealState: market.DealState{
|
||||
SectorStartEpoch: -1,
|
||||
LastUpdatedEpoch: -1,
|
||||
SlashEpoch: -1,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
onChain, err := api.StateMarketStorageDeal(ctx, v.DealID, head.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deals = append(deals, deal{
|
||||
LocalDeal: localDeals[idx],
|
||||
OnChainDealState: onChain.State,
|
||||
})
|
||||
deals = append(deals, deal{
|
||||
LocalDeal: v,
|
||||
OnChainDealState: onChain.State,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0)
|
||||
|
||||
+25
-19
@@ -13,12 +13,13 @@ import (
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr-net"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
"github.com/filecoin-project/lotus/lib/jsonrpc"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
@@ -210,28 +211,33 @@ func ReqContext(cctx *cli.Context) context.Context {
|
||||
}
|
||||
|
||||
var CommonCommands = []*cli.Command{
|
||||
authCmd,
|
||||
fetchParamCmd,
|
||||
netCmd,
|
||||
versionCmd,
|
||||
authCmd,
|
||||
logCmd,
|
||||
waitApiCmd,
|
||||
fetchParamCmd,
|
||||
versionCmd,
|
||||
}
|
||||
|
||||
var Commands = []*cli.Command{
|
||||
authCmd,
|
||||
chainCmd,
|
||||
clientCmd,
|
||||
fetchParamCmd,
|
||||
mpoolCmd,
|
||||
multisigCmd,
|
||||
netCmd,
|
||||
paychCmd,
|
||||
sendCmd,
|
||||
stateCmd,
|
||||
syncCmd,
|
||||
withCategory("basic", sendCmd),
|
||||
withCategory("basic", walletCmd),
|
||||
withCategory("basic", clientCmd),
|
||||
withCategory("basic", multisigCmd),
|
||||
withCategory("basic", paychCmd),
|
||||
withCategory("developer", authCmd),
|
||||
withCategory("developer", mpoolCmd),
|
||||
withCategory("developer", stateCmd),
|
||||
withCategory("developer", chainCmd),
|
||||
withCategory("developer", logCmd),
|
||||
withCategory("developer", waitApiCmd),
|
||||
withCategory("developer", fetchParamCmd),
|
||||
withCategory("network", netCmd),
|
||||
withCategory("network", syncCmd),
|
||||
versionCmd,
|
||||
walletCmd,
|
||||
logCmd,
|
||||
waitApiCmd,
|
||||
}
|
||||
|
||||
func withCategory(cat string, cmd *cli.Command) *cli.Command {
|
||||
cmd.Category = cat
|
||||
return cmd
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
var logCmd = &cli.Command{
|
||||
|
||||
+1
-1
@@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
|
||||
+9
-5
@@ -17,12 +17,13 @@ import (
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -117,7 +118,7 @@ var msigCreateCmd = &cli.Command{
|
||||
}
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -206,7 +207,10 @@ var msigInspectCmd = &cli.Command{
|
||||
tx := pending[txid]
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%x\n", txid, state(tx), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
|
||||
}
|
||||
w.Flush()
|
||||
if err := w.Flush(); err != nil {
|
||||
return xerrors.Errorf("flushing output: %+v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -333,7 +337,7 @@ var msigProposeCmd = &cli.Command{
|
||||
|
||||
fmt.Println("send proposal in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -449,7 +453,7 @@ var msigApproveCmd = &cli.Command{
|
||||
|
||||
fmt.Println("sent approval in message: ", msgCid)
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid)
|
||||
wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+26
-2
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/addrutil"
|
||||
)
|
||||
@@ -21,6 +21,7 @@ var netCmd = &cli.Command{
|
||||
netListen,
|
||||
netId,
|
||||
netFindPeer,
|
||||
netScores,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -44,7 +45,30 @@ var netPeers = &cli.Command{
|
||||
})
|
||||
|
||||
for _, peer := range peers {
|
||||
fmt.Println(peer)
|
||||
fmt.Printf("%s, %s\n", peer.ID, peer.Addrs)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var netScores = &cli.Command{
|
||||
Name: "scores",
|
||||
Usage: "Print peers' pubsub scores",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
scores, err := api.NetPubsubScores(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, peer := range scores {
|
||||
fmt.Printf("%s, %f\n", peer.ID, peer.Score)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+3
-2
@@ -3,8 +3,8 @@ package cli
|
||||
import (
|
||||
"github.com/docker/go-units"
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
@@ -24,7 +24,8 @@ var fetchParamCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
sectorSize := uint64(sectorSizeInt)
|
||||
err = paramfetch.GetParams(build.ParametersJson(), sectorSize)
|
||||
|
||||
err = paramfetch.GetParams(ReqContext(cctx), build.ParametersJSON(), sectorSize)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
+4
-3
@@ -4,10 +4,11 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
@@ -361,7 +362,7 @@ var paychVoucherSubmitCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
mwait, err := api.StateWaitMsg(ctx, mcid)
|
||||
mwait, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -370,7 +371,7 @@ var paychVoucherSubmitCmd = &cli.Command{
|
||||
return fmt.Errorf("message execution failed (exit code %d)", mwait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
fmt.Println("channel updated succesfully")
|
||||
fmt.Println("channel updated successfully")
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var sendCmd = &cli.Command{
|
||||
|
||||
+94
-18
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -14,9 +15,9 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@@ -34,6 +35,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
)
|
||||
@@ -391,7 +393,7 @@ var stateReplaySetCmd = &cli.Command{
|
||||
|
||||
ts, err = types.NewTipSet(headers)
|
||||
} else {
|
||||
r, err := api.StateWaitMsg(ctx, mcid)
|
||||
r, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("finding message in chain: %w", err)
|
||||
}
|
||||
@@ -493,6 +495,12 @@ var stateGetDealSetCmd = &cli.Command{
|
||||
var stateListMinersCmd = &cli.Command{
|
||||
Name: "list-miners",
|
||||
Usage: "list all miners in the network",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "sort-by",
|
||||
Usage: "criteria to sort miners by (none, num-deals)",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -512,6 +520,26 @@ var stateListMinersCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
switch cctx.String("sort-by") {
|
||||
case "num-deals":
|
||||
ndm, err := getDealsCounts(ctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sort.Slice(miners, func(i, j int) bool {
|
||||
return ndm[miners[i]] > ndm[miners[j]]
|
||||
})
|
||||
|
||||
for i := 0; i < 50 && i < len(miners); i++ {
|
||||
fmt.Printf("%s %d\n", miners[i], ndm[miners[i]])
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unrecognized sorting order")
|
||||
case "", "none":
|
||||
}
|
||||
|
||||
for _, m := range miners {
|
||||
fmt.Println(m.String())
|
||||
}
|
||||
@@ -520,6 +548,22 @@ var stateListMinersCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func getDealsCounts(ctx context.Context, lapi api.FullNode) (map[address.Address]int, error) {
|
||||
allDeals, err := lapi.StateMarketDeals(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(map[address.Address]int)
|
||||
for _, d := range allDeals {
|
||||
if d.State.SectorStartEpoch != -1 {
|
||||
out[d.Proposal.Provider]++
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
var stateListActorsCmd = &cli.Command{
|
||||
Name: "list-actors",
|
||||
Usage: "list all actors in the network",
|
||||
@@ -892,7 +936,7 @@ var stateComputeStateCmd = &cli.Command{
|
||||
return c.Code, nil
|
||||
}
|
||||
|
||||
return computeStateHtml(stout, getCode)
|
||||
return computeStateHtml(ts, stout, getCode)
|
||||
}
|
||||
|
||||
fmt.Println("computed state cid: ", stout.Root)
|
||||
@@ -921,7 +965,7 @@ func codeStr(c cid.Cid) string {
|
||||
return string(cmh.Digest)
|
||||
}
|
||||
|
||||
func computeStateHtml(o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
|
||||
func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(addr address.Address) (cid.Cid, error)) error {
|
||||
fmt.Printf(`<html>
|
||||
<head>
|
||||
<style>
|
||||
@@ -947,8 +991,10 @@ func computeStateHtml(o *api.ComputeStateOutput, getCode func(addr address.Addre
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>Tipset: <b>%s</b></div>
|
||||
<div>Height: %d</div>
|
||||
<div>State CID: <b>%s</b></div>
|
||||
<div>Calls</div>`, o.Root)
|
||||
<div>Calls</div>`, ts.Key(), ts.Height(), o.Root)
|
||||
|
||||
for _, ir := range o.Trace {
|
||||
toCode, err := getCode(ir.Msg.To)
|
||||
@@ -996,7 +1042,7 @@ func computeStateHtml(o *api.ComputeStateOutput, getCode func(addr address.Addre
|
||||
|
||||
if len(ir.InternalExecutions) > 0 {
|
||||
fmt.Println("<div>Internal executions:</div>")
|
||||
if err := printInternalExecutionsHtml(ir.InternalExecutions, getCode); err != nil {
|
||||
if err := printInternalExecutionsHtml(cid.String(), ir.InternalExecutions, getCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1008,8 +1054,10 @@ func computeStateHtml(o *api.ComputeStateOutput, getCode func(addr address.Addre
|
||||
return nil
|
||||
}
|
||||
|
||||
func printInternalExecutionsHtml(trace []*types.ExecutionResult, getCode func(addr address.Address) (cid.Cid, error)) error {
|
||||
for _, im := range trace {
|
||||
func printInternalExecutionsHtml(hashName string, trace []*types.ExecutionResult, getCode func(addr address.Address) (cid.Cid, error)) error {
|
||||
for i, im := range trace {
|
||||
hashName := fmt.Sprintf("%s-r%d", hashName, i)
|
||||
|
||||
toCode, err := getCode(im.Msg.To)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting code for %s: %w", toCode, err)
|
||||
@@ -1037,18 +1085,21 @@ func printInternalExecutionsHtml(trace []*types.ExecutionResult, getCode func(ad
|
||||
ret = `, Return</div><div><pre class="ret">` + ret + `</pre></div>`
|
||||
}
|
||||
|
||||
fmt.Printf(`<div class="exec">
|
||||
<div><h4 class="call">%s:%s</h4></div>
|
||||
slow := im.Duration > 10*time.Millisecond
|
||||
veryslow := im.Duration > 50*time.Millisecond
|
||||
|
||||
fmt.Printf(`<div class="exec" id="%s">
|
||||
<div><a href="#%s"><h4 class="call">%s:%s</h4></a></div>
|
||||
<div><b>%s</b> -> <b>%s</b> (%s FIL), M%d</div>
|
||||
%s
|
||||
<div><span class="exit%d">Exit: <b>%d</b></span>%s
|
||||
`, codeStr(toCode), methods[toCode][im.Msg.Method].name, im.Msg.From, im.Msg.To, types.FIL(im.Msg.Value), im.Msg.Method, params, im.MsgRct.ExitCode, im.MsgRct.ExitCode, ret)
|
||||
<div><span class="slow-%t-%t">Took %s</span>, <span class="exit%d">Exit: <b>%d</b></span>%s
|
||||
`, hashName, hashName, codeStr(toCode), methods[toCode][im.Msg.Method].name, im.Msg.From, im.Msg.To, types.FIL(im.Msg.Value), im.Msg.Method, params, slow, veryslow, im.Duration, im.MsgRct.ExitCode, im.MsgRct.ExitCode, ret)
|
||||
if im.MsgRct.ExitCode != 0 {
|
||||
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, im.Error)
|
||||
}
|
||||
if len(im.Subcalls) > 0 {
|
||||
fmt.Println("<div>Subcalls:</div>")
|
||||
if err := printInternalExecutionsHtml(im.Subcalls, getCode); err != nil {
|
||||
if err := printInternalExecutionsHtml(hashName, im.Subcalls, getCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1108,19 +1159,44 @@ var stateWaitMsgCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
mw, err := api.StateWaitMsg(ctx, msg)
|
||||
mw, err := api.StateWaitMsg(ctx, msg, build.MessageConfidence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("message was executed in tipset: %s", mw.TipSet.Cids())
|
||||
fmt.Printf("Exit Code: %d", mw.Receipt.ExitCode)
|
||||
fmt.Printf("Gas Used: %d", mw.Receipt.GasUsed)
|
||||
fmt.Printf("Return: %x", mw.Receipt.Return)
|
||||
m, err := api.ChainGetMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("message was executed in tipset: %s\n", mw.TipSet.Cids())
|
||||
fmt.Printf("Exit Code: %d\n", mw.Receipt.ExitCode)
|
||||
fmt.Printf("Gas Used: %d\n", mw.Receipt.GasUsed)
|
||||
fmt.Printf("Return: %x\n", mw.Receipt.Return)
|
||||
if err := printReceiptReturn(ctx, api, m, mw.Receipt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func printReceiptReturn(ctx context.Context, api api.FullNode, m *types.Message, r types.MessageReceipt) error {
|
||||
act, err := api.StateGetActor(ctx, m.To, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jret, err := jsonReturn(act.Code, m.Method, r.Return)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(jret)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var stateSearchMsgCmd = &cli.Command{
|
||||
Name: "search-msg",
|
||||
Usage: "Search to see whether a message has appeared on chain",
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
+4
-2
@@ -3,7 +3,7 @@ package cli
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var versionCmd = &cli.Command{
|
||||
@@ -23,7 +23,9 @@ var versionCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(v)
|
||||
fmt.Println("Daemon: ", v)
|
||||
|
||||
fmt.Print("Local: ")
|
||||
cli.VersionPrinter(cctx)
|
||||
return nil
|
||||
},
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var waitApiCmd = &cli.Command{
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var walletCmd = &cli.Command{
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -53,8 +53,7 @@ var runCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
sendSmallFundsTxs(ctx, api, addr, 5)
|
||||
return nil
|
||||
return sendSmallFundsTxs(ctx, api, addr, 5)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ import (
|
||||
"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/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -22,7 +24,7 @@ import (
|
||||
"github.com/ipfs/go-datastore"
|
||||
badger "github.com/ipfs/go-ds-badger2"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
type TipSetExec struct {
|
||||
@@ -53,7 +55,7 @@ var importBenchCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cfi.Close()
|
||||
defer cfi.Close() //nolint:errcheck // read only file
|
||||
|
||||
tdir, err := ioutil.TempDir("", "lotus-import-bench")
|
||||
if err != nil {
|
||||
@@ -65,6 +67,11 @@ var importBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
bs := blockstore.NewBlockstore(bds)
|
||||
cbs, err := blockstore.CachedBlockstore(context.TODO(), bs, blockstore.DefaultCacheOpts())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bs = cbs
|
||||
ds := datastore.NewMapDatastore()
|
||||
cs := store.NewChainStore(bs, ds, vm.Syscalls(ffiwrapper.ProofVerifier))
|
||||
stm := stmgr.NewStateManager(cs)
|
||||
@@ -73,7 +80,7 @@ var importBenchCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer prof.Close()
|
||||
defer prof.Close() //nolint:errcheck
|
||||
|
||||
if err := pprof.StartCPUProfile(prof); err != nil {
|
||||
return err
|
||||
@@ -111,7 +118,14 @@ var importBenchCmd = &cli.Command{
|
||||
cur := tschain[i]
|
||||
log.Infof("computing state (height: %d, ts=%s)", cur.Height(), cur.Cids())
|
||||
if cur.ParentState() != lastState {
|
||||
return xerrors.Errorf("tipset chain had state mismatch at height %d", cur.Height())
|
||||
lastTrace := out[len(out)-1].Trace
|
||||
d, err := json.MarshalIndent(lastTrace, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("TRACE")
|
||||
fmt.Println(string(d))
|
||||
return xerrors.Errorf("tipset chain had state mismatch at height %d (%s != %s)", cur.Height(), cur.ParentState(), lastState)
|
||||
}
|
||||
start := time.Now()
|
||||
st, trace, err := stm.ExecutionTrace(context.TODO(), cur)
|
||||
@@ -132,7 +146,7 @@ var importBenchCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ibj.Close()
|
||||
defer ibj.Close() //nolint:errcheck
|
||||
|
||||
if err := json.NewEncoder(ibj).Encode(out); err != nil {
|
||||
return err
|
||||
|
||||
+23
-23
@@ -15,11 +15,12 @@ import (
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper/basicfs"
|
||||
"github.com/filecoin-project/sector-storage/stores"
|
||||
@@ -78,7 +79,7 @@ func main() {
|
||||
app := &cli.App{
|
||||
Name: "lotus-bench",
|
||||
Usage: "Benchmark performance of lotus on your hardware",
|
||||
Version: build.UserVersion,
|
||||
Version: build.UserVersion(),
|
||||
Commands: []*cli.Command{
|
||||
proveCmd,
|
||||
sealBenchCmd,
|
||||
@@ -141,7 +142,10 @@ var sealBenchCmd = &cli.Command{
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.Bool("no-gpu") {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
err := os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting no-gpu flag: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
robench := c.String("benchmark-existing-sectorbuilder")
|
||||
@@ -154,7 +158,10 @@ var sealBenchCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
os.MkdirAll(sdir, 0775)
|
||||
err = os.MkdirAll(sdir, 0775) //nolint:gosec
|
||||
if err != nil {
|
||||
return xerrors.Errorf("creating sectorbuilder dir: %w", err)
|
||||
}
|
||||
|
||||
tsdir, err := ioutil.TempDir(sdir, "bench")
|
||||
if err != nil {
|
||||
@@ -209,7 +216,7 @@ var sealBenchCmd = &cli.Command{
|
||||
|
||||
// Only fetch parameters if actually needed
|
||||
if !c.Bool("skip-commit2") {
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), uint64(sectorSize)); err != nil {
|
||||
if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), uint64(sectorSize)); err != nil {
|
||||
return xerrors.Errorf("getting params: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -527,16 +534,11 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, mid
|
||||
|
||||
if !skipc2 {
|
||||
svi := abi.SealVerifyInfo{
|
||||
SectorID: abi.SectorID{Miner: mid, Number: i},
|
||||
OnChain: abi.OnChainSealVerifyInfo{
|
||||
SealedCID: cids.Sealed,
|
||||
InteractiveEpoch: seed.Epoch,
|
||||
RegisteredProof: sb.SealProofType(),
|
||||
Proof: proof,
|
||||
DealIDs: nil,
|
||||
SectorNumber: i,
|
||||
SealRandEpoch: 0,
|
||||
},
|
||||
SectorID: abi.SectorID{Miner: mid, Number: i},
|
||||
SealedCID: cids.Sealed,
|
||||
RegisteredProof: sb.SealProofType(),
|
||||
Proof: proof,
|
||||
DealIDs: nil,
|
||||
Randomness: ticket,
|
||||
InteractiveRandomness: seed.Value,
|
||||
UnsealedCID: cids.Unsealed,
|
||||
@@ -567,15 +569,10 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, mid
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RM unsealed sector first
|
||||
rc, err := sb.ReadPieceFromSealedSector(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, 0, abi.UnpaddedPieceSize(sectorSize), ticket, cids.Unsealed)
|
||||
err := sb.UnsealPiece(context.TODO(), abi.SectorID{Miner: mid, Number: 1}, 0, abi.UnpaddedPieceSize(sectorSize), ticket, cids.Unsealed)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := rc.Close(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
unseal := time.Now()
|
||||
|
||||
@@ -604,7 +601,10 @@ var proveCmd = &cli.Command{
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.Bool("no-gpu") {
|
||||
os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
err := os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting no-gpu flag: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !c.Args().Present() {
|
||||
@@ -621,7 +621,7 @@ var proveCmd = &cli.Command{
|
||||
return xerrors.Errorf("unmarshalling input file: %w", err)
|
||||
}
|
||||
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), c2in.SectorSize); err != nil {
|
||||
if err := paramfetch.GetParams(lcli.ReqContext(c), build.ParametersJSON(), c2in.SectorSize); err != nil {
|
||||
return xerrors.Errorf("getting params: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func subBlocks(ctx context.Context, api aapi.FullNode, st *storage) {
|
||||
bh.Cid(): bh,
|
||||
}, false)
|
||||
if err != nil {
|
||||
//log.Errorf("%+v", err)
|
||||
log.Errorf("%+v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var dotCmd = &cli.Command{
|
||||
@@ -20,7 +20,13 @@ var dotCmd = &cli.Command{
|
||||
}
|
||||
|
||||
minH, err := strconv.ParseInt(cctx.Args().Get(0), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tosee, err := strconv.ParseInt(cctx.Args().Get(1), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxH := minH + tosee
|
||||
|
||||
res, err := st.db.Query(`select block, parent, b.miner, b.height, p.height from block_parents
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"os"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
var log = logging.Logger("chainwatch")
|
||||
|
||||
func main() {
|
||||
logging.SetLogLevel("*", "INFO")
|
||||
_ = logging.SetLogLevel("*", "INFO")
|
||||
|
||||
log.Info("Starting chainwatch")
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
app := &cli.App{
|
||||
Name: "lotus-chainwatch",
|
||||
Usage: "Devnet token distribution utility",
|
||||
Version: build.UserVersion,
|
||||
Version: build.UserVersion(),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
@@ -86,7 +86,7 @@ var runCmd = &cli.Command{
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer st.close()
|
||||
defer st.close() //nolint:errcheck
|
||||
|
||||
runSyncer(ctx, api, st, maxBatch)
|
||||
|
||||
|
||||
@@ -653,6 +653,14 @@ create temp table b (like blocks excluding constraints) on commit drop;
|
||||
eprof = bh.ElectionProof.VRFProof
|
||||
}
|
||||
|
||||
if bh.Ticket == nil {
|
||||
log.Warnf("got a block with nil ticket")
|
||||
|
||||
bh.Ticket = &types.Ticket{
|
||||
VRFProof: []byte{},
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := stmt2.Exec(
|
||||
bh.Cid().String(),
|
||||
bh.ParentWeight.String(),
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
parmap "github.com/filecoin-project/lotus/lib/parmap"
|
||||
)
|
||||
|
||||
func runSyncer(ctx context.Context, api api.FullNode, st *storage, maxBatch int) {
|
||||
@@ -138,21 +139,21 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
log.Infof("Syncing %d blocks", len(toSync))
|
||||
|
||||
paDone := 0
|
||||
par(50, maparr(toSync), func(bh *types.BlockHeader) {
|
||||
parmap.Par(50, parmap.MapArr(toSync), func(bh *types.BlockHeader) {
|
||||
paDone++
|
||||
if paDone%100 == 0 {
|
||||
log.Infof("pa: %d %d%%", paDone, (paDone*100)/len(toSync))
|
||||
}
|
||||
|
||||
if len(bh.Parents) == 0 { // genesis case
|
||||
ts, err := types.NewTipSet([]*types.BlockHeader{bh})
|
||||
ts, _ := types.NewTipSet([]*types.BlockHeader{bh})
|
||||
aadrs, err := api.StateListActors(ctx, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
par(50, aadrs, func(addr address.Address) {
|
||||
parmap.Par(50, aadrs, func(addr address.Address) {
|
||||
act, err := api.StateGetActor(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -198,6 +199,8 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
}
|
||||
|
||||
for a, act := range changes {
|
||||
act := act
|
||||
|
||||
addr, err := address.NewFromString(a)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -239,7 +242,7 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
addresses[message.From] = address.Undef
|
||||
}
|
||||
|
||||
par(50, kmaparr(addresses), func(addr address.Address) {
|
||||
parmap.Par(50, parmap.KMapArr(addresses), func(addr address.Address) {
|
||||
raddr, err := api.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
@@ -268,7 +271,7 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
}
|
||||
}
|
||||
|
||||
par(50, kvmaparr(miners), func(it func() (minerKey, *minerInfo)) {
|
||||
parmap.Par(50, parmap.KVMapArr(miners), func(it func() (minerKey, *minerInfo)) {
|
||||
k, info := it()
|
||||
|
||||
pow, err := api.StateMinerPower(ctx, k.addr, types.EmptyTSK)
|
||||
@@ -386,7 +389,7 @@ func fetchMessages(ctx context.Context, api api.FullNode, toSync map[cid.Cid]*ty
|
||||
messages := map[cid.Cid]*types.Message{}
|
||||
inclusions := map[cid.Cid][]cid.Cid{} // block -> msgs
|
||||
|
||||
par(50, maparr(toSync), func(header *types.BlockHeader) {
|
||||
parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) {
|
||||
msgs, err := api.ChainGetBlockMessages(ctx, header.Cid())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -423,7 +426,7 @@ func fetchParentReceipts(ctx context.Context, api api.FullNode, toSync map[cid.C
|
||||
var lk sync.Mutex
|
||||
out := map[mrec]*types.MessageReceipt{}
|
||||
|
||||
par(50, maparr(toSync), func(header *types.BlockHeader) {
|
||||
parmap.Par(50, parmap.MapArr(toSync), func(header *types.BlockHeader) {
|
||||
recs, err := api.ChainGetParentReceipts(ctx, header.Cid())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
||||
+11
-11
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
@@ -46,7 +46,7 @@ func main() {
|
||||
app := &cli.App{
|
||||
Name: "lotus-fountain",
|
||||
Usage: "Devnet token distribution utility",
|
||||
Version: build.UserVersion,
|
||||
Version: build.UserVersion(),
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
@@ -157,7 +157,7 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) {
|
||||
to, err := address.NewFromString(r.FormValue("address"))
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -204,25 +204,25 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(smsg.Cid().String()))
|
||||
_, _ = w.Write([]byte(smsg.Cid().String()))
|
||||
}
|
||||
|
||||
func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
owner, err := address.NewFromString(r.FormValue("address"))
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
_, _ = w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if owner.Protocol() != address.BLS {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("Miner address must use BLS. A BLS address starts with the prefix 't3'."))
|
||||
w.Write([]byte("Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node."))
|
||||
_, _ = w.Write([]byte("Miner address must use BLS. A BLS address starts with the prefix 't3'."))
|
||||
_, _ = w.Write([]byte("Please create a BLS address by running \"lotus wallet new bls\" while connected to a Lotus node."))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
Owner: owner,
|
||||
Worker: owner,
|
||||
SealProofType: spt,
|
||||
Peer: h.defaultMinerPeer,
|
||||
Peer: abi.PeerID(h.defaultMinerPeer),
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
@@ -334,7 +334,7 @@ func (h *handler) msgwait(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
mw, err := h.api.StateWaitMsg(r.Context(), c)
|
||||
mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
@@ -357,7 +357,7 @@ func (h *handler) msgwaitaddr(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
mw, err := h.api.StateWaitMsg(r.Context(), c)
|
||||
mw, err := h.api.StateWaitMsg(r.Context(), c, build.MessageConfidence)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
</div>
|
||||
<div class="Index-node" id="formnd">
|
||||
<form id="f" action='/mkminer' method='POST'>
|
||||
<span>Enter destination address:</span>
|
||||
<input type='text' name='address' style="width: 300px">
|
||||
<span>Enter owner/worker address:</span>
|
||||
<input type='text' name='address' style="width: 300px" placeholder="t3...">
|
||||
<select name="sectorSize">
|
||||
<option selected value="536870912">512MiB sectors</option>
|
||||
<option value="34359738368">32GiB sectors</option>
|
||||
<option selected value="34359738368">32GiB sectors</option>
|
||||
<option value="68719476736">64GiB sectors</option>
|
||||
</select>
|
||||
<button type='submit'>Create Miner</button>
|
||||
@@ -28,6 +27,9 @@
|
||||
<div class="Index-node">
|
||||
<span>When creating storage miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min.</span>
|
||||
</div>
|
||||
<div class="Index-node">
|
||||
<span>If you don't have an owner/worker address, you can create it by following <a target="_blank" href="https://docs.lotu.sh/en+mining#get-started-22083">these instructions</a>.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Index-footer">
|
||||
<div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user