Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ad725a04c | ||
|
|
a898b18fd6 | ||
|
|
0fa362cc23 | ||
|
|
61401e5e82 | ||
|
|
6afeb2e72b | ||
|
|
b5d50f2b52 | ||
|
|
7e0be91cfd | ||
|
|
4f6ec225cf | ||
|
|
b2a0ad68dd | ||
|
|
60970008c8 | ||
|
|
4750f32ab6 | ||
|
|
1c9072bf6e | ||
|
|
656c022ed6 | ||
|
|
4d5af19b9d | ||
|
|
fc227561ba | ||
|
|
ca0bed47c4 | ||
|
|
4f4f18482a | ||
|
|
1dafcf24f1 | ||
|
|
d6cf76a91a | ||
|
|
a34537ae9f | ||
|
|
85c7864f78 | ||
|
|
f24d947388 | ||
|
|
78c0c9b21a | ||
|
|
6bf87e28e9 | ||
|
|
49167cc55f | ||
|
|
a2b6aa8e67 | ||
|
|
c7ffaad763 | ||
|
|
14580b6144 | ||
|
|
5c3ed4d91a | ||
|
|
243b295559 | ||
|
|
0661a1bbfc | ||
|
|
5133ff16ba | ||
|
|
201eb3bab8 | ||
|
|
c4b790a910 | ||
|
|
dbcf2c3cf5 | ||
|
|
a9cb1d6543 | ||
|
|
e326a444b1 | ||
|
|
bc15d5234e | ||
|
|
05c262eb9f | ||
|
|
1e1668e949 | ||
|
|
352fb9f9ea | ||
|
|
fc46938383 | ||
|
|
0309e2332c | ||
|
|
17c3d158d2 | ||
|
|
d4338047af | ||
|
|
44c1e3a347 | ||
|
|
709fd12b7f | ||
|
|
21a603ed8f | ||
|
|
85f91a1114 | ||
|
|
e7a1be4dde | ||
|
|
e9470d873e | ||
|
|
cf8e90fa3e | ||
|
|
62146b7bb3 | ||
|
|
575e962d16 | ||
|
|
70da3e124a | ||
|
|
4bd6d7be1a | ||
|
|
63af9f2a9e | ||
|
|
1a9c775407 | ||
|
|
955b86deea | ||
|
|
6eb342b8ee | ||
|
|
5bc1cb2aa3 | ||
|
|
cb05001e5a | ||
|
|
ad9e4db3d6 | ||
|
|
5e6ab42cb8 | ||
|
|
63ee6b6791 | ||
|
|
f837cb5513 | ||
|
|
b7ff44485a | ||
|
|
9935e3acfc | ||
|
|
90ecfbe0e4 | ||
|
|
0ca349033d | ||
|
|
5cc089be12 | ||
|
|
a8d18c8ac9 | ||
|
|
cc0635335c | ||
|
|
65d8769002 | ||
|
|
d8f5330c29 | ||
|
|
ea2f53745e | ||
|
|
c9bd682c33 | ||
|
|
04c8bca073 | ||
|
|
7f1335a8dd | ||
|
|
ff77198a08 | ||
|
|
8da64d710e | ||
|
|
e453a38865 | ||
|
|
ce7be477ce | ||
|
|
01b6ddbbd3 | ||
|
|
37929ff75f | ||
|
|
b6ba0ed47c | ||
|
|
87f7315f5a | ||
|
|
1b6ad6d2a1 | ||
|
|
a62572bb76 | ||
|
|
f752770a47 | ||
|
|
d117cb61b6 | ||
|
|
c071b2dc47 | ||
|
|
d70ebd2ba5 | ||
|
|
cda7f08b76 | ||
|
|
19a65319ee | ||
|
|
7402b14df3 | ||
|
|
0622eb7634 | ||
|
|
95f344540e | ||
|
|
ee9060aa14 | ||
|
|
c6fd45727d | ||
|
|
cd27f5a4bc | ||
|
|
8ad8fa902d | ||
|
|
7861b5e6cb | ||
|
|
70aaa8fc92 | ||
|
|
e441b48ea7 | ||
|
|
6ed57ede6a | ||
|
|
aefc463586 | ||
|
|
f2340579a5 | ||
|
|
de5577ca70 | ||
|
|
316b11445e | ||
|
|
b42e481600 | ||
|
|
e5a48800ab | ||
|
|
db50d01db9 | ||
|
|
cec2085790 | ||
|
|
75ee71e35a | ||
|
|
7f9a3ac584 | ||
|
|
1e9f293994 | ||
|
|
b5f9a385ae | ||
|
|
f1114d3852 | ||
|
|
d27187b1de | ||
|
|
4aaa758543 | ||
|
|
03f07042ff | ||
|
|
bcbfc931ba | ||
|
|
e2b2026fa5 | ||
|
|
4b8b79dbe0 | ||
|
|
9e5cc46638 | ||
|
|
ba542cf67a | ||
|
|
3f58ffe572 | ||
|
|
25f544f3db | ||
|
|
df747c8216 | ||
|
|
53da298c4f | ||
|
|
73c7f40ce3 | ||
|
|
66bfadb71a | ||
|
|
5af64c53b6 | ||
|
|
b60860456d | ||
|
|
095a309aef | ||
|
|
834383b7e5 | ||
|
|
1cdf29244c | ||
|
|
cb665caf9e | ||
|
|
eb4b85aea5 | ||
|
|
9c6c5aef5d | ||
|
|
050d552b9d | ||
|
|
cf86bc6e23 | ||
|
|
af61dfd8cd | ||
|
|
2a2a18a163 | ||
|
|
29f3d6aa28 | ||
|
|
4379ff60f6 | ||
|
|
a55a37c17b | ||
|
|
5532093d58 | ||
|
|
752be27815 | ||
|
|
80903e86fa | ||
|
|
dc076c6441 | ||
|
|
c6e63db7b4 | ||
|
|
dff6e87ce9 | ||
|
|
c765289da9 | ||
|
|
2841edfb96 | ||
|
|
c9c437cb3b | ||
|
|
c0e317f829 | ||
|
|
63a5124f57 | ||
|
|
eda726ec34 | ||
|
|
bab23aa7b1 | ||
|
|
7b258eddc4 | ||
|
|
3bf0bd6ce9 | ||
|
|
0ed981be19 | ||
|
|
77113844a2 | ||
|
|
9da4296e21 | ||
|
|
9fc5f0cd9d | ||
|
|
2f2e7be12a | ||
|
|
9892bf4379 | ||
|
|
351a683812 | ||
|
|
445b7f3388 | ||
|
|
9e95372e5d | ||
|
|
b5660b58b3 | ||
|
|
b472ea371a | ||
|
|
6703bd2c71 | ||
|
|
36388de4e1 | ||
|
|
10159ba1bb | ||
|
|
792a2cad82 | ||
|
|
7f1b12d29e | ||
|
|
23b46a05f7 | ||
|
|
cd14a5eb40 | ||
|
|
2256e62648 | ||
|
|
6b42a78c3f | ||
|
|
6b2b22782b | ||
|
|
de52d3cadd | ||
|
|
7e43c40529 | ||
|
|
df9dfa9d0c | ||
|
|
08a2e0f82c | ||
|
|
01dc9c767e | ||
|
|
67b441838b | ||
|
|
94f2948020 | ||
|
|
f5540195de | ||
|
|
558e4c7669 | ||
|
|
c3a5da8586 | ||
|
|
02c8ab7839 | ||
|
|
8414569428 | ||
|
|
bd97eb98c5 | ||
|
|
e67fbda305 | ||
|
|
26e6bc32ee | ||
|
|
11a6bff416 | ||
|
|
e67ee227a3 | ||
|
|
f8ec1d9d22 | ||
|
|
7fb3360d6f | ||
|
|
cb35625a53 | ||
|
|
26870501a7 | ||
|
|
f5d061f34f | ||
|
|
362fbbf913 | ||
|
|
f8d5f610b6 | ||
|
|
e43174f2af | ||
|
|
16523c2ef9 | ||
|
|
d3a9006272 | ||
|
|
a404d535ee | ||
|
|
dcd01df2d3 | ||
|
|
ba5a5d1248 | ||
|
|
052b090bbf | ||
|
|
4654d9c192 | ||
|
|
1e877eae86 | ||
|
|
3c934ea21f | ||
|
|
52718e514c | ||
|
|
4310cc23ce | ||
|
|
bfb1cc6379 | ||
|
|
cbfc675f4f | ||
|
|
e7b5d678a9 | ||
|
|
effacec817 | ||
|
|
3a89388039 | ||
|
|
3366c02a36 | ||
|
|
a26cc96a49 | ||
|
|
6d9ac84359 | ||
|
|
882507e915 | ||
|
|
08e1b52281 | ||
|
|
cf153f89df | ||
|
|
d2401bc339 | ||
|
|
fd0bfc8777 | ||
|
|
7b295d7bb0 | ||
|
|
b6563ffc29 | ||
|
|
2594ff6233 | ||
|
|
807d803a81 | ||
|
|
2076cb106d | ||
|
|
5b304fa20a | ||
|
|
fbc0330fa8 | ||
|
|
f5bfaff003 | ||
|
|
eac17a8328 | ||
|
|
f9c9316990 | ||
|
|
d9f5f6e2c6 | ||
|
|
955b755055 | ||
|
|
0c6e4c6c40 | ||
|
|
57812fc61d | ||
|
|
62f05d4c14 | ||
|
|
e4de5c55ac | ||
|
|
efaf2c720b | ||
|
|
d1f419c9d1 | ||
|
|
c5ece2a892 | ||
|
|
7712d97270 | ||
|
|
8e90d5fb17 | ||
|
|
b2fcca87ff | ||
|
|
a46a9bb42e | ||
|
|
62d661f898 | ||
|
|
4436148fa1 | ||
|
|
3886e050b0 | ||
|
|
ff4b0c8f5d | ||
|
|
f82ee0a2a7 | ||
|
|
b5d603dd46 | ||
|
|
0b8ae006d3 | ||
|
|
55fd0a4e60 | ||
|
|
3c4acbc6cb | ||
|
|
8224aab851 | ||
|
|
28604f5a4c | ||
|
|
533081454a | ||
|
|
e94e64652b | ||
|
|
489ecef47b | ||
|
|
8b42ca76f8 | ||
|
|
be2d138aac | ||
|
|
1e782b3de2 | ||
|
|
8bd62165f5 | ||
|
|
ae8a9a93bf | ||
|
|
f7ab2103ce | ||
|
|
c3d5a9848b | ||
|
|
6d6d82a304 | ||
|
|
bc83c0221b | ||
|
|
c6bf252a21 | ||
|
|
f9ea6969c3 | ||
|
|
9e956ff9f4 | ||
|
|
0a45e97699 | ||
|
|
3962d4204b | ||
|
|
fd76216652 | ||
|
|
2a7dcb6e17 | ||
|
|
b02eaee0d4 | ||
|
|
6ccf24ce6c | ||
|
|
c6186a03f1 | ||
|
|
ee4f503e10 | ||
|
|
0c227e89b2 | ||
|
|
128933a655 | ||
|
|
055b215bc7 | ||
|
|
611dd77442 | ||
|
|
fb173c058e | ||
|
|
2edb32979f | ||
|
|
e3bed8d12a | ||
|
|
84de47377c | ||
|
|
06c99d0e18 | ||
|
|
0aebec6697 | ||
|
|
d4c50b8ea0 | ||
|
|
cc424d64fe | ||
|
|
48ea36d37f | ||
|
|
ffdd436b52 | ||
|
|
ec9286eb4b | ||
|
|
68f8d60323 | ||
|
|
5cabb068c0 | ||
|
|
01079b0815 | ||
|
|
7e15aa243e | ||
|
|
e9ca6c0871 | ||
|
|
604bf64ef6 | ||
|
|
925e057acb | ||
|
|
c47e96ca45 | ||
|
|
6354a8ce03 | ||
|
|
85ec972abb | ||
|
|
a8d38ad82f | ||
|
|
be6badc6a5 | ||
|
|
cf9275a2a2 | ||
|
|
66f707c243 | ||
|
|
1163e46622 | ||
|
|
08b99ff413 | ||
|
|
23472aa4f2 | ||
|
|
05edf50931 | ||
|
|
a8e39962d0 | ||
|
|
5a42bb166e | ||
|
|
3953227702 | ||
|
|
d8d8ce7526 | ||
|
|
458acbf33d | ||
|
|
8a9707788c | ||
|
|
2fecf3a8f1 | ||
|
|
2ef8c1ae0c | ||
|
|
2fea9433d8 | ||
|
|
e06c19b51c | ||
|
|
34abc3d023 | ||
|
|
f6d41ee77d | ||
|
|
da2a11ed76 | ||
|
|
86f078dbea | ||
|
|
f739b7e377 |
+94
-5
@@ -7,6 +7,9 @@ executors:
|
||||
docker:
|
||||
- image: circleci/golang:1.13
|
||||
resource_class: 2xlarge
|
||||
ubuntu:
|
||||
docker:
|
||||
- image: ubuntu:19.10
|
||||
|
||||
commands:
|
||||
install-deps:
|
||||
@@ -24,6 +27,8 @@ commands:
|
||||
description: is a darwin build environment?
|
||||
type: boolean
|
||||
steps:
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- checkout
|
||||
- when:
|
||||
condition: << parameters.linux >>
|
||||
@@ -46,7 +51,27 @@ commands:
|
||||
key: 'v20-1k-lotus-params'
|
||||
paths:
|
||||
- /var/tmp/filecoin-proof-parameters/
|
||||
|
||||
install_ipfs:
|
||||
steps:
|
||||
- run: |
|
||||
apt update
|
||||
apt install -y wget
|
||||
wget https://github.com/ipfs/go-ipfs/releases/download/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz
|
||||
wget https://github.com/ipfs/go-ipfs/releases/download/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz.sha512
|
||||
if [ "$(sha512sum go-ipfs_v0.4.22_linux-amd64.tar.gz)" != "$(cat go-ipfs_v0.4.22_linux-amd64.tar.gz.sha512)" ]
|
||||
then
|
||||
echo "ipfs failed checksum check"
|
||||
exit 1
|
||||
fi
|
||||
tar -xf go-ipfs_v0.4.22_linux-amd64.tar.gz
|
||||
mv go-ipfs/ipfs /usr/local/bin/ipfs
|
||||
chmod +x /usr/local/bin/ipfs
|
||||
git_fetch_all_tags:
|
||||
steps:
|
||||
- run:
|
||||
name: fetch all tags
|
||||
command: |
|
||||
git fetch --all
|
||||
|
||||
jobs:
|
||||
mod-tidy-check:
|
||||
@@ -74,6 +99,13 @@ jobs:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir linux && mv lotus lotus-storage-miner lotus-seal-worker linux/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
- linux
|
||||
|
||||
test: &test
|
||||
description: |
|
||||
@@ -153,7 +185,7 @@ jobs:
|
||||
- "~/go/src/github.com"
|
||||
- "~/go/src/golang.org"
|
||||
|
||||
test-short:
|
||||
test-short:
|
||||
<<: *test
|
||||
|
||||
build-macos:
|
||||
@@ -196,6 +228,13 @@ jobs:
|
||||
path: lotus
|
||||
- store_artifacts:
|
||||
path: lotus-storage-miner
|
||||
- store_artifacts:
|
||||
path: lotus-seal-worker
|
||||
- run: mkdir darwin && mv lotus lotus-storage-miner lotus-seal-worker darwin/
|
||||
- persist_to_workspace:
|
||||
root: "."
|
||||
paths:
|
||||
- darwin
|
||||
- save_cache:
|
||||
name: save cargo cache
|
||||
key: v3-go-deps-{{ arch }}-{{ checksum "~/go/src/github.com/filecoin-project/lotus/go.sum" }}
|
||||
@@ -246,6 +285,26 @@ jobs:
|
||||
lint-all:
|
||||
<<: *lint
|
||||
|
||||
publish:
|
||||
description: publish binary artifacts
|
||||
executor: ubuntu
|
||||
steps:
|
||||
- run:
|
||||
name: Install git jq curl
|
||||
command: apt update && apt install -y git jq curl
|
||||
- checkout
|
||||
- git_fetch_all_tags
|
||||
- checkout
|
||||
- install_ipfs
|
||||
- attach_workspace:
|
||||
at: "."
|
||||
- run:
|
||||
name: Create bundles
|
||||
command: ./scripts/build-bundle.sh
|
||||
- run:
|
||||
name: Publish release
|
||||
command: ./scripts/publish-release.sh
|
||||
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
@@ -255,8 +314,38 @@ workflows:
|
||||
args: "--new-from-rev origin/master"
|
||||
- test:
|
||||
codecov-upload: true
|
||||
- mod-tidy-check
|
||||
- test-short:
|
||||
go-test-flags: "--timeout 10m --short"
|
||||
- mod-tidy-check
|
||||
- build-all
|
||||
- build-macos
|
||||
filters:
|
||||
tags:
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
- build-all:
|
||||
requires:
|
||||
- test-short
|
||||
filters:
|
||||
tags:
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
- build-macos:
|
||||
requires:
|
||||
- test-short
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- /.*/
|
||||
tags:
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
- publish:
|
||||
requires:
|
||||
- build-all
|
||||
- build-macos
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- /.*/
|
||||
tags:
|
||||
only:
|
||||
- /^v\d+\.\d+\.\d+$/
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
.gitignore
|
||||
@@ -2,6 +2,7 @@
|
||||
/lotus-storage-miner
|
||||
/lotus-seal-worker
|
||||
/lotus-seed
|
||||
/lotus-health
|
||||
/pond
|
||||
/townhall
|
||||
/fountain
|
||||
@@ -25,6 +26,9 @@ build/paramfetch.sh
|
||||
/blocks.svg
|
||||
/chainwatch
|
||||
/chainwatch.db
|
||||
/bundle
|
||||
/darwin
|
||||
/linux
|
||||
|
||||
*-fuzz.zip
|
||||
/chain/types/work_msg/
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- vet
|
||||
- gofmt
|
||||
- govet
|
||||
- goimports
|
||||
- misspell
|
||||
- goconst
|
||||
|
||||
@@ -14,7 +14,7 @@ MODULES:=
|
||||
|
||||
CLEAN:=
|
||||
BINS:=
|
||||
GOFLAGS+=-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))"
|
||||
GOFLAGS+=-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))"
|
||||
|
||||
## FFI
|
||||
|
||||
@@ -124,7 +124,7 @@ BINS+=townhall
|
||||
fountain:
|
||||
rm -f fountain
|
||||
go build -o fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: fountain
|
||||
BINS+=fountain
|
||||
|
||||
@@ -149,6 +149,14 @@ stats:
|
||||
.PHONY: stats
|
||||
BINS+=stats
|
||||
|
||||
health:
|
||||
rm -f lotus-health
|
||||
go build -o lotus-health ./cmd/lotus-health
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-health -i ./build
|
||||
|
||||
.PHONY: health
|
||||
BINS+=health
|
||||
|
||||
# MISC
|
||||
|
||||
buildall: $(BINS)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Project Lotus - 莲
|
||||
|
||||
Lotus is an experimental implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
||||
Lotus is an implementation of the Filecoin Distributed Storage Network. For more details about Filecoin, check out the [Filecoin Spec](https://github.com/filecoin-project/specs).
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ type Common interface {
|
||||
|
||||
// Version provides information about API provider
|
||||
Version(context.Context) (Version, error)
|
||||
|
||||
LogList(context.Context) ([]string, error)
|
||||
LogSetLevel(context.Context, string, string) error
|
||||
}
|
||||
|
||||
// Version provides various build-time information
|
||||
|
||||
+41
-28
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -30,22 +30,26 @@ type FullNode interface {
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
|
||||
ChainGetParentReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
|
||||
ChainGetParentMessages(context.Context, cid.Cid) ([]Message, error)
|
||||
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
ChainSetHead(context.Context, *types.TipSet) error
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
ChainSetHead(context.Context, types.TipSetKey) error
|
||||
ChainGetGenesis(context.Context) (*types.TipSet, error)
|
||||
ChainTipSetWeight(context.Context, *types.TipSet) (types.BigInt, error)
|
||||
ChainTipSetWeight(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
ChainGetNode(ctx context.Context, p string) (interface{}, error)
|
||||
ChainGetMessage(context.Context, cid.Cid) (*types.Message, error)
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*store.HeadChange, error)
|
||||
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, error)
|
||||
|
||||
// syncer
|
||||
SyncState(context.Context) (*SyncState, error)
|
||||
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
|
||||
MpoolPending(context.Context, *types.TipSet) ([]*types.SignedMessage, error)
|
||||
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
|
||||
MpoolGetNonce(context.Context, address.Address) (uint64, error)
|
||||
@@ -55,7 +59,7 @@ type FullNode interface {
|
||||
|
||||
// miner
|
||||
|
||||
MinerCreateBlock(context.Context, address.Address, *types.TipSet, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error)
|
||||
MinerCreateBlock(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error)
|
||||
|
||||
// // UX ?
|
||||
|
||||
@@ -93,31 +97,35 @@ type FullNode interface {
|
||||
//ClientListAsks() []Ask
|
||||
|
||||
// if tipset is nil, we'll use heaviest
|
||||
StateCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
|
||||
StateReplay(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error)
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
|
||||
StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
|
||||
StateListMessages(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error)
|
||||
StateCall(context.Context, *types.Message, types.TipSetKey) (*MethodCall, error)
|
||||
StateReplay(context.Context, types.TipSetKey, cid.Cid) (*ReplayResults, error)
|
||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*ActorState, error)
|
||||
StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error)
|
||||
|
||||
StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*ChainSectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*ChainSectorInfo, error)
|
||||
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error)
|
||||
StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
|
||||
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
|
||||
StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error)
|
||||
StateMinerSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error)
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (MinerPower, error)
|
||||
StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
StateMinerPeerID(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error)
|
||||
StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error)
|
||||
StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (uint64, error)
|
||||
StateMinerFaults(context.Context, address.Address, types.TipSetKey) ([]uint64, error)
|
||||
StatePledgeCollateral(context.Context, types.TipSetKey) (types.BigInt, error)
|
||||
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
|
||||
StateListMiners(context.Context, *types.TipSet) ([]address.Address, error)
|
||||
StateListActors(context.Context, *types.TipSet) ([]address.Address, error)
|
||||
StateMarketBalance(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error)
|
||||
StateMarketParticipants(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error)
|
||||
StateMarketDeals(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error)
|
||||
StateMarketStorageDeal(context.Context, uint64, *types.TipSet) (*actors.OnChainDeal, error)
|
||||
StateLookupID(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
StateListActors(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
StateMarketBalance(context.Context, address.Address, types.TipSetKey) (actors.StorageParticipantBalance, error)
|
||||
StateMarketParticipants(context.Context, types.TipSetKey) (map[string]actors.StorageParticipantBalance, error)
|
||||
StateMarketDeals(context.Context, types.TipSetKey) (map[string]actors.OnChainDeal, error)
|
||||
StateMarketStorageDeal(context.Context, uint64, types.TipSetKey) (*actors.OnChainDeal, error)
|
||||
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error)
|
||||
StateMinerSectorCount(context.Context, address.Address, *types.TipSet) (MinerSectors, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
||||
StateMinerSectorCount(context.Context, address.Address, types.TipSetKey) (MinerSectors, error)
|
||||
StateCompute(context.Context, uint64, []*types.Message, types.TipSetKey) (cid.Cid, error)
|
||||
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, types.BigInt) error
|
||||
// MarketFreeBalance
|
||||
@@ -268,6 +276,11 @@ type ReplayResults struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
type MethodCall struct {
|
||||
types.MessageReceipt
|
||||
Error string
|
||||
}
|
||||
|
||||
type ActiveSync struct {
|
||||
Base *types.TipSet
|
||||
Target *types.TipSet
|
||||
|
||||
+17
-4
@@ -19,14 +19,14 @@ const (
|
||||
|
||||
Unsealed // sealing / queued
|
||||
PreCommitting // on chain pre-commit
|
||||
PreCommitted // waiting for seed
|
||||
WaitSeed // waiting for seed
|
||||
Committing
|
||||
CommitWait // waiting for message to land on chain
|
||||
FinalizeSector
|
||||
Proving
|
||||
_ // reserved
|
||||
_
|
||||
_
|
||||
_
|
||||
|
||||
// recovery handling
|
||||
// Reseal
|
||||
@@ -45,7 +45,7 @@ const (
|
||||
PreCommitFailed
|
||||
SealCommitFailed
|
||||
CommitFailed
|
||||
_
|
||||
PackingFailed
|
||||
_
|
||||
_
|
||||
_
|
||||
@@ -61,15 +61,17 @@ var SectorStates = []string{
|
||||
Packing: "Packing",
|
||||
Unsealed: "Unsealed",
|
||||
PreCommitting: "PreCommitting",
|
||||
PreCommitted: "PreCommitted",
|
||||
WaitSeed: "WaitSeed",
|
||||
Committing: "Committing",
|
||||
CommitWait: "CommitWait",
|
||||
FinalizeSector: "FinalizeSector",
|
||||
Proving: "Proving",
|
||||
|
||||
SealFailed: "SealFailed",
|
||||
PreCommitFailed: "PreCommitFailed",
|
||||
SealCommitFailed: "SealCommitFailed",
|
||||
CommitFailed: "CommitFailed",
|
||||
PackingFailed: "PackingFailed",
|
||||
|
||||
FailedUnrecoverable: "FailedUnrecoverable",
|
||||
|
||||
@@ -107,6 +109,15 @@ type StorageMiner interface {
|
||||
WorkerDone(ctx context.Context, task uint64, res sectorbuilder.SealRes) error
|
||||
}
|
||||
|
||||
type SectorLog struct {
|
||||
Kind string
|
||||
Timestamp uint64
|
||||
|
||||
Trace string
|
||||
|
||||
Message string
|
||||
}
|
||||
|
||||
type SectorInfo struct {
|
||||
SectorID uint64
|
||||
State SectorState
|
||||
@@ -119,6 +130,8 @@ type SectorInfo struct {
|
||||
Retries uint64
|
||||
|
||||
LastErr string
|
||||
|
||||
Log []SectorLog
|
||||
}
|
||||
|
||||
type SealedRef struct {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package apibstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type ChainIO interface {
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
}
|
||||
|
||||
type apiBStore struct {
|
||||
api ChainIO
|
||||
}
|
||||
|
||||
func (a *apiBStore) DeleteBlock(cid.Cid) error {
|
||||
return xerrors.New("not supported")
|
||||
}
|
||||
|
||||
func (a *apiBStore) Has(c cid.Cid) (bool, error) {
|
||||
return a.api.ChainHasObj(context.TODO(), c)
|
||||
}
|
||||
|
||||
func (a *apiBStore) Get(c cid.Cid) (blocks.Block, error) {
|
||||
bb, err := a.api.ChainReadObj(context.TODO(), c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.NewBlockWithCid(bb, c)
|
||||
}
|
||||
|
||||
func (a *apiBStore) GetSize(c cid.Cid) (int, error) {
|
||||
bb, err := a.api.ChainReadObj(context.TODO(), c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(bb), nil
|
||||
}
|
||||
|
||||
func (a *apiBStore) Put(blocks.Block) error {
|
||||
return xerrors.New("not supported")
|
||||
}
|
||||
|
||||
func (a *apiBStore) PutMany([]blocks.Block) error {
|
||||
return xerrors.New("not supported")
|
||||
}
|
||||
|
||||
func (a *apiBStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
return nil, xerrors.New("not supported")
|
||||
}
|
||||
|
||||
func (a *apiBStore) HashOnRead(enabled bool) {
|
||||
return
|
||||
}
|
||||
|
||||
var _ blockstore.Blockstore = &apiBStore{}
|
||||
+139
-92
@@ -32,6 +32,9 @@ type CommonStruct struct {
|
||||
|
||||
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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,34 +43,38 @@ type FullNodeStruct struct {
|
||||
CommonStruct
|
||||
|
||||
Internal struct {
|
||||
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
|
||||
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetRandomness func(context.Context, types.TipSetKey, int64) ([]byte, error) `perm:"read"`
|
||||
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
|
||||
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
|
||||
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
|
||||
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
ChainGetTipSetByHeight func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) `perm:"read"`
|
||||
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
|
||||
ChainSetHead func(context.Context, *types.TipSet) error `perm:"admin"`
|
||||
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainTipSetWeight func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
||||
ChainGetNode func(ctx context.Context, p string) (interface{}, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainNotify func(context.Context) (<-chan []*store.HeadChange, error) `perm:"read"`
|
||||
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetRandomness func(context.Context, types.TipSetKey, int64) ([]byte, error) `perm:"read"`
|
||||
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
|
||||
ChainGetTipSet func(context.Context, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainGetBlockMessages func(context.Context, cid.Cid) (*api.BlockMessages, error) `perm:"read"`
|
||||
ChainGetParentReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
|
||||
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
ChainGetTipSetByHeight func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
|
||||
ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"`
|
||||
ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"`
|
||||
ChainGetGenesis func(context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
ChainTipSetWeight func(context.Context, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
ChainGetNode func(ctx context.Context, p string) (interface{}, error) `perm:"read"`
|
||||
ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*store.HeadChange, error) `perm:"read"`
|
||||
ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, error) `perm:"read"`
|
||||
|
||||
SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
|
||||
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
|
||||
SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"`
|
||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||
|
||||
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPushMessage func(context.Context, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
|
||||
|
||||
MinerCreateBlock func(context.Context, address.Address, *types.TipSet, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error) `perm:"write"`
|
||||
MinerCreateBlock func(context.Context, address.Address, types.TipSetKey, *types.Ticket, *types.EPostProof, []*types.SignedMessage, uint64, uint64) (*types.BlockMsg, error) `perm:"write"`
|
||||
|
||||
WalletNew func(context.Context, string) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
@@ -90,30 +97,34 @@ type FullNodeStruct struct {
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, path string) error `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"`
|
||||
|
||||
StateMinerSectors func(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, *types.TipSet) (api.MinerPower, error) `perm:"read"`
|
||||
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
|
||||
StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"`
|
||||
StateMinerElectionPeriodStart func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
|
||||
StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
|
||||
StateReplay func(context.Context, *types.TipSet, cid.Cid) (*api.ReplayResults, error) `perm:"read"`
|
||||
StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
|
||||
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*api.ActorState, error) `perm:"read"`
|
||||
StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"`
|
||||
StateMinerSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerProvingSet func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"`
|
||||
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (api.MinerPower, error) `perm:"read"`
|
||||
StateMinerWorker func(context.Context, address.Address, types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateMinerPeerID func(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error) `perm:"read"`
|
||||
StateMinerElectionPeriodStart func(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) `perm:"read"`
|
||||
StateMinerSectorSize func(context.Context, address.Address, types.TipSetKey) (uint64, error) `perm:"read"`
|
||||
StateMinerFaults func(context.Context, address.Address, types.TipSetKey) ([]uint64, error) `perm:"read"`
|
||||
StateCall func(context.Context, *types.Message, types.TipSetKey) (*api.MethodCall, error) `perm:"read"`
|
||||
StateReplay func(context.Context, types.TipSetKey, cid.Cid) (*api.ReplayResults, 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.MsgWait, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
||||
StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"`
|
||||
StateMarketBalance func(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error) `perm:"read"`
|
||||
StateMarketParticipants func(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error) `perm:"read"`
|
||||
StateMarketDeals func(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error) `perm:"read"`
|
||||
StateMarketStorageDeal func(context.Context, uint64, *types.TipSet) (*actors.OnChainDeal, error) `perm:"read"`
|
||||
StateLookupID func(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, 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"`
|
||||
StateMarketBalance func(context.Context, address.Address, types.TipSetKey) (actors.StorageParticipantBalance, error) `perm:"read"`
|
||||
StateMarketParticipants func(context.Context, types.TipSetKey) (map[string]actors.StorageParticipantBalance, error) `perm:"read"`
|
||||
StateMarketDeals func(context.Context, types.TipSetKey) (map[string]actors.OnChainDeal, error) `perm:"read"`
|
||||
StateMarketStorageDeal func(context.Context, uint64, types.TipSetKey) (*actors.OnChainDeal, error) `perm:"read"`
|
||||
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateChangedActors func(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) `perm:"read"`
|
||||
StateGetReceipt func(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
|
||||
StateMinerSectorCount func(context.Context, address.Address, *types.TipSet) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error) `perm:"read"`
|
||||
StateGetReceipt func(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) `perm:"read"`
|
||||
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error) `perm:"read"`
|
||||
StateCompute func(context.Context, uint64, []*types.Message, types.TipSetKey) (cid.Cid, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, types.BigInt) error `perm:"sign"`
|
||||
|
||||
@@ -133,8 +144,8 @@ type FullNodeStruct struct {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectorCount(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MinerSectors, error) {
|
||||
return c.Internal.StateMinerSectorCount(ctx, addr, ts)
|
||||
func (c *FullNodeStruct) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) {
|
||||
return c.Internal.StateMinerSectorCount(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
type StorageMinerStruct struct {
|
||||
@@ -196,6 +207,14 @@ func (c *CommonStruct) Version(ctx context.Context) (api.Version, error) {
|
||||
return c.Internal.Version(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) LogList(ctx context.Context) ([]string, error) {
|
||||
return c.Internal.LogList(ctx)
|
||||
}
|
||||
|
||||
func (c *CommonStruct) LogSetLevel(ctx context.Context, group, level string) error {
|
||||
return c.Internal.LogSetLevel(ctx, group, level)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientListImports(ctx context.Context) ([]api.Import, error) {
|
||||
return c.Internal.ClientListImports(ctx)
|
||||
}
|
||||
@@ -231,8 +250,8 @@ func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner ad
|
||||
return c.Internal.ClientQueryAsk(ctx, p, miner)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPending(ctx context.Context, ts *types.TipSet) ([]*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx, ts)
|
||||
func (c *FullNodeStruct) MpoolPending(ctx context.Context, tsk types.TipSetKey) ([]*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPending(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
|
||||
@@ -247,7 +266,7 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
|
||||
return c.Internal.MpoolSub(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base *types.TipSet, ticket *types.Ticket, eproof *types.EPostProof, msgs []*types.SignedMessage, height, ts uint64) (*types.BlockMsg, error) {
|
||||
func (c *FullNodeStruct) MinerCreateBlock(ctx context.Context, addr address.Address, base types.TipSetKey, ticket *types.Ticket, eproof *types.EPostProof, msgs []*types.SignedMessage, height, ts uint64) (*types.BlockMsg, error) {
|
||||
return c.Internal.MinerCreateBlock(ctx, addr, base, ticket, eproof, msgs, height, ts)
|
||||
}
|
||||
|
||||
@@ -259,8 +278,8 @@ func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts types.TipSe
|
||||
return c.Internal.ChainGetRandomness(ctx, pts, round)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, ts *types.TipSet) (*types.TipSet, error) {
|
||||
return c.Internal.ChainGetTipSetByHeight(ctx, h, ts)
|
||||
func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h uint64, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ string) (address.Address, error) {
|
||||
@@ -335,16 +354,20 @@ func (c *FullNodeStruct) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte,
|
||||
return c.Internal.ChainReadObj(ctx, obj)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainSetHead(ctx context.Context, ts *types.TipSet) error {
|
||||
return c.Internal.ChainSetHead(ctx, ts)
|
||||
func (c *FullNodeStruct) ChainHasObj(ctx context.Context, o cid.Cid) (bool, error) {
|
||||
return c.Internal.ChainHasObj(ctx, o)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainSetHead(ctx context.Context, tsk types.TipSetKey) error {
|
||||
return c.Internal.ChainSetHead(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetGenesis(ctx context.Context) (*types.TipSet, error) {
|
||||
return c.Internal.ChainGetGenesis(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainTipSetWeight(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
return c.Internal.ChainTipSetWeight(ctx, ts)
|
||||
func (c *FullNodeStruct) ChainTipSetWeight(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.ChainTipSetWeight(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetNode(ctx context.Context, p string) (interface{}, error) {
|
||||
@@ -355,6 +378,14 @@ func (c *FullNodeStruct) ChainGetMessage(ctx context.Context, mc cid.Cid) (*type
|
||||
return c.Internal.ChainGetMessage(ctx, mc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*store.HeadChange, error) {
|
||||
return c.Internal.ChainGetPath(ctx, from, to)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainExport(ctx context.Context, tsk types.TipSetKey) (<-chan []byte, error) {
|
||||
return c.Internal.ChainExport(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncState(ctx context.Context) (*api.SyncState, error) {
|
||||
return c.Internal.SyncState(ctx)
|
||||
}
|
||||
@@ -371,95 +402,111 @@ func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error {
|
||||
return c.Internal.SyncMarkBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerSectors(ctx, addr, ts)
|
||||
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerProvingSet(ctx, addr, ts)
|
||||
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerSectors(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, ts *types.TipSet) (api.MinerPower, error) {
|
||||
return c.Internal.StateMinerPower(ctx, a, ts)
|
||||
func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
return c.Internal.StateMinerProvingSet(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return c.Internal.StateMinerWorker(ctx, m, ts)
|
||||
func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MinerPower, error) {
|
||||
return c.Internal.StateMinerPower(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) {
|
||||
return c.Internal.StateMinerPeerID(ctx, m, ts)
|
||||
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return c.Internal.StateMinerWorker(ctx, m, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
|
||||
return c.Internal.StateMinerElectionPeriodStart(ctx, actor, ts)
|
||||
func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, tsk types.TipSetKey) (peer.ID, error) {
|
||||
return c.Internal.StateMinerPeerID(ctx, m, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
|
||||
return c.Internal.StateMinerSectorSize(ctx, actor, ts)
|
||||
func (c *FullNodeStruct) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) {
|
||||
return c.Internal.StateMinerElectionPeriodStart(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||
return c.Internal.StateCall(ctx, msg, ts)
|
||||
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, tsk types.TipSetKey) (uint64, error) {
|
||||
return c.Internal.StateMinerSectorSize(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateReplay(ctx context.Context, ts *types.TipSet, mc cid.Cid) (*api.ReplayResults, error) {
|
||||
return c.Internal.StateReplay(ctx, ts, mc)
|
||||
func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) ([]uint64, error) {
|
||||
return c.Internal.StateMinerFaults(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
return c.Internal.StateGetActor(ctx, actor, ts)
|
||||
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.MethodCall, error) {
|
||||
return c.Internal.StateCall(ctx, msg, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*api.ActorState, error) {
|
||||
return c.Internal.StateReadState(ctx, act, ts)
|
||||
func (c *FullNodeStruct) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.ReplayResults, error) {
|
||||
return c.Internal.StateReplay(ctx, tsk, mc)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
||||
return c.Internal.StatePledgeCollateral(ctx, ts)
|
||||
func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||
return c.Internal.StateGetActor(ctx, actor, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||
return c.Internal.StateReadState(ctx, act, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StatePledgeCollateral(ctx context.Context, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.StatePledgeCollateral(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid) (*api.MsgWait, error) {
|
||||
return c.Internal.StateWaitMsg(ctx, msgc)
|
||||
}
|
||||
func (c *FullNodeStruct) StateListMiners(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
||||
return c.Internal.StateListMiners(ctx, ts)
|
||||
func (c *FullNodeStruct) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
|
||||
return c.Internal.StateListMiners(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateListActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
||||
return c.Internal.StateListActors(ctx, ts)
|
||||
func (c *FullNodeStruct) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
|
||||
return c.Internal.StateListActors(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) {
|
||||
return c.Internal.StateMarketBalance(ctx, addr, ts)
|
||||
func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (actors.StorageParticipantBalance, error) {
|
||||
return c.Internal.StateMarketBalance(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) {
|
||||
return c.Internal.StateMarketParticipants(ctx, ts)
|
||||
func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]actors.StorageParticipantBalance, error) {
|
||||
return c.Internal.StateMarketParticipants(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) {
|
||||
return c.Internal.StateMarketDeals(ctx, ts)
|
||||
func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (map[string]actors.OnChainDeal, error) {
|
||||
return c.Internal.StateMarketDeals(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateMarketStorageDeal(ctx context.Context, dealid uint64, ts *types.TipSet) (*actors.OnChainDeal, error) {
|
||||
return c.Internal.StateMarketStorageDeal(ctx, dealid, ts)
|
||||
func (c *FullNodeStruct) StateMarketStorageDeal(ctx context.Context, dealid uint64, tsk types.TipSetKey) (*actors.OnChainDeal, error) {
|
||||
return c.Internal.StateMarketStorageDeal(ctx, dealid, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateLookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return c.Internal.StateLookupID(ctx, addr, ts)
|
||||
func (c *FullNodeStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return c.Internal.StateLookupID(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateChangedActors(ctx context.Context, olnstate cid.Cid, newstate cid.Cid) (map[string]types.Actor, error) {
|
||||
return c.Internal.StateChangedActors(ctx, olnstate, newstate)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateGetReceipt(ctx context.Context, msg cid.Cid, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||
return c.Internal.StateGetReceipt(ctx, msg, ts)
|
||||
func (c *FullNodeStruct) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) {
|
||||
return c.Internal.StateGetReceipt(ctx, msg, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *types.Message, ts *types.TipSet, toht uint64) ([]cid.Cid, error) {
|
||||
return c.Internal.StateListMessages(ctx, match, ts, toht)
|
||||
func (c *FullNodeStruct) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht uint64) ([]cid.Cid, error) {
|
||||
return c.Internal.StateListMessages(ctx, match, tsk, toht)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCompute(ctx context.Context, height uint64, msgs []*types.Message, tsk types.TipSetKey) (cid.Cid, error) {
|
||||
return c.Internal.StateCompute(ctx, height, msgs, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr address.Address, amt types.BigInt) error {
|
||||
|
||||
+155
-186
@@ -98,114 +98,95 @@ func (t *PaymentInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("PaymentInfo: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
// t.Channel (address.Address) (struct)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
if name != "Channel" {
|
||||
return fmt.Errorf("expected struct map entry %s to be Channel", name)
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
if err := t.Channel.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
// t.ChannelMessage (cid.Cid) (struct)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
if name != "ChannelMessage" {
|
||||
return fmt.Errorf("expected struct map entry %s to be ChannelMessage", name)
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
pb, err := br.PeekByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pb == cbg.CborNull[0] {
|
||||
var nbuf [1]byte
|
||||
if _, err := br.Read(nbuf[:]); err != nil {
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// t.Channel (address.Address) (struct)
|
||||
case "Channel":
|
||||
|
||||
{
|
||||
|
||||
if err := t.Channel.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
// t.ChannelMessage (cid.Cid) (struct)
|
||||
case "ChannelMessage":
|
||||
|
||||
{
|
||||
|
||||
pb, err := br.PeekByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pb == cbg.CborNull[0] {
|
||||
var nbuf [1]byte
|
||||
if _, err := br.Read(nbuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err)
|
||||
}
|
||||
|
||||
t.ChannelMessage = &c
|
||||
}
|
||||
|
||||
}
|
||||
// t.Vouchers ([]*types.SignedVoucher) (slice)
|
||||
case "Vouchers":
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.ChannelMessage: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
t.ChannelMessage = &c
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Vouchers: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
if extra > 0 {
|
||||
t.Vouchers = make([]*types.SignedVoucher, extra)
|
||||
}
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.SignedVoucher
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Vouchers[i] = &v
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
|
||||
}
|
||||
|
||||
}
|
||||
// t.Vouchers ([]*types.SignedVoucher) (slice)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
if name != "Vouchers" {
|
||||
return fmt.Errorf("expected struct map entry %s to be Vouchers", name)
|
||||
}
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Vouchers: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
if extra > 0 {
|
||||
t.Vouchers = make([]*types.SignedVoucher, extra)
|
||||
}
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v types.SignedVoucher
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Vouchers[i] = &v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *SealedRef) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
@@ -276,84 +257,66 @@ func (t *SealedRef) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("SealedRef: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
// t.SectorID (uint64) (uint64)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
switch name {
|
||||
// t.SectorID (uint64) (uint64)
|
||||
case "SectorID":
|
||||
|
||||
if name != "SectorID" {
|
||||
return fmt.Errorf("expected struct map entry %s to be SectorID", name)
|
||||
}
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.SectorID = uint64(extra)
|
||||
// t.Offset (uint64) (uint64)
|
||||
case "Offset":
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.SectorID = uint64(extra)
|
||||
// t.Offset (uint64) (uint64)
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Offset = uint64(extra)
|
||||
// t.Size (uint64) (uint64)
|
||||
case "Size":
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Size = uint64(extra)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
if name != "Offset" {
|
||||
return fmt.Errorf("expected struct map entry %s to be Offset", name)
|
||||
}
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Offset = uint64(extra)
|
||||
// t.Size (uint64) (uint64)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
if name != "Size" {
|
||||
return fmt.Errorf("expected struct map entry %s to be Size", name)
|
||||
}
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Size = uint64(extra)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *SealedRefs) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
@@ -401,50 +364,56 @@ func (t *SealedRefs) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra != 1 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("SealedRefs: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
// t.Refs ([]api.SealedRef) (slice)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
{
|
||||
sval, err := cbg.ReadString(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
switch name {
|
||||
// t.Refs ([]api.SealedRef) (slice)
|
||||
case "Refs":
|
||||
|
||||
if name != "Refs" {
|
||||
return fmt.Errorf("expected struct map entry %s to be Refs", name)
|
||||
}
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maj, extra, err = cbg.CborReadHeader(br)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Refs: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Refs: array too large (%d)", extra)
|
||||
}
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
if extra > 0 {
|
||||
t.Refs = make([]SealedRef, extra)
|
||||
}
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
if extra > 0 {
|
||||
t.Refs = make([]SealedRef, extra)
|
||||
}
|
||||
for i := 0; i < int(extra); i++ {
|
||||
var v SealedRef
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var v SealedRef
|
||||
if err := v.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
t.Refs[i] = v
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown struct field %d: '%s'", i, name)
|
||||
}
|
||||
|
||||
t.Refs[i] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -65,7 +65,6 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
defer close(done)
|
||||
for mine {
|
||||
time.Sleep(blocktime)
|
||||
fmt.Println("mining a block now")
|
||||
if err := sn[0].MineOne(ctx); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
+7
-1
@@ -1,3 +1,9 @@
|
||||
package build
|
||||
|
||||
// No forks yet \o/
|
||||
const ForkBlizzardHeight = 6288
|
||||
|
||||
const ForkFrigidHeight = 7950
|
||||
|
||||
const ForkBootyBayHeight = 11000
|
||||
|
||||
const ForkMissingSnowballs = 34000
|
||||
|
||||
+3
-1
@@ -2,4 +2,6 @@ package build
|
||||
|
||||
import rice "github.com/GeertJohan/go.rice"
|
||||
|
||||
var ParametersJson = rice.MustFindBox("proof-params").MustBytes("parameters.json")
|
||||
func ParametersJson() []byte {
|
||||
return rice.MustFindBox("proof-params").MustBytes("parameters.json")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
package build
|
||||
|
||||
import "os"
|
||||
func init() {
|
||||
InsecurePoStValidation = true
|
||||
}
|
||||
|
||||
var SectorSizes = []uint64{1024}
|
||||
|
||||
@@ -31,7 +33,3 @@ const InteractivePoRepConfidence = 6
|
||||
|
||||
// Bytes
|
||||
var MinimumMinerPower uint64 = 2 << 10 // 2KiB
|
||||
|
||||
func init() {
|
||||
os.Setenv("TRUST_PARAMS", "1")
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ func SupportedSectorSize(ssize uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
const SectorChallengeRatioDiv = 25
|
||||
|
||||
// /////
|
||||
// Payments
|
||||
|
||||
@@ -105,3 +107,4 @@ const BlsSignatureCacheSize = 40000
|
||||
// Limits
|
||||
|
||||
const BlockMessageLimit = 512
|
||||
const MinerMaxSectors = 1 << 48
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import "fmt"
|
||||
var CurrentCommit string
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.2.2"
|
||||
const BuildVersion = "0.2.8"
|
||||
|
||||
var UserVersion = BuildVersion + CurrentCommit
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ const (
|
||||
GasCreateActor = 100
|
||||
)
|
||||
|
||||
var BuiltInActors map[cid.Cid]bool
|
||||
|
||||
func init() {
|
||||
|
||||
n, err := cbor.WrapObject(map[string]string{}, mh.SHA2_256, -1)
|
||||
@@ -160,12 +162,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams)
|
||||
}
|
||||
|
||||
func IsBuiltinActor(code cid.Cid) bool {
|
||||
switch code {
|
||||
case StorageMarketCodeCid, StoragePowerCodeCid, StorageMinerCodeCid, AccountCodeCid, InitCodeCid, MultisigCodeCid, PaymentChannelCodeCid:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return BuiltInActors[code]
|
||||
}
|
||||
|
||||
func IsSingletonActor(code cid.Cid) bool {
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -22,8 +20,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const MaxSectors = 1 << 48
|
||||
|
||||
type StorageMinerActor struct{}
|
||||
|
||||
type StorageMinerActorState struct {
|
||||
@@ -485,7 +481,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
}
|
||||
|
||||
activeFaults := uint64(0)
|
||||
var sectorInfos []ffi.PublicSectorInfo
|
||||
var sectorInfos []types.PublicSectorInfo
|
||||
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
|
||||
if faults[id] {
|
||||
activeFaults++
|
||||
@@ -496,7 +492,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
|
||||
return xerrors.New("could not decode comms")
|
||||
}
|
||||
si := ffi.PublicSectorInfo{
|
||||
si := types.PublicSectorInfo{
|
||||
SectorID: id,
|
||||
}
|
||||
commR := comms[0]
|
||||
@@ -514,11 +510,11 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
|
||||
proverID := vmctx.Message().To // TODO: normalize to ID address
|
||||
|
||||
var candidates []sectorbuilder.EPostCandidate
|
||||
var candidates []types.Candidate
|
||||
for _, t := range params.Candidates {
|
||||
var partial [32]byte
|
||||
copy(partial[:], t.Partial)
|
||||
candidates = append(candidates, sectorbuilder.EPostCandidate{
|
||||
candidates = append(candidates, types.Candidate{
|
||||
PartialTicket: partial,
|
||||
SectorID: t.SectorID,
|
||||
SectorChallengeIndex: t.ChallengeIndex,
|
||||
@@ -526,7 +522,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
|
||||
}
|
||||
|
||||
if ok, lerr := vmctx.Sys().VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
|
||||
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
|
||||
sectorInfos, seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
|
||||
if lerr != nil {
|
||||
// TODO: study PoST errors
|
||||
return nil, aerrors.Absorb(lerr, 4, "PoST error")
|
||||
@@ -571,7 +567,7 @@ func SectorIsUnique(ctx context.Context, s types.Storage, sroot cid.Cid, sid uin
|
||||
}
|
||||
|
||||
func AddToSectorSet(ctx context.Context, blks amt.Blocks, ss cid.Cid, sectorID uint64, commR, commD []byte) (cid.Cid, ActorError) {
|
||||
if sectorID >= MaxSectors {
|
||||
if sectorID >= build.MinerMaxSectors {
|
||||
return cid.Undef, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
|
||||
}
|
||||
ssr, err := amt.LoadAMT(blks, ss)
|
||||
@@ -594,7 +590,7 @@ func AddToSectorSet(ctx context.Context, blks amt.Blocks, ss cid.Cid, sectorID u
|
||||
}
|
||||
|
||||
func GetFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, sectorID uint64) (bool, []byte, []byte, ActorError) {
|
||||
if sectorID >= MaxSectors {
|
||||
if sectorID >= build.MinerMaxSectors {
|
||||
return false, nil, nil, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,903 @@
|
||||
package actors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
amt2 "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type StorageMinerActor2 struct{}
|
||||
|
||||
func (sma StorageMinerActor2) Exports() []interface{} {
|
||||
return []interface{}{
|
||||
1: sma.StorageMinerConstructor,
|
||||
2: sma.PreCommitSector,
|
||||
3: sma.ProveCommitSector,
|
||||
4: sma.SubmitFallbackPoSt,
|
||||
//5: sma.SlashStorageFault,
|
||||
//6: sma.GetCurrentProvingSet,
|
||||
//7: sma.ArbitrateDeal,
|
||||
//8: sma.DePledge,
|
||||
9: sma.GetOwner,
|
||||
10: sma.GetWorkerAddr,
|
||||
11: withUpdates(
|
||||
update{0, sma.GetPower},
|
||||
update{build.ForkMissingSnowballs, sma.GetPower2},
|
||||
), // FORK
|
||||
12: sma.GetPeerID,
|
||||
13: sma.GetSectorSize,
|
||||
14: sma.UpdatePeerID,
|
||||
//15: sma.ChangeWorker,
|
||||
16: sma.IsSlashed,
|
||||
17: sma.CheckMiner,
|
||||
18: sma.DeclareFaults,
|
||||
19: sma.SlashConsensusFault,
|
||||
20: sma.SubmitElectionPoSt,
|
||||
}
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) StorageMinerConstructor(act *types.Actor, vmctx types.VMContext, params *StorageMinerConstructorParams) ([]byte, ActorError) {
|
||||
minerInfo := &MinerInfo{
|
||||
Owner: params.Owner,
|
||||
Worker: params.Worker,
|
||||
PeerID: params.PeerID,
|
||||
SectorSize: params.SectorSize,
|
||||
}
|
||||
|
||||
minfocid, err := vmctx.Storage().Put(minerInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var self StorageMinerActorState
|
||||
sectors := amt2.NewAMT(types.WrapStorage(vmctx.Storage()))
|
||||
scid, serr := sectors.Flush()
|
||||
if serr != nil {
|
||||
return nil, aerrors.HandleExternalError(serr, "initializing AMT")
|
||||
}
|
||||
|
||||
self.Sectors = scid
|
||||
self.ProvingSet = scid
|
||||
self.Info = minfocid
|
||||
|
||||
storage := vmctx.Storage()
|
||||
c, err := storage.Put(&self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := storage.Commit(EmptyCBOR, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) PreCommitSector(act *types.Actor, vmctx types.VMContext, params *SectorPreCommitInfo) ([]byte, ActorError) {
|
||||
|
||||
ctx := vmctx.Context()
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if params.SealEpoch >= vmctx.BlockHeight()+build.SealRandomnessLookback {
|
||||
return nil, aerrors.Newf(1, "sector commitment must be based off past randomness (%d >= %d)", params.SealEpoch, vmctx.BlockHeight()+build.SealRandomnessLookback)
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight()-params.SealEpoch+build.SealRandomnessLookback > build.SealRandomnessLookbackLimit {
|
||||
return nil, aerrors.Newf(2, "sector commitment must be recent enough (was %d)", vmctx.BlockHeight()-params.SealEpoch+build.SealRandomnessLookback)
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(1, "not authorized to precommit sector for miner")
|
||||
}
|
||||
|
||||
// make sure the miner isnt trying to submit a pre-existing sector
|
||||
unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !unique {
|
||||
return nil, aerrors.New(3, "sector already committed!")
|
||||
}
|
||||
|
||||
// Power of the miner after adding this sector
|
||||
futurePower := types.BigAdd(self.Power, types.NewInt(mi.SectorSize))
|
||||
collateralRequired := CollateralForPower(futurePower)
|
||||
|
||||
// TODO: grab from market?
|
||||
if act.Balance.LessThan(collateralRequired) {
|
||||
return nil, aerrors.New(4, "not enough collateral")
|
||||
}
|
||||
|
||||
self.PreCommittedSectors[uintToStringKey(params.SectorNumber)] = &PreCommittedSector{
|
||||
Info: *params,
|
||||
ReceivedEpoch: vmctx.BlockHeight(),
|
||||
}
|
||||
|
||||
if len(self.PreCommittedSectors) > 4096 {
|
||||
return nil, aerrors.New(5, "too many precommitted sectors")
|
||||
}
|
||||
|
||||
nstate, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) ProveCommitSector(act *types.Actor, vmctx types.VMContext, params *SectorProveCommitInfo) ([]byte, ActorError) {
|
||||
ctx := vmctx.Context()
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(1, "not authorized to submit sector proof for miner")
|
||||
}
|
||||
|
||||
us, ok := self.PreCommittedSectors[uintToStringKey(params.SectorID)]
|
||||
if !ok {
|
||||
return nil, aerrors.New(1, "no pre-commitment found for sector")
|
||||
}
|
||||
|
||||
if us.ReceivedEpoch+build.InteractivePoRepDelay >= vmctx.BlockHeight() {
|
||||
return nil, aerrors.New(2, "too early for proof submission")
|
||||
}
|
||||
|
||||
delete(self.PreCommittedSectors, uintToStringKey(params.SectorID))
|
||||
|
||||
// TODO: ensure normalization to ID address
|
||||
maddr := vmctx.Message().To
|
||||
|
||||
if vmctx.BlockHeight()-us.Info.SealEpoch > build.MaxSealLookback {
|
||||
return nil, aerrors.Newf(5, "source randomness for sector SealEpoch too far in past (epoch %d)", us.Info.SealEpoch)
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight()-us.ReceivedEpoch > build.MaxSealLookback {
|
||||
return nil, aerrors.Newf(6, "source randomness for sector ReceivedEpoch too far in past (epoch %d)", us.ReceivedEpoch)
|
||||
}
|
||||
|
||||
ticket, err := vmctx.GetRandomness(us.Info.SealEpoch - build.SealRandomnessLookback)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to get ticket randomness")
|
||||
}
|
||||
|
||||
seed, err := vmctx.GetRandomness(us.ReceivedEpoch + build.InteractivePoRepDelay)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to get randomness for prove sector commitment")
|
||||
}
|
||||
|
||||
enc, err := SerializeParams(&ComputeDataCommitmentParams{
|
||||
DealIDs: params.DealIDs,
|
||||
SectorSize: mi.SectorSize,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to serialize ComputeDataCommitmentParams")
|
||||
}
|
||||
|
||||
commD, err := vmctx.Send(StorageMarketAddress, SMAMethods.ComputeDataCommitment, types.NewInt(0), enc)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrapf(err, "failed to compute data commitment (sector %d, deals: %v)", params.SectorID, params.DealIDs)
|
||||
}
|
||||
|
||||
if ok, err := vmctx.Sys().ValidatePoRep(ctx, maddr, mi.SectorSize, commD, us.Info.CommR, ticket, params.Proof, seed, params.SectorID); err != nil {
|
||||
return nil, err
|
||||
} else if !ok {
|
||||
return nil, aerrors.Newf(2, "porep proof was invalid (t:%x; s:%x(%d); p:%s)", ticket, seed, us.ReceivedEpoch+build.InteractivePoRepDelay, truncateHexPrint(params.Proof))
|
||||
}
|
||||
|
||||
// Note: There must exist a unique index in the miner's sector set for each
|
||||
// sector ID. The `faults`, `recovered`, and `done` parameters of the
|
||||
// SubmitPoSt method express indices into this sector set.
|
||||
nssroot, err := AddToSectorSet2(ctx, types.WrapStorage(vmctx.Storage()), self.Sectors, params.SectorID, us.Info.CommR, commD)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
self.Sectors = nssroot
|
||||
|
||||
// if miner is not mining, start their proving period now
|
||||
// Note: As written here, every miners first PoSt will only be over one sector.
|
||||
// We could set up a 'grace period' for starting mining that would allow miners
|
||||
// to submit several sectors for their first proving period. Alternatively, we
|
||||
// could simply make the 'PreCommitSector' call take multiple sectors at a time.
|
||||
//
|
||||
// Note: Proving period is a function of sector size; small sectors take less
|
||||
// time to prove than large sectors do. Sector size is selected when pledging.
|
||||
pss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
|
||||
if lerr != nil {
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
if pss.Count == 0 && !self.Active {
|
||||
self.ProvingSet = self.Sectors
|
||||
// TODO: probably want to wait until the miner is above a certain
|
||||
// threshold before starting this
|
||||
self.ElectionPeriodStart = vmctx.BlockHeight()
|
||||
}
|
||||
|
||||
nstate, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
activateParams, err := SerializeParams(&ActivateStorageDealsParams{
|
||||
Deals: params.DealIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = vmctx.Send(StorageMarketAddress, SMAMethods.ActivateStorageDeals, types.NewInt(0), activateParams)
|
||||
return nil, aerrors.Wrapf(err, "calling ActivateStorageDeals failed")
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) SubmitFallbackPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitFallbackPoStParams) ([]byte, ActorError) {
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(1, "not authorized to submit post for miner")
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: handle fees
|
||||
msgVal := vmctx.Message().Value
|
||||
if msgVal.LessThan(feesRequired) {
|
||||
return nil, aerrors.New(2, "not enough funds to pay post submission fees")
|
||||
}
|
||||
|
||||
if msgVal.GreaterThan(feesRequired) {
|
||||
_, err := vmctx.Send(vmctx.Message().From, 0,
|
||||
types.BigSub(msgVal, feesRequired), nil)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "could not refund excess fees")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
var seed [sectorbuilder.CommLen]byte
|
||||
{
|
||||
randHeight := self.ElectionPeriodStart + build.FallbackPoStDelay
|
||||
if vmctx.BlockHeight() <= randHeight {
|
||||
// TODO: spec, retcode
|
||||
return nil, aerrors.Newf(1, "submit fallback PoSt called too early (%d < %d)", vmctx.BlockHeight(), randHeight)
|
||||
}
|
||||
|
||||
rand, err := vmctx.GetRandomness(randHeight)
|
||||
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "could not get randomness for PoST")
|
||||
}
|
||||
if len(rand) < len(seed) {
|
||||
return nil, aerrors.Escalate(fmt.Errorf("randomness too small (%d < %d)",
|
||||
len(rand), len(seed)), "improper randomness")
|
||||
}
|
||||
copy(seed[:], rand)
|
||||
}
|
||||
|
||||
pss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
|
||||
if lerr != nil {
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
ss, lerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if lerr != nil {
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(err, 5, "RLE+ invalid")
|
||||
}
|
||||
|
||||
activeFaults := uint64(0)
|
||||
var sectorInfos []types.PublicSectorInfo
|
||||
if err := pss.ForEach(func(id uint64, v *cbg.Deferred) error {
|
||||
if faults[id] {
|
||||
activeFaults++
|
||||
return nil
|
||||
}
|
||||
|
||||
var comms [][]byte
|
||||
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
|
||||
return xerrors.New("could not decode comms")
|
||||
}
|
||||
si := types.PublicSectorInfo{
|
||||
SectorID: id,
|
||||
}
|
||||
commR := comms[0]
|
||||
if len(commR) != len(si.CommR) {
|
||||
return xerrors.Errorf("commR length is wrong: %d", len(commR))
|
||||
}
|
||||
copy(si.CommR[:], commR)
|
||||
|
||||
sectorInfos = append(sectorInfos, si)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, aerrors.Absorb(err, 3, "could not decode sectorset")
|
||||
}
|
||||
|
||||
proverID := vmctx.Message().To // TODO: normalize to ID address
|
||||
|
||||
var candidates []types.Candidate
|
||||
for _, t := range params.Candidates {
|
||||
var partial [32]byte
|
||||
copy(partial[:], t.Partial)
|
||||
candidates = append(candidates, types.Candidate{
|
||||
PartialTicket: partial,
|
||||
SectorID: t.SectorID,
|
||||
SectorChallengeIndex: t.ChallengeIndex,
|
||||
})
|
||||
}
|
||||
|
||||
if ok, lerr := vmctx.Sys().VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
|
||||
sectorInfos, seed[:], params.Proof, candidates, proverID, activeFaults); !ok || lerr != nil {
|
||||
if lerr != nil {
|
||||
// TODO: study PoST errors
|
||||
return nil, aerrors.Absorb(lerr, 4, "PoST error")
|
||||
}
|
||||
if !ok {
|
||||
return nil, aerrors.New(4, "PoST invalid")
|
||||
}
|
||||
}
|
||||
|
||||
// Post submission is successful!
|
||||
if err := onSuccessfulPoSt2(self, vmctx, activeFaults); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vmctx.Storage().Commit(oldstate, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetPower(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return self.Power.Bytes(), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetPower2(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if self.SlashedAt != 0 {
|
||||
return types.NewInt(0).Bytes(), nil
|
||||
}
|
||||
|
||||
return self.Power.Bytes(), nil
|
||||
}
|
||||
|
||||
func SectorIsUnique2(ctx context.Context, s types.Storage, sroot cid.Cid, sid uint64) (bool, ActorError) {
|
||||
found, _, _, err := GetFromSectorSet2(ctx, s, sroot, sid)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return !found, nil
|
||||
}
|
||||
|
||||
func AddToSectorSet2(ctx context.Context, blks amt2.Blocks, ss cid.Cid, sectorID uint64, commR, commD []byte) (cid.Cid, ActorError) {
|
||||
if sectorID >= build.MinerMaxSectors {
|
||||
return cid.Undef, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
|
||||
}
|
||||
ssr, err := amt2.LoadAMT(blks, ss)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "could not load sector set node")
|
||||
}
|
||||
|
||||
// TODO: Spec says to use SealCommitment, and construct commD from deals each time,
|
||||
// but that would make SubmitPoSt way, way more expensive
|
||||
if err := ssr.Set(sectorID, [][]byte{commR, commD}); err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to set commitment in sector set")
|
||||
}
|
||||
|
||||
ncid, err := ssr.Flush()
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush sector set")
|
||||
}
|
||||
|
||||
return ncid, nil
|
||||
}
|
||||
|
||||
func GetFromSectorSet2(ctx context.Context, s types.Storage, ss cid.Cid, sectorID uint64) (bool, []byte, []byte, ActorError) {
|
||||
if sectorID >= build.MinerMaxSectors {
|
||||
return false, nil, nil, aerrors.Newf(25, "sector ID out of range: %d", sectorID)
|
||||
}
|
||||
|
||||
ssr, err := amt2.LoadAMT(types.WrapStorage(s), ss)
|
||||
if err != nil {
|
||||
return false, nil, nil, aerrors.HandleExternalError(err, "could not load sector set node")
|
||||
}
|
||||
|
||||
var comms [][]byte
|
||||
err = ssr.Get(sectorID, &comms)
|
||||
if err != nil {
|
||||
if _, ok := err.(*amt2.ErrNotFound); ok {
|
||||
return false, nil, nil, nil
|
||||
}
|
||||
return false, nil, nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
|
||||
}
|
||||
|
||||
if len(comms) != 2 {
|
||||
return false, nil, nil, aerrors.Newf(20, "sector set entry should only have 2 elements")
|
||||
}
|
||||
|
||||
return true, comms[0], comms[1], nil
|
||||
}
|
||||
|
||||
func RemoveFromSectorSet2(ctx context.Context, s types.Storage, ss cid.Cid, ids []uint64) (cid.Cid, aerrors.ActorError) {
|
||||
|
||||
ssr, err := amt2.LoadAMT(types.WrapStorage(s), ss)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "could not load sector set node")
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
if err := ssr.Delete(id); err != nil {
|
||||
log.Warnf("failed to delete sector %d from set: %s", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
ncid, err := ssr.Flush()
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to flush sector set")
|
||||
}
|
||||
|
||||
return ncid, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetWorkerAddr(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mi.Worker.Bytes(), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetOwner(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mi.Owner.Bytes(), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetPeerID(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(mi.PeerID), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) UpdatePeerID(act *types.Actor, vmctx types.VMContext, params *UpdatePeerIDParams) ([]byte, ActorError) {
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(2, "only the mine worker may update the peer ID")
|
||||
}
|
||||
|
||||
mi.PeerID = params.PeerID
|
||||
|
||||
mic, err := vmctx.Storage().Put(mi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
self.Info = mic
|
||||
|
||||
c, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := vmctx.Storage().Commit(oldstate, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) GetSectorSize(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mi, err := loadMinerInfo(vmctx, self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewInt(mi.SectorSize).Bytes(), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) IsSlashed(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) {
|
||||
_, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cbg.EncodeBool(self.SlashedAt != 0), nil
|
||||
}
|
||||
|
||||
// TODO: better name
|
||||
func (sma StorageMinerActor2) CheckMiner(act *types.Actor, vmctx types.VMContext, params *CheckMinerParams) ([]byte, ActorError) {
|
||||
if vmctx.Message().From != StoragePowerAddress {
|
||||
return nil, aerrors.New(2, "only the storage power actor can check miner")
|
||||
}
|
||||
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isLate(vmctx.BlockHeight(), self) {
|
||||
// Everything's fine
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if self.SlashedAt != 0 {
|
||||
// Don't slash more than necessary
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if params.NetworkPower.Equals(self.Power) {
|
||||
// Don't break the network when there's only one miner left
|
||||
|
||||
log.Warnf("can't slash miner %s for missed PoSt, no power would be left in the network", vmctx.Message().To)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Slash for being late
|
||||
|
||||
self.SlashedAt = vmctx.BlockHeight()
|
||||
oldPower := self.Power
|
||||
|
||||
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
|
||||
self.Power = types.NewInt(0)
|
||||
}
|
||||
|
||||
nstate, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
if err := oldPower.MarshalCBOR(&out); err != nil {
|
||||
return nil, aerrors.HandleExternalError(err, "marshaling return value")
|
||||
}
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) DeclareFaults(act *types.Actor, vmctx types.VMContext, params *DeclareFaultsParams) ([]byte, ActorError) {
|
||||
oldstate, self, aerr := loadState(vmctx)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
mi, aerr := loadMinerInfo(vmctx, self)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
if vmctx.Message().From != mi.Worker {
|
||||
return nil, aerrors.New(1, "not authorized to declare faults for miner")
|
||||
}
|
||||
|
||||
nfaults, err := types.MergeBitFields(params.Faults, self.FaultSet)
|
||||
if err != nil {
|
||||
return nil, aerrors.Absorb(err, 1, "failed to merge bitfields")
|
||||
}
|
||||
|
||||
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load sector set")
|
||||
}
|
||||
|
||||
cf, nerr := nfaults.Count()
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(nerr, 2, "could not decode RLE+")
|
||||
}
|
||||
|
||||
if cf > 2*ss.Count {
|
||||
return nil, aerrors.Newf(3, "too many declared faults: %d > %d", cf, 2*ss.Count)
|
||||
}
|
||||
|
||||
self.FaultSet = nfaults
|
||||
|
||||
self.LastFaultSubmission = vmctx.BlockHeight()
|
||||
|
||||
nstate, aerr := vmctx.Storage().Put(self)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, nstate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) {
|
||||
if vmctx.Message().From != StoragePowerAddress {
|
||||
return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor")
|
||||
}
|
||||
|
||||
slashedCollateral := params.SlashedCollateral
|
||||
if slashedCollateral.LessThan(act.Balance) {
|
||||
slashedCollateral = act.Balance
|
||||
}
|
||||
|
||||
// Some of the slashed collateral should be paid to the slasher
|
||||
// GROWTH_RATE determines how fast the slasher share of slashed collateral will increase as block elapses
|
||||
// current GROWTH_RATE results in SLASHER_SHARE reaches 1 after 30 blocks
|
||||
// TODO: define arithmetic precision and rounding for this operation
|
||||
blockElapsed := vmctx.BlockHeight() - params.AtHeight
|
||||
|
||||
slasherShare := slasherShare(params.SlashedCollateral, blockElapsed)
|
||||
|
||||
burnPortion := types.BigSub(slashedCollateral, slasherShare)
|
||||
|
||||
_, err := vmctx.Send(vmctx.Message().From, 0, slasherShare, nil)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to pay slasher")
|
||||
}
|
||||
|
||||
_, err = vmctx.Send(BurntFundsAddress, 0, burnPortion, nil)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to burn funds")
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
|
||||
oldstate, self, err := loadState(vmctx)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to load state for slashing")
|
||||
}
|
||||
|
||||
self.Power = types.NewInt(0)
|
||||
|
||||
ncid, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, ncid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this still allows the miner to commit sectors and submit posts,
|
||||
// their users could potentially be unaffected, but the miner will never be
|
||||
// able to mine a block again
|
||||
// One potential issue: the miner will have to pay back the slashed
|
||||
// collateral to continue submitting PoSts, which includes pledge
|
||||
// collateral that they no longer really 'need'
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (sma StorageMinerActor2) SubmitElectionPoSt(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
||||
if vmctx.Message().From != NetworkAddress {
|
||||
return nil, aerrors.Newf(1, "submit election post can only be called by the storage power actor")
|
||||
}
|
||||
|
||||
oldstate, self, aerr := loadState(vmctx)
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
if self.SlashedAt != 0 {
|
||||
return nil, aerrors.New(1, "slashed miners can't perform election PoSt")
|
||||
}
|
||||
|
||||
pss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.AllMap(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return nil, aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
|
||||
}
|
||||
|
||||
activeFaults := uint64(0)
|
||||
for f := range faults {
|
||||
if f > amt2.MaxIndex {
|
||||
continue
|
||||
}
|
||||
|
||||
var comms [][]byte
|
||||
err := pss.Get(f, &comms)
|
||||
if err != nil {
|
||||
var notfound *amt2.ErrNotFound
|
||||
if !xerrors.As(err, ¬found) {
|
||||
return nil, aerrors.HandleExternalError(err, "failed to find sector in sector set")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
activeFaults++
|
||||
}
|
||||
|
||||
if err := onSuccessfulPoSt2(self, vmctx, activeFaults); err != nil { // TODO
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ncid, err := vmctx.Storage().Put(self)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vmctx.Storage().Commit(oldstate, ncid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func onSuccessfulPoSt2(self *StorageMinerActorState, vmctx types.VMContext, activeFaults uint64) aerrors.ActorError {
|
||||
// FORK
|
||||
if vmctx.BlockHeight() < build.ForkBootyBayHeight {
|
||||
return onSuccessfulPoSt(self, vmctx, activeFaults)
|
||||
}
|
||||
|
||||
var mi MinerInfo
|
||||
if err := vmctx.Storage().Get(self.Info, &mi); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.ProvingSet)
|
||||
if nerr != nil {
|
||||
return aerrors.HandleExternalError(nerr, "failed to load proving set")
|
||||
}
|
||||
|
||||
ss, nerr := amt2.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Sectors)
|
||||
if nerr != nil {
|
||||
return aerrors.HandleExternalError(nerr, "failed to load sector set")
|
||||
}
|
||||
|
||||
faults, nerr := self.FaultSet.All(2 * ss.Count)
|
||||
if nerr != nil {
|
||||
return aerrors.Absorb(nerr, 1, "invalid bitfield (fatal?)")
|
||||
}
|
||||
|
||||
self.FaultSet = types.NewBitField()
|
||||
|
||||
oldPower := self.Power
|
||||
newPower := types.BigMul(types.NewInt(pss.Count-activeFaults), types.NewInt(mi.SectorSize))
|
||||
|
||||
// If below the minimum size requirement, miners have zero power
|
||||
if newPower.LessThan(types.NewInt(build.MinimumMinerPower)) {
|
||||
newPower = types.NewInt(0)
|
||||
}
|
||||
|
||||
self.Power = newPower
|
||||
|
||||
delta := types.BigSub(self.Power, oldPower)
|
||||
if self.SlashedAt != 0 {
|
||||
self.SlashedAt = 0
|
||||
delta = self.Power
|
||||
}
|
||||
|
||||
prevSlashingDeadline := self.ElectionPeriodStart + build.SlashablePowerDelay
|
||||
if !self.Active && newPower.GreaterThan(types.NewInt(0)) {
|
||||
self.Active = true
|
||||
prevSlashingDeadline = 0
|
||||
}
|
||||
|
||||
if !(oldPower.IsZero() && newPower.IsZero()) {
|
||||
enc, err := SerializeParams(&UpdateStorageParams{
|
||||
Delta: delta,
|
||||
NextSlashDeadline: vmctx.BlockHeight() + build.SlashablePowerDelay,
|
||||
PreviousSlashDeadline: prevSlashingDeadline,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
|
||||
if err != nil {
|
||||
return aerrors.Wrap(err, "updating storage failed")
|
||||
}
|
||||
|
||||
self.ElectionPeriodStart = vmctx.BlockHeight()
|
||||
}
|
||||
|
||||
var ncid cid.Cid
|
||||
var err aerrors.ActorError
|
||||
|
||||
ncid, err = RemoveFromSectorSet2(vmctx.Context(), vmctx.Storage(), self.Sectors, faults)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.Sectors = ncid
|
||||
self.ProvingSet = ncid
|
||||
return nil
|
||||
}
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-cbor-util"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
type StorageMarketActor struct{}
|
||||
@@ -131,7 +132,7 @@ func (sdp *StorageDealProposal) Verify(worker address.Address) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes()); err != nil {
|
||||
if err := sigs.Verify(sdp.ProposerSignature, sdp.Client, buf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
type StoragePowerActor struct{}
|
||||
@@ -85,7 +86,13 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM
|
||||
return nil, aerrors.Newf(1, "not enough funds passed to cover required miner collateral (needed %s, got %s)", reqColl, vmctx.Message().Value)
|
||||
}
|
||||
|
||||
encoded, err := CreateExecParams(StorageMinerCodeCid, &StorageMinerConstructorParams{
|
||||
// FORK
|
||||
minerCid := StorageMinerCodeCid
|
||||
if vmctx.BlockHeight() > build.ForkFrigidHeight {
|
||||
minerCid = StorageMiner2CodeCid
|
||||
}
|
||||
|
||||
encoded, err := CreateExecParams(minerCid, &StorageMinerConstructorParams{
|
||||
Owner: params.Owner,
|
||||
Worker: params.Worker,
|
||||
SectorSize: params.SectorSize,
|
||||
@@ -138,6 +145,21 @@ func (spa StoragePowerActor) ArbitrateConsensusFault(act *types.Actor, vmctx typ
|
||||
return nil, aerrors.New(2, "blocks must be from the same miner")
|
||||
}
|
||||
|
||||
// FORK
|
||||
if vmctx.BlockHeight() > build.ForkBlizzardHeight {
|
||||
if params.Block1.Height <= build.ForkBlizzardHeight {
|
||||
return nil, aerrors.New(10, "cannot slash miners with blocks from before blizzard")
|
||||
}
|
||||
|
||||
if params.Block2.Height <= build.ForkBlizzardHeight {
|
||||
return nil, aerrors.New(11, "cannot slash miners with blocks from before blizzard")
|
||||
}
|
||||
|
||||
if params.Block1.Cid() == params.Block2.Cid() {
|
||||
return nil, aerrors.New(3, "blocks must be different")
|
||||
}
|
||||
}
|
||||
|
||||
rval, err := vmctx.Send(params.Block1.Miner, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to get miner worker")
|
||||
@@ -149,11 +171,11 @@ func (spa StoragePowerActor) ArbitrateConsensusFault(act *types.Actor, vmctx typ
|
||||
return nil, aerrors.Absorb(oerr, 3, "response from 'GetWorkerAddr' was not a valid address")
|
||||
}
|
||||
|
||||
if err := params.Block1.CheckBlockSignature(vmctx.Context(), worker); err != nil {
|
||||
if err := sigs.CheckBlockSignature(params.Block1, vmctx.Context(), worker); err != nil {
|
||||
return nil, aerrors.Absorb(err, 4, "block1 did not have valid signature")
|
||||
}
|
||||
|
||||
if err := params.Block2.CheckBlockSignature(vmctx.Context(), worker); err != nil {
|
||||
if err := sigs.CheckBlockSignature(params.Block2, vmctx.Context(), worker); err != nil {
|
||||
return nil, aerrors.Absorb(err, 5, "block2 did not have valid signature")
|
||||
}
|
||||
|
||||
@@ -453,7 +475,8 @@ func powerLookup(ctx context.Context, vmctx types.VMContext, self *StoragePowerS
|
||||
}
|
||||
|
||||
if !has {
|
||||
return types.EmptyInt, aerrors.New(1, "miner not registered with storage power actor")
|
||||
// A miner could be registered with storage power actor, but removed for some reasons, e.g. consensus fault
|
||||
return types.EmptyInt, aerrors.New(1, "miner not registered with storage power actor, or removed already")
|
||||
}
|
||||
|
||||
// TODO: Use local amt
|
||||
@@ -627,6 +650,8 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
|
||||
return aerrors.HandleExternalError(err, "failed to load proving bucket")
|
||||
}
|
||||
|
||||
forRemoval := make([]address.Address, 0)
|
||||
|
||||
err = bhamt.ForEach(vmctx.Context(), func(k string, val interface{}) error {
|
||||
_, span := trace.StartSpan(vmctx.Context(), "StoragePowerActor.CheckProofSubmissions.loop")
|
||||
defer span.End()
|
||||
@@ -636,6 +661,18 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
|
||||
return aerrors.Escalate(err, "parsing miner address")
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight() > build.ForkMissingSnowballs {
|
||||
has, aerr := MinerSetHas(vmctx, self.Miners, maddr)
|
||||
if aerr != nil {
|
||||
return aerr
|
||||
}
|
||||
|
||||
if !has {
|
||||
forRemoval = append(forRemoval, maddr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
span.AddAttributes(trace.StringAttribute("miner", maddr.String()))
|
||||
|
||||
params, err := SerializeParams(&CheckMinerParams{NetworkPower: self.TotalStorage})
|
||||
@@ -669,6 +706,24 @@ func checkProofSubmissionsAtH(vmctx types.VMContext, self *StoragePowerState, he
|
||||
return aerrors.HandleExternalError(err, "iterating miners in proving bucket")
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight() > build.ForkMissingSnowballs && len(forRemoval) > 0 {
|
||||
nBucket, err := MinerSetRemove(vmctx.Context(), vmctx, bucket, forRemoval...)
|
||||
|
||||
if err != nil {
|
||||
return aerrors.Wrap(err, "could not remove miners from set")
|
||||
}
|
||||
|
||||
eerr := buckets.Set(bucketID, nBucket)
|
||||
if err != nil {
|
||||
return aerrors.HandleExternalError(eerr, "could not set the bucket")
|
||||
}
|
||||
ncid, eerr := buckets.Flush()
|
||||
if err != nil {
|
||||
return aerrors.HandleExternalError(eerr, "could not flush buckets")
|
||||
}
|
||||
self.ProvingBuckets = ncid
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -743,19 +798,21 @@ func MinerSetAdd(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (cid.Cid, aerrors.ActorError) {
|
||||
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddrs ...address.Address) (cid.Cid, aerrors.ActorError) {
|
||||
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to load miner set")
|
||||
}
|
||||
|
||||
mkey := string(maddr.Bytes())
|
||||
switch nd.Delete(ctx, mkey) {
|
||||
default:
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to delete miner from set")
|
||||
case hamt.ErrNotFound:
|
||||
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
|
||||
case nil:
|
||||
for _, maddr := range maddrs {
|
||||
mkey := string(maddr.Bytes())
|
||||
switch nd.Delete(ctx, mkey) {
|
||||
default:
|
||||
return cid.Undef, aerrors.HandleExternalError(err, "failed to delete miner from set")
|
||||
case hamt.ErrNotFound:
|
||||
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
|
||||
case nil:
|
||||
}
|
||||
}
|
||||
|
||||
if err := nd.Flush(ctx); err != nil {
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@@ -93,7 +95,15 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
||||
signBlock(t, h.w, workerAddr, b1)
|
||||
signBlock(t, h.w, workerAddr, b2)
|
||||
|
||||
h.BlockHeight = build.ForkBlizzardHeight + 1
|
||||
ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
|
||||
&ArbitrateConsensusFaultParams{
|
||||
Block1: b1,
|
||||
Block2: b1,
|
||||
})
|
||||
assert.Equal(t, uint8(3), ret.ExitCode, "should have failed with exit 3")
|
||||
|
||||
ret, _ = h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault,
|
||||
&ArbitrateConsensusFaultParams{
|
||||
Block1: b1,
|
||||
Block2: b2,
|
||||
@@ -145,7 +155,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
|
||||
|
||||
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
|
||||
c := fakeCid(t, 1)
|
||||
return &types.BlockHeader{Height: 5, Miner: minerAddr, Timestamp: ts, ParentStateRoot: c, Messages: c, ParentMessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
|
||||
return &types.BlockHeader{Height: 8000, Miner: minerAddr, Timestamp: ts, ParentStateRoot: c, Messages: c, ParentMessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
|
||||
}
|
||||
|
||||
func fakeCid(t *testing.T, s int) cid.Cid {
|
||||
|
||||
@@ -12,6 +12,7 @@ var CronCodeCid cid.Cid
|
||||
var StoragePowerCodeCid cid.Cid
|
||||
var StorageMarketCodeCid cid.Cid
|
||||
var StorageMinerCodeCid cid.Cid
|
||||
var StorageMiner2CodeCid cid.Cid
|
||||
var MultisigCodeCid cid.Cid
|
||||
var InitCodeCid cid.Cid
|
||||
var PaymentChannelCodeCid cid.Cid
|
||||
@@ -46,7 +47,19 @@ func init() {
|
||||
StoragePowerCodeCid = mustSum("fil/1/power")
|
||||
StorageMarketCodeCid = mustSum("fil/1/market")
|
||||
StorageMinerCodeCid = mustSum("fil/1/miner")
|
||||
StorageMiner2CodeCid = mustSum("fil/1/miner/2")
|
||||
MultisigCodeCid = mustSum("fil/1/multisig")
|
||||
InitCodeCid = mustSum("fil/1/init")
|
||||
PaymentChannelCodeCid = mustSum("fil/1/paych")
|
||||
|
||||
BuiltInActors = map[cid.Cid]bool{
|
||||
StorageMarketCodeCid: true,
|
||||
StoragePowerCodeCid: true,
|
||||
StorageMinerCodeCid: true,
|
||||
StorageMiner2CodeCid: true,
|
||||
AccountCodeCid: true,
|
||||
InitCodeCid: true,
|
||||
MultisigCodeCid: true,
|
||||
PaymentChannelCodeCid: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func setupVMTestEnv(t *testing.T) (*vm.VM, []address.Address, bstore.Blockstore)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateroot, err := st.Flush()
|
||||
stateroot, err := st.Flush(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func withUpdates(updates ...update) interface{} {
|
||||
vmctx := args[1].Interface().(types.VMContext)
|
||||
|
||||
for _, u := range updates {
|
||||
if vmctx.BlockHeight() >= u.start {
|
||||
if vmctx.BlockHeight() > u.start {
|
||||
return reflect.ValueOf(u.method).Call(args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@ package actors_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@@ -185,7 +186,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateroot, err := st.Flush()
|
||||
stateroot, err := st.Flush(context.TODO())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+9
-4
@@ -21,10 +21,15 @@ func NewBadBlockCache() *BadBlockCache {
|
||||
}
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Add(c cid.Cid) {
|
||||
bts.badBlocks.Add(c, nil)
|
||||
func (bts *BadBlockCache) Add(c cid.Cid, reason string) {
|
||||
bts.badBlocks.Add(c, reason)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) bool {
|
||||
return bts.badBlocks.Contains(c)
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (string, bool) {
|
||||
rval, ok := bts.badBlocks.Get(c)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return rval.(string), true
|
||||
}
|
||||
|
||||
@@ -3,17 +3,17 @@ package blocksync
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-cbor-util"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -25,11 +25,7 @@ type NewStreamFunc func(context.Context, peer.ID, ...protocol.ID) (inet.Stream,
|
||||
|
||||
const BlockSyncProtocolID = "/fil/sync/blk/0.0.1"
|
||||
|
||||
func init() {
|
||||
cbor.RegisterCborType(BlockSyncRequest{})
|
||||
cbor.RegisterCborType(BlockSyncResponse{})
|
||||
cbor.RegisterCborType(BSTipSet{})
|
||||
}
|
||||
const BlockSyncMaxRequestLength = 800
|
||||
|
||||
type BlockSyncService struct {
|
||||
cs *store.ChainStore
|
||||
@@ -55,8 +51,17 @@ func ParseBSOptions(optfield uint64) *BSOptions {
|
||||
}
|
||||
|
||||
const (
|
||||
BSOptBlocks = 1 << 0
|
||||
BSOptMessages = 1 << 1
|
||||
BSOptBlocks = 1 << iota
|
||||
BSOptMessages
|
||||
)
|
||||
|
||||
const (
|
||||
StatusOK = uint64(0)
|
||||
StatusPartial = uint64(101)
|
||||
StatusNotFound = uint64(201)
|
||||
StatusGoAway = uint64(202)
|
||||
StatusInternalError = uint64(203)
|
||||
StatusBadRequest = uint64(204)
|
||||
)
|
||||
|
||||
type BlockSyncResponse struct {
|
||||
@@ -93,28 +98,30 @@ func (bss *BlockSyncService) HandleStream(s inet.Stream) {
|
||||
log.Warnf("failed to read block sync request: %s", err)
|
||||
return
|
||||
}
|
||||
log.Infof("block sync request for: %s %d", req.Start, req.RequestLength)
|
||||
log.Infow("block sync request", "start", req.Start, "len", req.RequestLength)
|
||||
|
||||
resp, err := bss.processRequest(ctx, &req)
|
||||
resp, err := bss.processRequest(ctx, s.Conn().RemotePeer(), &req)
|
||||
if err != nil {
|
||||
log.Warn("failed to process block sync request: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
writeDeadline := 60 * time.Second
|
||||
s.SetDeadline(time.Now().Add(writeDeadline))
|
||||
if err := cborutil.WriteCborRPC(s, resp); err != nil {
|
||||
log.Warn("failed to write back response for handle stream: ", err)
|
||||
log.Warnw("failed to write back response for handle stream", "err", err, "peer", s.Conn().RemotePeer())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (bss *BlockSyncService) processRequest(ctx context.Context, req *BlockSyncRequest) (*BlockSyncResponse, error) {
|
||||
func (bss *BlockSyncService) processRequest(ctx context.Context, p peer.ID, req *BlockSyncRequest) (*BlockSyncResponse, error) {
|
||||
_, span := trace.StartSpan(ctx, "blocksync.ProcessRequest")
|
||||
defer span.End()
|
||||
|
||||
opts := ParseBSOptions(req.Options)
|
||||
if len(req.Start) == 0 {
|
||||
return &BlockSyncResponse{
|
||||
Status: 204,
|
||||
Status: StatusBadRequest,
|
||||
Message: "no cids given in blocksync request",
|
||||
}, nil
|
||||
}
|
||||
@@ -122,20 +129,32 @@ func (bss *BlockSyncService) processRequest(ctx context.Context, req *BlockSyncR
|
||||
span.AddAttributes(
|
||||
trace.BoolAttribute("blocks", opts.IncludeBlocks),
|
||||
trace.BoolAttribute("messages", opts.IncludeMessages),
|
||||
trace.Int64Attribute("reqlen", int64(req.RequestLength)),
|
||||
)
|
||||
|
||||
chain, err := bss.collectChainSegment(types.NewTipSetKey(req.Start...), req.RequestLength, opts)
|
||||
reqlen := req.RequestLength
|
||||
if reqlen > BlockSyncMaxRequestLength {
|
||||
log.Warnw("limiting blocksync request length", "orig", req.RequestLength, "peer", p)
|
||||
reqlen = BlockSyncMaxRequestLength
|
||||
}
|
||||
|
||||
chain, err := bss.collectChainSegment(types.NewTipSetKey(req.Start...), reqlen, opts)
|
||||
if err != nil {
|
||||
log.Warn("encountered error while responding to block sync request: ", err)
|
||||
return &BlockSyncResponse{
|
||||
Status: 203,
|
||||
Status: StatusInternalError,
|
||||
Message: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
status := StatusOK
|
||||
if reqlen < req.RequestLength {
|
||||
status = StatusPartial
|
||||
}
|
||||
|
||||
return &BlockSyncResponse{
|
||||
Chain: chain,
|
||||
Status: 0,
|
||||
Status: status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,10 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-cbor-util"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
incrt "github.com/filecoin-project/lotus/lib/increadtimeout"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/peermgr"
|
||||
)
|
||||
@@ -44,15 +45,15 @@ func NewBlockSyncClient(bserv dtypes.ChainBlockService, h host.Host, pmgr peermg
|
||||
|
||||
func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse) error {
|
||||
switch res.Status {
|
||||
case 101: // Partial Response
|
||||
case StatusPartial: // Partial Response
|
||||
return xerrors.Errorf("not handling partial blocksync responses yet")
|
||||
case 201: // req.Start not found
|
||||
case StatusNotFound: // req.Start not found
|
||||
return xerrors.Errorf("not found")
|
||||
case 202: // Go Away
|
||||
case StatusGoAway: // Go Away
|
||||
return xerrors.Errorf("not handling 'go away' blocksync responses yet")
|
||||
case 203: // Internal Error
|
||||
case StatusInternalError: // Internal Error
|
||||
return xerrors.Errorf("block sync peer errored: %s", res.Message)
|
||||
case 204:
|
||||
case StatusBadRequest:
|
||||
return xerrors.Errorf("block sync request invalid: %s", res.Message)
|
||||
default:
|
||||
return xerrors.Errorf("unrecognized response code: %d", res.Status)
|
||||
@@ -194,11 +195,16 @@ func (bs *BlockSync) GetChainMessages(ctx context.Context, h *types.TipSet, coun
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Status == 0 {
|
||||
if res.Status == StatusOK {
|
||||
bs.syncPeers.logGlobalSuccess(time.Since(start))
|
||||
return res.Chain, nil
|
||||
}
|
||||
|
||||
if res.Status == StatusPartial {
|
||||
log.Warn("dont yet handle partial responses")
|
||||
continue
|
||||
}
|
||||
|
||||
err = bs.processStatus(req, res)
|
||||
if err != nil {
|
||||
log.Warnf("BlockSync peer %s response was an error: %s", p.String(), err)
|
||||
@@ -241,16 +247,18 @@ func (bs *BlockSync) sendRequestToPeer(ctx context.Context, p peer.ID, req *Bloc
|
||||
bs.RemovePeer(p)
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
s.SetDeadline(time.Now().Add(10 * time.Second))
|
||||
defer s.SetDeadline(time.Time{})
|
||||
s.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
|
||||
if err := cborutil.WriteCborRPC(s, req); err != nil {
|
||||
s.SetWriteDeadline(time.Time{})
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
s.SetWriteDeadline(time.Time{})
|
||||
|
||||
var res BlockSyncResponse
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(s), &res); err != nil {
|
||||
r := incrt.New(s, 50<<10, 5*time.Second)
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(r), &res); err != nil {
|
||||
bs.syncPeers.logFailure(p, time.Since(start))
|
||||
return nil, err
|
||||
}
|
||||
@@ -455,7 +463,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
getPeerInitLat := func(p peer.ID) float64 {
|
||||
var res float64
|
||||
if bpt.pmgr != nil {
|
||||
if lat, ok := bpt.pmgr.GetPeerLatency(out[i]); ok {
|
||||
if lat, ok := bpt.pmgr.GetPeerLatency(p); ok {
|
||||
res = float64(lat)
|
||||
}
|
||||
}
|
||||
@@ -476,7 +484,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID {
|
||||
failRateJ := float64(pj.failures) / float64(pj.failures+pj.successes)
|
||||
costJ = float64(pj.averageTime) + failRateJ*float64(bpt.avgGlobalTime)
|
||||
} else {
|
||||
costI = getPeerInitLat(out[i])
|
||||
costJ = getPeerInitLat(out[j])
|
||||
}
|
||||
|
||||
return costI < costJ
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -33,10 +33,10 @@ type heightHandler struct {
|
||||
type eventApi interface {
|
||||
ChainNotify(context.Context) (<-chan []*store.HeadChange, error)
|
||||
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
||||
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error)
|
||||
ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
|
||||
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
||||
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) // optional / for CalledMsg
|
||||
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) // optional / for CalledMsg
|
||||
}
|
||||
|
||||
type Events struct {
|
||||
|
||||
@@ -192,7 +192,7 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet) {
|
||||
continue
|
||||
}
|
||||
|
||||
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts)
|
||||
rec, err := e.cs.StateGetReceipt(e.ctx, event.msg.Cid(), ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
|
||||
@@ -40,15 +40,15 @@ type fakeCS struct {
|
||||
sub func(rev, app []*types.TipSet)
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error) {
|
||||
func (fcs *fakeCS) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
|
||||
panic("Not Implemented")
|
||||
}
|
||||
|
||||
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
|
||||
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
|
||||
panic("Not Implemented")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type tsByHFunc func(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
|
||||
type tsByHFunc func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error)
|
||||
|
||||
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
||||
// tipsets
|
||||
@@ -93,7 +93,7 @@ func (tsc *tipSetCache) getNonNull(height uint64) (*types.TipSet, error) {
|
||||
func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) {
|
||||
if tsc.len == 0 {
|
||||
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
||||
return tsc.storage(context.TODO(), height, nil)
|
||||
return tsc.storage(context.TODO(), height, types.EmptyTSK)
|
||||
}
|
||||
|
||||
headH := tsc.cache[tsc.start].Height()
|
||||
@@ -113,7 +113,7 @@ func (tsc *tipSetCache) get(height uint64) (*types.TipSet, error) {
|
||||
|
||||
if height < tail.Height() {
|
||||
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
|
||||
return tsc.storage(context.TODO(), height, tail)
|
||||
return tsc.storage(context.TODO(), height, tail.Key())
|
||||
}
|
||||
|
||||
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTsCache(t *testing.T) {
|
||||
tsc := newTSCache(50, func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
|
||||
tsc := newTSCache(50, func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
|
||||
t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
})
|
||||
@@ -54,7 +54,7 @@ func TestTsCache(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTsCacheNulls(t *testing.T) {
|
||||
tsc := newTSCache(50, func(context.Context, uint64, *types.TipSet) (*types.TipSet, error) {
|
||||
tsc := newTSCache(50, func(context.Context, uint64, types.TipSetKey) (*types.TipSet, error) {
|
||||
t.Fatal("storage call")
|
||||
return &types.TipSet{}, nil
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg store.ChainMsg, hnd Ca
|
||||
msg := smsg.VMMessage()
|
||||
|
||||
return func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||
fa, err := e.cs.StateGetActor(ctx, msg.From, ts)
|
||||
fa, err := e.cs.StateGetActor(ctx, msg.From, ts.Key())
|
||||
if err != nil {
|
||||
return false, true, err
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func (e *calledEvents) CheckMsg(ctx context.Context, smsg store.ChainMsg, hnd Ca
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts)
|
||||
rec, err := e.cs.StateGetReceipt(ctx, smsg.VMMessage().Cid(), ts.Key())
|
||||
if err != nil {
|
||||
return false, true, xerrors.Errorf("getting receipt in CheckMsg: %w", err)
|
||||
}
|
||||
|
||||
+64
-29
@@ -6,36 +6,36 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"io/ioutil"
|
||||
"sync/atomic"
|
||||
|
||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||
|
||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-car"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipfs/go-merkledag"
|
||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||
"github.com/filecoin-project/go-address"
|
||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var log = logging.Logger("gen")
|
||||
@@ -56,6 +56,8 @@ type ChainGen struct {
|
||||
|
||||
Timestamper func(*types.TipSet, uint64) uint64
|
||||
|
||||
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
||||
|
||||
w *wallet.Wallet
|
||||
|
||||
eppProvs map[address.Address]ElectionPoStProver
|
||||
@@ -210,10 +212,11 @@ func NewGenerator() (*ChainGen, error) {
|
||||
genesis: genb.Genesis,
|
||||
w: w,
|
||||
|
||||
Miners: minercfg.MinerAddrs,
|
||||
eppProvs: mgen,
|
||||
banker: banker,
|
||||
receivers: receievers,
|
||||
GetMessages: getRandomMessages,
|
||||
Miners: minercfg.MinerAddrs,
|
||||
eppProvs: mgen,
|
||||
banker: banker,
|
||||
receivers: receievers,
|
||||
|
||||
CurTipset: gents,
|
||||
|
||||
@@ -224,6 +227,14 @@ func NewGenerator() (*ChainGen, error) {
|
||||
return gen, nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) SetStateManager(sm *stmgr.StateManager) {
|
||||
cg.sm = sm
|
||||
}
|
||||
|
||||
func (cg *ChainGen) ChainStore() *store.ChainStore {
|
||||
return cg.cs
|
||||
}
|
||||
|
||||
func (cg *ChainGen) Genesis() *types.BlockHeader {
|
||||
return cg.genesis
|
||||
}
|
||||
@@ -295,7 +306,7 @@ func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
|
||||
func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
|
||||
var blks []*types.FullBlock
|
||||
|
||||
msgs, err := cg.getRandomMessages()
|
||||
msgs, err := cg.GetMessages(cg)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get random messages: %w", err)
|
||||
}
|
||||
@@ -359,7 +370,15 @@ func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cg *ChainGen) getRandomMessages() ([]*types.SignedMessage, error) {
|
||||
func (cg *ChainGen) Banker() address.Address {
|
||||
return cg.banker
|
||||
}
|
||||
|
||||
func (cg *ChainGen) Wallet() *wallet.Wallet {
|
||||
return cg.w
|
||||
}
|
||||
|
||||
func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
||||
msgs := make([]*types.SignedMessage, cg.msgsPerBlock)
|
||||
for m := range msgs {
|
||||
msg := types.Message{
|
||||
@@ -400,13 +419,13 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
|
||||
type MiningCheckAPI interface {
|
||||
ChainGetRandomness(context.Context, types.TipSetKey, int64) ([]byte, error)
|
||||
|
||||
StateMinerPower(context.Context, address.Address, *types.TipSet) (api.MinerPower, error)
|
||||
StateMinerPower(context.Context, address.Address, types.TipSetKey) (api.MinerPower, error)
|
||||
|
||||
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateMinerWorker(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
|
||||
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
|
||||
StateMinerSectorSize(context.Context, address.Address, types.TipSetKey) (uint64, error)
|
||||
|
||||
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
|
||||
StateMinerProvingSet(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error)
|
||||
|
||||
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
|
||||
}
|
||||
@@ -420,7 +439,11 @@ func (mca mca) ChainGetRandomness(ctx context.Context, pts types.TipSetKey, lb i
|
||||
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), int64(lb))
|
||||
}
|
||||
|
||||
func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) {
|
||||
func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (api.MinerPower, error) {
|
||||
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return api.MinerPower{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
mpow, tpow, err := stmgr.GetPower(ctx, mca.sm, ts, maddr)
|
||||
if err != nil {
|
||||
return api.MinerPower{}, err
|
||||
@@ -432,15 +455,27 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t
|
||||
}, err
|
||||
}
|
||||
|
||||
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr)
|
||||
}
|
||||
|
||||
func (mca mca) StateMinerSectorSize(ctx context.Context, maddr address.Address, ts *types.TipSet) (uint64, error) {
|
||||
func (mca mca) StateMinerSectorSize(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (uint64, error) {
|
||||
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return stmgr.GetMinerSectorSize(ctx, mca.sm, ts, maddr)
|
||||
}
|
||||
|
||||
func (mca mca) StateMinerProvingSet(ctx context.Context, maddr address.Address, ts *types.TipSet) ([]*api.ChainSectorInfo, error) {
|
||||
func (mca mca) StateMinerProvingSet(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
|
||||
ts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
|
||||
}
|
||||
return stmgr.GetMinerProvingSet(ctx, mca.sm, ts, maddr)
|
||||
}
|
||||
|
||||
@@ -484,7 +519,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
|
||||
return nil, xerrors.Errorf("chain get randomness: %w", err)
|
||||
}
|
||||
|
||||
mworker, err := a.StateMinerWorker(ctx, miner, ts)
|
||||
mworker, err := a.StateMinerWorker(ctx, miner, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
@@ -494,7 +529,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
|
||||
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
|
||||
pset, err := a.StateMinerProvingSet(ctx, miner, ts)
|
||||
pset, err := a.StateMinerProvingSet(ctx, miner, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load proving set for miner: %w", err)
|
||||
}
|
||||
@@ -519,12 +554,12 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
|
||||
return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err)
|
||||
}
|
||||
|
||||
pow, err := a.StateMinerPower(ctx, miner, ts)
|
||||
pow, err := a.StateMinerPower(ctx, miner, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to check power: %w", err)
|
||||
}
|
||||
|
||||
ssize, err := a.StateMinerSectorSize(ctx, miner, ts)
|
||||
ssize, err := a.StateMinerSectorSize(ctx, miner, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to look up miners sector size: %w", err)
|
||||
}
|
||||
@@ -611,7 +646,7 @@ func VerifyVRF(ctx context.Context, worker, miner address.Address, p uint64, inp
|
||||
Data: vrfproof,
|
||||
}
|
||||
|
||||
if err := sig.Verify(worker, vrfBase); err != nil {
|
||||
if err := sigs.Verify(sig, worker, vrfBase); err != nil {
|
||||
return xerrors.Errorf("vrf was invalid: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
+3
-3
@@ -254,7 +254,7 @@ func SetupStorageMarketActor(bs bstore.Blockstore, sroot cid.Cid, deals []actors
|
||||
return cid.Undef, xerrors.Errorf("set storage market actor: %w", err)
|
||||
}
|
||||
|
||||
return state.Flush()
|
||||
return state.Flush(context.TODO())
|
||||
}
|
||||
|
||||
type GenMinerCfg struct {
|
||||
@@ -563,7 +563,7 @@ func MakeGenesisBlock(bs bstore.Blockstore, sys *types.VMSyscalls, balances map[
|
||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err := state.Flush()
|
||||
stateroot, err := state.Flush(ctx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("flush state tree failed: %w", err)
|
||||
}
|
||||
@@ -673,5 +673,5 @@ func AdjustInitActorStartID(ctx context.Context, bs blockstore.Blockstore, state
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return tree.Flush()
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"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/sigs"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
@@ -94,7 +95,7 @@ func (ms *msgSet) add(m *types.SignedMessage) error {
|
||||
if _, has := ms.msgs[m.Message.Nonce]; has {
|
||||
if m.Cid() != ms.msgs[m.Message.Nonce].Cid() {
|
||||
log.Error("Add with duplicate nonce")
|
||||
return xerrors.Errorf("message to %s with nonce %d already in mpool")
|
||||
return xerrors.Errorf("message to %s with nonce %d already in mpool", m.Message.To, m.Message.Nonce)
|
||||
}
|
||||
}
|
||||
ms.msgs[m.Message.Nonce] = m
|
||||
@@ -303,7 +304,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error
|
||||
return ErrMessageValueTooHigh
|
||||
}
|
||||
|
||||
if err := m.Signature.Verify(m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
log.Warnf("mpooladd signature verification failed: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
)
|
||||
|
||||
@@ -95,7 +95,7 @@ func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain
|
||||
case notif := <-notifs:
|
||||
n := notif[len(notif)-1]
|
||||
|
||||
w, err := chain.ChainTipSetWeight(ctx, n.Val)
|
||||
w, err := chain.ChainTipSetWeight(ctx, n.Val.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -116,23 +117,29 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) {
|
||||
return &act, nil
|
||||
}
|
||||
|
||||
func (st *StateTree) Flush() (cid.Cid, error) {
|
||||
func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.Flush")
|
||||
defer span.End()
|
||||
|
||||
for addr, act := range st.actorcache {
|
||||
if err := st.root.Set(context.TODO(), string(addr.Bytes()), act); err != nil {
|
||||
if err := st.root.Set(ctx, string(addr.Bytes()), act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
st.actorcache = make(map[address.Address]*types.Actor)
|
||||
|
||||
if err := st.root.Flush(context.TODO()); err != nil {
|
||||
if err := st.root.Flush(ctx); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return st.Store.Put(context.TODO(), st.root)
|
||||
return st.Store.Put(ctx, st.root)
|
||||
}
|
||||
|
||||
func (st *StateTree) Snapshot() error {
|
||||
ss, err := st.Flush()
|
||||
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||
ctx, span := trace.StartSpan(ctx, "stateTree.SnapShot")
|
||||
defer span.End()
|
||||
|
||||
ss, err := st.Flush(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
@@ -60,7 +61,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if _, err := st.Flush(); err != nil {
|
||||
if _, err := st.Flush(context.TODO()); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -88,7 +89,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := st.Flush(); err != nil {
|
||||
if _, err := st.Flush(context.TODO()); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -8,13 +8,14 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight uint64) (*types.MessageReceipt, error) {
|
||||
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight uint64) (*api.MethodCall, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
|
||||
defer span.End()
|
||||
|
||||
@@ -54,14 +55,19 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
return nil, xerrors.Errorf("apply message failed: %w", err)
|
||||
}
|
||||
|
||||
var errs string
|
||||
if ret.ActorErr != nil {
|
||||
errs = ret.ActorErr.Error()
|
||||
log.Warnf("chain call failed: %s", ret.ActorErr)
|
||||
}
|
||||
return &ret.MessageReceipt, nil
|
||||
return &api.MethodCall{
|
||||
MessageReceipt: ret.MessageReceipt,
|
||||
Error: errs,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.MethodCall, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
+211
-1
@@ -3,14 +3,224 @@ package stmgr
|
||||
import (
|
||||
"context"
|
||||
|
||||
amt "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var ForksAtHeight = map[uint64]func(context.Context, *StateManager, cid.Cid) (cid.Cid, error){
|
||||
build.ForkBlizzardHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
log.Warnw("Executing blizzard fork logic")
|
||||
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("blizzard bug fix failed: %w", err)
|
||||
}
|
||||
return nstate, nil
|
||||
},
|
||||
build.ForkFrigidHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
log.Warnw("Executing frigid fork logic")
|
||||
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("frigid bug fix failed: %w", err)
|
||||
}
|
||||
return nstate, nil
|
||||
},
|
||||
build.ForkBootyBayHeight: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
log.Warnw("Executing booty bay fork logic")
|
||||
nstate, err := fixBlizzardAMTBug(ctx, sm, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("booty bay bug fix failed: %w", err)
|
||||
}
|
||||
return nstate, nil
|
||||
},
|
||||
build.ForkMissingSnowballs: func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
log.Warnw("Adding more snow to the world")
|
||||
nstate, err := fixTooFewSnowballs(ctx, sm, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("missing snowballs bug fix failed: %w", err)
|
||||
}
|
||||
return nstate, nil
|
||||
},
|
||||
}
|
||||
|
||||
func (sm *StateManager) handleStateForks(ctx context.Context, pstate cid.Cid, height, parentH uint64) (_ cid.Cid, err error) {
|
||||
for i := parentH; i < height; i++ {
|
||||
switch i {
|
||||
f, ok := ForksAtHeight[i]
|
||||
if ok {
|
||||
nstate, err := f(ctx, sm, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
pstate = nstate
|
||||
}
|
||||
}
|
||||
|
||||
return pstate, nil
|
||||
}
|
||||
|
||||
func fixTooFewSnowballs(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
|
||||
st, err := state.LoadStateTree(cst, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
spa, err := st.GetActor(actors.StoragePowerAddress)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to get storage power actor: %w", err)
|
||||
}
|
||||
|
||||
var spast actors.StoragePowerState
|
||||
if err := cst.Get(ctx, spa.Head, &spast); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
miners, err := actors.MinerSetList(ctx, cst, spast.Miners)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
sum := types.NewInt(0)
|
||||
for _, m := range miners {
|
||||
mact, err := st.GetActor(m)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting miner actor to fix: %w", err)
|
||||
}
|
||||
|
||||
var mstate actors.StorageMinerActorState
|
||||
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
if mstate.SlashedAt != 0 {
|
||||
continue
|
||||
}
|
||||
sum = types.BigAdd(sum, mstate.Power)
|
||||
}
|
||||
|
||||
spast.TotalStorage = sum
|
||||
nspahead, err := cst.Put(ctx, &spast)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
spa.Head = nspahead
|
||||
|
||||
return st.Flush(ctx)
|
||||
}
|
||||
|
||||
/*
|
||||
1) Iterate through each miner in the chain:
|
||||
1.1) Fixup their sector set and proving set
|
||||
1.2) Change their code cid to point to the new miner actor code
|
||||
*/
|
||||
func fixBlizzardAMTBug(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
|
||||
st, err := state.LoadStateTree(cst, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
spa, err := st.GetActor(actors.StoragePowerAddress)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to get storage power actor: %w", err)
|
||||
}
|
||||
|
||||
var spast actors.StoragePowerState
|
||||
if err := cst.Get(ctx, spa.Head, &spast); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
miners, err := actors.MinerSetList(ctx, cst, spast.Miners)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
for _, m := range miners {
|
||||
mact, err := st.GetActor(m)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting miner actor to fix: %w", err)
|
||||
}
|
||||
|
||||
nhead, err := fixMiner(ctx, cst, sm.cs.Blockstore(), mact.Head)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("fixing miner: %w", err)
|
||||
}
|
||||
|
||||
if nhead != mact.Head {
|
||||
log.Warnf("Miner %s had changes", m)
|
||||
}
|
||||
|
||||
mact.Head = nhead
|
||||
mact.Code = actors.StorageMiner2CodeCid
|
||||
|
||||
if err := st.SetActor(m, mact); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
|
||||
return st.Flush(ctx)
|
||||
}
|
||||
|
||||
func fixMiner(ctx context.Context, cst *hamt.CborIpldStore, bs blockstore.Blockstore, mscid cid.Cid) (cid.Cid, error) {
|
||||
var mstate actors.StorageMinerActorState
|
||||
if err := cst.Get(ctx, mscid, &mstate); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
amts := amt.WrapBlockstore(bs)
|
||||
|
||||
nsectors, err := amtFsck(amts, mstate.Sectors)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("error fsck'ing sector set: %w", err)
|
||||
}
|
||||
mstate.Sectors = nsectors
|
||||
|
||||
nproving, err := amtFsck(amts, mstate.ProvingSet)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("error fsck'ing proving set: %w", err)
|
||||
}
|
||||
mstate.ProvingSet = nproving
|
||||
|
||||
nmcid, err := cst.Put(ctx, &mstate)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to put modified miner state: %w", err)
|
||||
}
|
||||
|
||||
return nmcid, nil
|
||||
}
|
||||
|
||||
func amtFsck(s amt.Blocks, ss cid.Cid) (cid.Cid, error) {
|
||||
a, err := amt.LoadAMT(s, ss)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("could not load AMT: %w", a)
|
||||
}
|
||||
|
||||
b := amt.NewAMT(s)
|
||||
|
||||
err = a.ForEach(func(id uint64, data *cbg.Deferred) error {
|
||||
err := b.Set(id, data)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not copy at idx (%d): %w", id, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("could not copy: %w", err)
|
||||
}
|
||||
|
||||
nss, err := b.Flush()
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("could not flush: %w", err)
|
||||
}
|
||||
|
||||
return nss, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
package stmgr_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
. "github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
logging "github.com/ipfs/go-log"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
func init() {
|
||||
build.SectorSizes = []uint64{1024}
|
||||
build.MinimumMinerPower = 1024
|
||||
}
|
||||
|
||||
const testForkHeight = 40
|
||||
|
||||
type testActor struct {
|
||||
}
|
||||
|
||||
type testActorState struct {
|
||||
HasUpgraded uint64
|
||||
}
|
||||
|
||||
func (tas *testActorState) MarshalCBOR(w io.Writer) error {
|
||||
return cbg.CborWriteHeader(w, cbg.MajUnsignedInt, tas.HasUpgraded)
|
||||
}
|
||||
|
||||
func (tas *testActorState) UnmarshalCBOR(r io.Reader) error {
|
||||
t, v, err := cbg.CborReadHeader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type in test actor state")
|
||||
}
|
||||
tas.HasUpgraded = v
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ta *testActor) Exports() []interface{} {
|
||||
return []interface{}{
|
||||
1: ta.Constructor,
|
||||
2: ta.TestMethod,
|
||||
}
|
||||
}
|
||||
|
||||
func (ta *testActor) Constructor(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
||||
c, err := vmctx.Storage().Put(&testActorState{11})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", vmctx.Message().To.String())
|
||||
|
||||
return nil, vmctx.Storage().Commit(actors.EmptyCBOR, c)
|
||||
}
|
||||
|
||||
func (ta *testActor) TestMethod(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, aerrors.ActorError) {
|
||||
var st testActorState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &st); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vmctx.BlockHeight() > testForkHeight {
|
||||
if st.HasUpgraded != 55 {
|
||||
return nil, aerrors.Fatal("fork updating applied in wrong order")
|
||||
}
|
||||
} else {
|
||||
if st.HasUpgraded != 11 {
|
||||
return nil, aerrors.Fatal("fork updating happened too early")
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestForkHeightTriggers(t *testing.T) {
|
||||
logging.SetAllLoggers(logging.LevelInfo)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cg, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sm := NewStateManager(cg.ChainStore())
|
||||
|
||||
inv := vm.NewInvoker()
|
||||
|
||||
pref := cid.NewPrefixV1(cid.Raw, mh.IDENTITY)
|
||||
actcid, err := pref.Sum([]byte("testactor"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actors.BuiltInActors[actcid] = true
|
||||
|
||||
// predicting the address here... may break if other assumptions change
|
||||
taddr, err := address.NewIDAddress(1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, pstate cid.Cid) (cid.Cid, error) {
|
||||
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
|
||||
st, err := state.LoadStateTree(cst, pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
act, err := st.GetActor(taddr)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
var tas testActorState
|
||||
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
tas.HasUpgraded = 55
|
||||
|
||||
ns, err := cst.Put(ctx, &tas)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
act.Head = ns
|
||||
|
||||
if err := st.SetActor(taddr, act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return st.Flush(ctx)
|
||||
}
|
||||
|
||||
inv.Register(actcid, &testActor{}, &testActorState{})
|
||||
sm.SetVMConstructor(func(c cid.Cid, h uint64, r vm.Rand, a address.Address, b blockstore.Blockstore, s *types.VMSyscalls) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(c, h, r, a, b, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nvm.SetInvoker(inv)
|
||||
return nvm, nil
|
||||
})
|
||||
|
||||
cg.SetStateManager(sm)
|
||||
|
||||
var msgs []*types.SignedMessage
|
||||
|
||||
enc, err := actors.SerializeParams(&actors.ExecParams{Code: actcid})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
From: cg.Banker(),
|
||||
To: actors.InitAddress,
|
||||
Method: actors.IAMethods.Exec,
|
||||
Params: enc,
|
||||
GasLimit: types.NewInt(10000),
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
msgs = append(msgs, &types.SignedMessage{
|
||||
Signature: *sig,
|
||||
Message: *m,
|
||||
})
|
||||
|
||||
nonce := uint64(1)
|
||||
cg.GetMessages = func(cg *gen.ChainGen) ([]*types.SignedMessage, error) {
|
||||
if len(msgs) > 0 {
|
||||
fmt.Println("added construct method")
|
||||
m := msgs
|
||||
msgs = nil
|
||||
return m, nil
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
From: cg.Banker(),
|
||||
To: taddr,
|
||||
Method: 2,
|
||||
Params: nil,
|
||||
Nonce: nonce,
|
||||
GasLimit: types.NewInt(10000),
|
||||
GasPrice: types.NewInt(0),
|
||||
}
|
||||
nonce++
|
||||
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []*types.SignedMessage{
|
||||
&types.SignedMessage{
|
||||
Signature: *sig,
|
||||
Message: *m,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
_, err = cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
-1
@@ -18,6 +18,7 @@ import (
|
||||
bls "github.com/filecoin-project/filecoin-ffi"
|
||||
"github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -30,10 +31,12 @@ type StateManager struct {
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
stlk sync.Mutex
|
||||
newVM func(cid.Cid, uint64, vm.Rand, address.Address, blockstore.Blockstore, *types.VMSyscalls) (*vm.VM, error)
|
||||
}
|
||||
|
||||
func NewStateManager(cs *store.ChainStore) *StateManager {
|
||||
return &StateManager{
|
||||
newVM: vm.NewVM,
|
||||
cs: cs,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
compWait: make(map[string]chan struct{}),
|
||||
@@ -139,7 +142,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
|
||||
|
||||
r := store.NewChainRand(sm.cs, cids, blks[0].Height)
|
||||
|
||||
vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
vmi, err := sm.newVM(pstate, blks[0].Height, r, address.Undef, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
|
||||
}
|
||||
@@ -607,3 +610,36 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address,
|
||||
|
||||
return b[0], nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) error {
|
||||
tschain := []*types.TipSet{ts}
|
||||
for ts.Height() != 0 {
|
||||
next, err := sm.cs.LoadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tschain = append(tschain, next)
|
||||
ts = next
|
||||
}
|
||||
|
||||
lastState := tschain[len(tschain)-1].ParentState()
|
||||
for i := len(tschain) - 1; i >= 0; i-- {
|
||||
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())
|
||||
}
|
||||
st, _, err := sm.TipSetState(ctx, cur)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lastState = st
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, uint64, vm.Rand, address.Address, blockstore.Blockstore, *types.VMSyscalls) (*vm.VM, error)) {
|
||||
sm.newVM = nvm
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
amt2 "github.com/filecoin-project/go-amt-ipld/v2"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
|
||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||
@@ -10,7 +12,9 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
|
||||
amt "github.com/filecoin-project/go-amt-ipld"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
@@ -251,6 +255,21 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
|
||||
return mas.SlashedAt, nil
|
||||
}
|
||||
|
||||
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]uint64, error) {
|
||||
var mas actors.StorageMinerActorState
|
||||
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
ss, lerr := amt2.LoadAMT(amt.WrapBlockstore(sm.cs.Blockstore()), mas.Sectors)
|
||||
if lerr != nil {
|
||||
return nil, aerrors.HandleExternalError(lerr, "could not load proving set node")
|
||||
}
|
||||
|
||||
return mas.FaultSet.All(2 * ss.Count)
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId uint64, ts *types.TipSet) (*actors.OnChainDeal, error) {
|
||||
var state actors.StorageMarketState
|
||||
if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
|
||||
@@ -311,3 +330,37 @@ func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.C
|
||||
|
||||
return sset, nil
|
||||
}
|
||||
|
||||
func ComputeState(ctx context.Context, sm *StateManager, height uint64, msgs []*types.Message, ts *types.TipSet) (cid.Cid, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
base, _, err := sm.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids(), height)
|
||||
vmi, err := vm.NewVM(fstate, height, r, actors.NetworkAddress, sm.cs.Blockstore(), sm.cs.VMSys())
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
for i, msg := range msgs {
|
||||
ret, err := vmi.ApplyMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
|
||||
}
|
||||
if ret.ExitCode != 0 {
|
||||
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
}
|
||||
|
||||
return vmi.Flush(ctx)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -19,11 +21,16 @@ import (
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
car "github.com/ipfs/go-car"
|
||||
"github.com/ipfs/go-cid"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
format "github.com/ipfs/go-ipld-format"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
pubsub "github.com/whyrusleeping/pubsub"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -730,6 +737,30 @@ func (cs *ChainStore) readMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error)
|
||||
return blscids, secpkcids, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error) {
|
||||
fts, err := cs.LoadTipSet(from)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading from tipset %s: %w", from, err)
|
||||
}
|
||||
tts, err := cs.LoadTipSet(to)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading to tipset %s: %w", to, err)
|
||||
}
|
||||
revert, apply, err := cs.ReorgOps(fts, tts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error getting tipset branches: %w", err)
|
||||
}
|
||||
|
||||
path := make([]*HeadChange, len(revert)+len(apply))
|
||||
for i, r := range revert {
|
||||
path[i] = &HeadChange{Type: HCRevert, Val: r}
|
||||
}
|
||||
for j, i := 0, len(apply)-1; i >= 0; j, i = j+1, i-1 {
|
||||
path[j+len(revert)] = &HeadChange{Type: HCApply, Val: apply[i]}
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
blscids, secpkcids, err := cs.readMsgMetaCids(b.Messages)
|
||||
if err != nil {
|
||||
@@ -893,6 +924,84 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h uint64, ts *types
|
||||
}
|
||||
}
|
||||
|
||||
func recurseLinks(bs blockstore.Blockstore, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
data, err := bs.Get(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
top, err := cbg.ScanForLinks(bytes.NewReader(data.RawData()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
in = append(in, top...)
|
||||
for _, c := range top {
|
||||
var err error
|
||||
in, err = recurseLinks(bs, c, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, w io.Writer) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
bsrv := blockservice.New(cs.bs, nil)
|
||||
dserv := dag.NewDAGService(bsrv)
|
||||
return car.WriteCarWithWalker(ctx, dserv, ts.Cids(), w, func(nd format.Node) ([]*format.Link, error) {
|
||||
var b types.BlockHeader
|
||||
if err := b.UnmarshalCBOR(bytes.NewBuffer(nd.RawData())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []*format.Link
|
||||
for _, p := range b.Parents {
|
||||
out = append(out, &format.Link{Cid: p})
|
||||
}
|
||||
|
||||
cids, err := recurseLinks(cs.bs, b.Messages, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range cids {
|
||||
out = append(out, &format.Link{Cid: c})
|
||||
}
|
||||
|
||||
if b.Height == 0 {
|
||||
cids, err := recurseLinks(cs.bs, b.ParentStateRoot, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range cids {
|
||||
out = append(out, &format.Link{Cid: c})
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
|
||||
header, err := car.LoadCar(cs.Blockstore(), r)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loadcar failed: %w", err)
|
||||
}
|
||||
|
||||
root, err := cs.LoadTipSet(types.NewTipSetKey(header.Roots...))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
type chainRand struct {
|
||||
cs *ChainStore
|
||||
blks []cid.Cid
|
||||
@@ -910,3 +1019,11 @@ func NewChainRand(cs *ChainStore, blks []cid.Cid, bheight uint64) vm.Rand {
|
||||
func (cr *chainRand) GetRandomness(ctx context.Context, round int64) ([]byte, error) {
|
||||
return cr.cs.GetRandomness(ctx, cr.blks, round)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
} else {
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
}
|
||||
|
||||
+92
-12
@@ -4,8 +4,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
|
||||
peer "github.com/libp2p/go-libp2p-peer"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@@ -28,15 +31,9 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
continue
|
||||
}
|
||||
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
|
||||
log.Warnf("received block with too many messages over pubsub")
|
||||
continue
|
||||
blk, ok := msg.ValidatorData.(*types.BlockMsg)
|
||||
if !ok {
|
||||
log.Warnf("pubsub block validator passed on wrong type: %#v", msg.ValidatorData)
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -73,6 +70,89 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
}
|
||||
}
|
||||
|
||||
type BlockValidator struct {
|
||||
peers *lru.TwoQueueCache
|
||||
|
||||
killThresh int
|
||||
|
||||
recvBlocks *blockReceiptCache
|
||||
|
||||
blacklist func(peer.ID)
|
||||
}
|
||||
|
||||
func NewBlockValidator(blacklist func(peer.ID)) *BlockValidator {
|
||||
p, _ := lru.New2Q(4096)
|
||||
return &BlockValidator{
|
||||
peers: p,
|
||||
killThresh: 5,
|
||||
blacklist: blacklist,
|
||||
recvBlocks: newBlockReceiptCache(),
|
||||
}
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) flagPeer(p peer.ID) {
|
||||
v, ok := bv.peers.Get(p)
|
||||
if !ok {
|
||||
bv.peers.Add(p, int(1))
|
||||
return
|
||||
}
|
||||
|
||||
val := v.(int)
|
||||
|
||||
if val >= bv.killThresh {
|
||||
bv.blacklist(p)
|
||||
}
|
||||
|
||||
bv.peers.Add(p, v.(int)+1)
|
||||
}
|
||||
|
||||
func (bv *BlockValidator) Validate(ctx context.Context, pid peer.ID, msg *pubsub.Message) bool {
|
||||
blk, err := types.DecodeBlockMsg(msg.GetData())
|
||||
if err != nil {
|
||||
log.Error("got invalid block over pubsub: ", err)
|
||||
bv.flagPeer(pid)
|
||||
return false
|
||||
}
|
||||
|
||||
if len(blk.BlsMessages)+len(blk.SecpkMessages) > build.BlockMessageLimit {
|
||||
log.Warnf("received block with too many messages over pubsub")
|
||||
bv.flagPeer(pid)
|
||||
return false
|
||||
}
|
||||
|
||||
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 false
|
||||
}
|
||||
|
||||
msg.ValidatorData = blk
|
||||
return true
|
||||
}
|
||||
|
||||
type blockReceiptCache struct {
|
||||
blocks *lru.TwoQueueCache
|
||||
}
|
||||
|
||||
func newBlockReceiptCache() *blockReceiptCache {
|
||||
c, _ := lru.New2Q(8192)
|
||||
|
||||
return &blockReceiptCache{
|
||||
blocks: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (brc *blockReceiptCache) add(bcid cid.Cid) int {
|
||||
val, ok := brc.blocks.Get(bcid)
|
||||
if !ok {
|
||||
brc.blocks.Add(bcid, int(1))
|
||||
return 0
|
||||
}
|
||||
|
||||
brc.blocks.Add(bcid, val.(int)+1)
|
||||
return val.(int)
|
||||
}
|
||||
|
||||
func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool, msub *pubsub.Subscription) {
|
||||
for {
|
||||
msg, err := msub.Next(ctx)
|
||||
@@ -85,9 +165,9 @@ func HandleIncomingMessages(ctx context.Context, mpool *messagepool.MessagePool,
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := types.DecodeSignedMessage(msg.GetData())
|
||||
if err != nil {
|
||||
log.Errorf("got incorrectly formatted Message: %s", err)
|
||||
m, ok := msg.ValidatorData.(*types.SignedMessage)
|
||||
if !ok {
|
||||
log.Errorf("message validator func passed on wrong type: %#v", msg.ValidatorData)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
+23
-14
@@ -37,6 +37,7 @@ import (
|
||||
"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/sigs"
|
||||
)
|
||||
|
||||
var log = logging.Logger("chain")
|
||||
@@ -117,6 +118,10 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
}
|
||||
|
||||
for _, b := range fts.Blocks {
|
||||
if reason, ok := syncer.bad.Has(b.Cid()); ok {
|
||||
log.Warnf("InformNewHead called on block marked as bad: %s (reason: %s)", b.Cid(), reason)
|
||||
return false
|
||||
}
|
||||
if err := syncer.ValidateMsgMeta(b); err != nil {
|
||||
log.Warnf("invalid block received: %s", err)
|
||||
return false
|
||||
@@ -445,7 +450,7 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
||||
for _, b := range fts.Blocks {
|
||||
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
||||
if isPermanent(err) {
|
||||
syncer.bad.Add(b.Cid())
|
||||
syncer.bad.Add(b.Cid(), err.Error())
|
||||
}
|
||||
return xerrors.Errorf("validating block %s: %w", b.Cid(), err)
|
||||
}
|
||||
@@ -604,7 +609,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
}
|
||||
|
||||
blockSigCheck := async.Err(func() error {
|
||||
if err := h.CheckBlockSignature(ctx, waddr); err != nil {
|
||||
if err := sigs.CheckBlockSignature(h, ctx, waddr); err != nil {
|
||||
return xerrors.Errorf("check block signature failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -787,7 +792,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||
}
|
||||
|
||||
if err := m.Signature.Verify(kaddr, m.Message.Cid().Bytes()); err != nil {
|
||||
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
|
||||
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
||||
}
|
||||
|
||||
@@ -871,11 +876,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
|
||||
)
|
||||
|
||||
for _, pcid := range from.Parents().Cids() {
|
||||
if syncer.bad.Has(pcid) {
|
||||
if reason, ok := syncer.bad.Has(pcid); ok {
|
||||
for _, b := range from.Cids() {
|
||||
syncer.bad.Add(b)
|
||||
syncer.bad.Add(b, fmt.Sprintf("linked to %s", pcid))
|
||||
}
|
||||
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s)", from.Cids(), pcid)
|
||||
return nil, xerrors.Errorf("chain linked to block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), pcid, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,12 +898,12 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
|
||||
loop:
|
||||
for blockSet[len(blockSet)-1].Height() > untilHeight {
|
||||
for _, bc := range at.Cids() {
|
||||
if syncer.bad.Has(bc) {
|
||||
if reason, ok := syncer.bad.Has(bc); ok {
|
||||
for _, b := range acceptedBlocks {
|
||||
syncer.bad.Add(b)
|
||||
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s)", from.Cids(), bc)
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -941,12 +946,12 @@ loop:
|
||||
break loop
|
||||
}
|
||||
for _, bc := range b.Cids() {
|
||||
if syncer.bad.Has(bc) {
|
||||
if reason, ok := syncer.bad.Has(bc); ok {
|
||||
for _, b := range acceptedBlocks {
|
||||
syncer.bad.Add(b)
|
||||
syncer.bad.Add(b, fmt.Sprintf("chain contained %s", bc))
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s)", from.Cids(), bc)
|
||||
return nil, xerrors.Errorf("chain contained block marked previously as bad (%s, %s) (reason: %s)", from.Cids(), bc, reason)
|
||||
}
|
||||
}
|
||||
blockSet = append(blockSet, b)
|
||||
@@ -973,7 +978,7 @@ loop:
|
||||
// TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish?
|
||||
log.Warn("adding forked chain to our bad tipset cache")
|
||||
for _, b := range from.Blocks() {
|
||||
syncer.bad.Add(b.Cid())
|
||||
syncer.bad.Add(b.Cid(), "fork past finality")
|
||||
}
|
||||
}
|
||||
return nil, xerrors.Errorf("failed to sync fork: %w", err)
|
||||
@@ -1190,5 +1195,9 @@ func (syncer *Syncer) State() []SyncerState {
|
||||
}
|
||||
|
||||
func (syncer *Syncer) MarkBad(blk cid.Cid) {
|
||||
syncer.bad.Add(blk)
|
||||
syncer.bad.Add(blk, "manually marked bad")
|
||||
}
|
||||
|
||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||
return syncer.bad.Has(blk)
|
||||
}
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ func prepSyncTest(t testing.TB, h int) *syncTestUtil {
|
||||
|
||||
g, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
+18
-34
@@ -2,16 +2,12 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/minio/sha256-simd"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"go.opencensus.io/trace"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -36,31 +32,31 @@ type EPostProof struct {
|
||||
}
|
||||
|
||||
type BlockHeader struct {
|
||||
Miner address.Address
|
||||
Miner address.Address // 0
|
||||
|
||||
Ticket *Ticket
|
||||
Ticket *Ticket // 1
|
||||
|
||||
EPostProof EPostProof
|
||||
EPostProof EPostProof // 2
|
||||
|
||||
Parents []cid.Cid
|
||||
Parents []cid.Cid // 3
|
||||
|
||||
ParentWeight BigInt
|
||||
ParentWeight BigInt // 4
|
||||
|
||||
Height uint64
|
||||
Height uint64 // 5
|
||||
|
||||
ParentStateRoot cid.Cid
|
||||
ParentStateRoot cid.Cid // 6
|
||||
|
||||
ParentMessageReceipts cid.Cid
|
||||
ParentMessageReceipts cid.Cid // 7
|
||||
|
||||
Messages cid.Cid
|
||||
Messages cid.Cid // 8
|
||||
|
||||
BLSAggregate Signature
|
||||
BLSAggregate Signature // 9
|
||||
|
||||
Timestamp uint64
|
||||
Timestamp uint64 // 10
|
||||
|
||||
BlockSig *Signature
|
||||
BlockSig *Signature // 11
|
||||
|
||||
ForkSignaling uint64
|
||||
ForkSignaling uint64 // 12
|
||||
}
|
||||
|
||||
func (b *BlockHeader) ToStorageBlock() (block.Block, error) {
|
||||
@@ -116,22 +112,6 @@ func (blk *BlockHeader) SigningBytes() ([]byte, error) {
|
||||
return blkcopy.Serialize()
|
||||
}
|
||||
|
||||
func (blk *BlockHeader) CheckBlockSignature(ctx context.Context, worker address.Address) error {
|
||||
_, span := trace.StartSpan(ctx, "checkBlockSignature")
|
||||
defer span.End()
|
||||
|
||||
if blk.BlockSig == nil {
|
||||
return xerrors.New("block signature not present")
|
||||
}
|
||||
|
||||
sigb, err := blk.SigningBytes()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get block signing bytes: %w", err)
|
||||
}
|
||||
|
||||
return blk.BlockSig.Verify(worker, sigb)
|
||||
}
|
||||
|
||||
type MsgMeta struct {
|
||||
BlsMessages cid.Cid
|
||||
SecpkMessages cid.Cid
|
||||
@@ -223,7 +203,11 @@ func IsTicketWinner(partialTicket []byte, ssizeI uint64, snum uint64, totpow Big
|
||||
}
|
||||
|
||||
func ElectionPostChallengeCount(sectors uint64, faults uint64) uint64 {
|
||||
return sectorbuilder.ElectionPostChallengeCount(sectors, faults)
|
||||
if sectors-faults == 0 {
|
||||
return 0
|
||||
}
|
||||
// ceil(sectors / SectorChallengeRatioDiv)
|
||||
return (sectors-faults-1)/build.SectorChallengeRatioDiv + 1
|
||||
}
|
||||
|
||||
func (t *Ticket) Equals(ot *Ticket) bool {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
//+build cgo
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
bls "github.com/filecoin-project/filecoin-ffi"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-crypto"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func (s *Signature) Verify(addr address.Address, msg []byte) error {
|
||||
if s == nil {
|
||||
return xerrors.Errorf("signature is nil")
|
||||
}
|
||||
|
||||
if addr.Protocol() == address.ID {
|
||||
return fmt.Errorf("must resolve ID addresses before using them to verify a signature")
|
||||
}
|
||||
b2sum := blake2b.Sum256(msg)
|
||||
|
||||
switch s.Type {
|
||||
case KTSecp256k1:
|
||||
pubk, err := crypto.EcRecover(b2sum[:], s.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maybeaddr, err := address.NewSecp256k1Address(pubk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if addr != maybeaddr {
|
||||
return fmt.Errorf("signature did not match")
|
||||
}
|
||||
|
||||
return nil
|
||||
case KTBLS:
|
||||
digests := []bls.Digest{bls.Hash(bls.Message(msg))}
|
||||
|
||||
var pubk bls.PublicKey
|
||||
copy(pubk[:], addr.Payload())
|
||||
pubkeys := []bls.PublicKey{pubk}
|
||||
|
||||
var sig bls.Signature
|
||||
copy(sig[:], s.Data)
|
||||
|
||||
if !bls.Verify(&sig, digests, pubkeys) {
|
||||
return fmt.Errorf("bls signature failed to verify")
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot verify signature of unsupported type: %s", s.Type)
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,9 @@ func (ts *TipSet) Cids() []cid.Cid {
|
||||
}
|
||||
|
||||
func (ts *TipSet) Key() TipSetKey {
|
||||
if ts == nil {
|
||||
return EmptyTSK
|
||||
}
|
||||
return NewTipSetKey(ts.cids...)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var EmptyTSK = TipSetKey{}
|
||||
|
||||
// The length of a block header CID in bytes.
|
||||
var blockHeaderCIDLen int
|
||||
|
||||
@@ -90,6 +92,10 @@ func (k *TipSetKey) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k TipSetKey) IsEmpty() bool {
|
||||
return len(k.value) == 0
|
||||
}
|
||||
|
||||
func encodeKey(cids []cid.Cid) []byte {
|
||||
buffer := new(bytes.Buffer)
|
||||
for _, c := range cids {
|
||||
|
||||
@@ -2,11 +2,11 @@ package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-amt-ipld"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -46,14 +46,28 @@ type VMContext interface {
|
||||
Context() context.Context
|
||||
}
|
||||
|
||||
const CommitmentBytesLen = 32
|
||||
|
||||
type PublicSectorInfo struct {
|
||||
SectorID uint64
|
||||
CommR [CommitmentBytesLen]byte
|
||||
}
|
||||
|
||||
type Candidate struct {
|
||||
SectorID uint64
|
||||
PartialTicket [32]byte
|
||||
Ticket [32]byte
|
||||
SectorChallengeIndex uint64
|
||||
}
|
||||
|
||||
type VMSyscalls struct {
|
||||
ValidatePoRep func(context.Context, address.Address, uint64, []byte, []byte, []byte, []byte, []byte, uint64) (bool, aerrors.ActorError)
|
||||
VerifyFallbackPost func(ctx context.Context,
|
||||
sectorSize uint64,
|
||||
sectorInfo sectorbuilder.SortedPublicSectorInfo,
|
||||
sectorInfo []PublicSectorInfo,
|
||||
challengeSeed []byte,
|
||||
proof []byte,
|
||||
candidates []sectorbuilder.EPostCandidate,
|
||||
candidates []Candidate,
|
||||
proverID address.Address,
|
||||
faults uint64) (bool, error)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
func TestMessageFactory(t *testing.T) {
|
||||
|
||||
@@ -59,7 +59,7 @@ func NewState() *StateWrapper {
|
||||
if err != nil {
|
||||
panic(err) // Never returns error, the error return should be removed.
|
||||
}
|
||||
root, err := treeImpl.Flush()
|
||||
root, err := treeImpl.Flush(context.TODO())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (s *StateWrapper) Signer() *keyStore {
|
||||
|
||||
// Flushes a state tree to storage and sets this state's root to that tree's root CID.
|
||||
func (s *StateWrapper) flush(tree *state.StateTree) (err error) {
|
||||
s.stateRoot, err = tree.Flush()
|
||||
s.stateRoot, err = tree.Flush(context.TODO())
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+15
-10
@@ -23,20 +23,21 @@ type invoker struct {
|
||||
type invokeFunc func(act *types.Actor, vmctx types.VMContext, params []byte) ([]byte, aerrors.ActorError)
|
||||
type nativeCode []invokeFunc
|
||||
|
||||
func newInvoker() *invoker {
|
||||
func NewInvoker() *invoker {
|
||||
inv := &invoker{
|
||||
builtInCode: make(map[cid.Cid]nativeCode),
|
||||
builtInState: make(map[cid.Cid]reflect.Type),
|
||||
}
|
||||
|
||||
// add builtInCode using: register(cid, singleton)
|
||||
inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
|
||||
inv.register(actors.CronCodeCid, actors.CronActor{}, actors.CronActorState{})
|
||||
inv.register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
|
||||
inv.register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{})
|
||||
inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
|
||||
inv.register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
||||
inv.register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
||||
inv.Register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{})
|
||||
inv.Register(actors.CronCodeCid, actors.CronActor{}, actors.CronActorState{})
|
||||
inv.Register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{})
|
||||
inv.Register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{})
|
||||
inv.Register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{})
|
||||
inv.Register(actors.StorageMiner2CodeCid, actors.StorageMinerActor2{}, actors.StorageMinerActorState{})
|
||||
inv.Register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{})
|
||||
inv.Register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{})
|
||||
|
||||
return inv
|
||||
}
|
||||
@@ -59,7 +60,7 @@ func (inv *invoker) Invoke(act *types.Actor, vmctx types.VMContext, method uint6
|
||||
|
||||
}
|
||||
|
||||
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(err)
|
||||
@@ -160,7 +161,11 @@ func DecodeParams(b []byte, out interface{}) error {
|
||||
}
|
||||
|
||||
func DumpActorState(code cid.Cid, b []byte) (interface{}, error) {
|
||||
i := newInvoker() // TODO: register builtins in init block
|
||||
if code == actors.AccountCodeCid { // Account code special case
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
i := NewInvoker() // TODO: register builtins in init block
|
||||
|
||||
typ, ok := i.builtInState[code]
|
||||
if !ok {
|
||||
|
||||
+41
-1
@@ -2,6 +2,8 @@ package vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ffi "github.com/filecoin-project/filecoin-ffi"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
@@ -24,6 +26,44 @@ func Syscalls(verifier sectorbuilder.Verifier) *types.VMSyscalls {
|
||||
|
||||
return ok, nil
|
||||
},
|
||||
VerifyFallbackPost: verifier.VerifyFallbackPost,
|
||||
VerifyFallbackPost: func(ctx context.Context,
|
||||
sectorSize uint64,
|
||||
sectorInfo []types.PublicSectorInfo,
|
||||
challengeSeed []byte,
|
||||
proof []byte,
|
||||
candidates []types.Candidate,
|
||||
proverID address.Address,
|
||||
faults uint64) (bool, error) {
|
||||
|
||||
sI := make([]ffi.PublicSectorInfo, len(sectorInfo))
|
||||
for i, v := range sectorInfo {
|
||||
sI[i] = ffi.PublicSectorInfo{
|
||||
SectorID: v.SectorID,
|
||||
CommR: v.CommR,
|
||||
}
|
||||
}
|
||||
|
||||
cand := make([]sectorbuilder.EPostCandidate, len(candidates))
|
||||
for i, v := range candidates {
|
||||
cand[i] = sectorbuilder.EPostCandidate{
|
||||
SectorID: v.SectorID,
|
||||
PartialTicket: v.PartialTicket,
|
||||
Ticket: v.Ticket,
|
||||
SectorChallengeIndex: v.SectorChallengeIndex,
|
||||
}
|
||||
}
|
||||
|
||||
return verifier.VerifyFallbackPost(
|
||||
ctx,
|
||||
sectorSize,
|
||||
sectorbuilder.NewSortedPublicSectorInfo(sI),
|
||||
challengeSeed,
|
||||
proof,
|
||||
cand,
|
||||
proverID,
|
||||
faults,
|
||||
)
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
var log = logging.Logger("vm")
|
||||
@@ -196,7 +197,7 @@ func (vmctx *VMContext) VerifySignature(sig *types.Signature, act address.Addres
|
||||
act = kaddr
|
||||
}
|
||||
|
||||
if err := sig.Verify(act, data); err != nil {
|
||||
if err := sigs.Verify(sig, act, data); err != nil {
|
||||
return aerrors.New(2, "signature verification failed")
|
||||
}
|
||||
|
||||
@@ -327,7 +328,7 @@ func NewVM(base cid.Cid, height uint64, r Rand, maddr address.Address, cbs block
|
||||
buf: buf,
|
||||
blockHeight: height,
|
||||
blockMiner: maddr,
|
||||
inv: newInvoker(),
|
||||
inv: NewInvoker(),
|
||||
rand: r, // TODO: Probably should be a syscall
|
||||
Syscalls: syscalls,
|
||||
}, nil
|
||||
@@ -430,7 +431,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
}
|
||||
|
||||
st := vm.cstate
|
||||
if err := st.Snapshot(); err != nil {
|
||||
if err := st.Snapshot(ctx); err != nil {
|
||||
return nil, xerrors.Errorf("snapshot failed: %w", err)
|
||||
}
|
||||
|
||||
@@ -467,7 +468,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
|
||||
return nil, xerrors.Errorf("[from=%s,to=%s,n=%d,m=%d,h=%d] fatal error: %w", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
||||
}
|
||||
if actorErr != nil {
|
||||
log.Warnf("[from=%s,to=%s,n=%d,m=%d,h=%d] Send actor error: %+v", msg.From, msg.To, msg.Nonce, msg.Method, vm.blockHeight, actorErr)
|
||||
log.Warnw("Send actor error", "from", msg.From, "to", msg.To, "nonce", msg.Nonce, "method", msg.Method, "height", vm.blockHeight, "error", fmt.Sprintf("%+v", actorErr))
|
||||
}
|
||||
|
||||
var errcode uint8
|
||||
@@ -534,7 +535,7 @@ func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
from := vm.buf
|
||||
to := vm.buf.Read()
|
||||
|
||||
root, err := vm.cstate.Flush()
|
||||
root, err := vm.cstate.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||
}
|
||||
@@ -671,6 +672,10 @@ func Transfer(from, to *types.Actor, amt types.BigInt) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VM) SetInvoker(i *invoker) {
|
||||
vm.inv = i
|
||||
}
|
||||
|
||||
func deductFunds(act *types.Actor, amt types.BigInt) error {
|
||||
if act.Balance.LessThan(amt) {
|
||||
return fmt.Errorf("not enough funds")
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
const HalvingPeriodEpochs = 6 * 365 * 24 * 60 * 2
|
||||
|
||||
+16
-63
@@ -2,20 +2,16 @@ package wallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
bls "github.com/filecoin-project/filecoin-ffi"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-crypto"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
var log = logging.Logger("wallet")
|
||||
@@ -61,31 +57,7 @@ func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*t
|
||||
return nil, xerrors.Errorf("signing using key '%s': %w", addr.String(), types.ErrKeyInfoNotFound)
|
||||
}
|
||||
|
||||
switch ki.Type {
|
||||
case types.KTSecp256k1:
|
||||
b2sum := blake2b.Sum256(msg)
|
||||
sig, err := crypto.Sign(ki.PrivateKey, b2sum[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Signature{
|
||||
Type: types.KTSecp256k1,
|
||||
Data: sig,
|
||||
}, nil
|
||||
case types.KTBLS:
|
||||
var pk bls.PrivateKey
|
||||
copy(pk[:], ki.PrivateKey)
|
||||
sig := bls.PrivateKeySign(pk, msg)
|
||||
|
||||
return &types.Signature{
|
||||
Type: types.KTBLS,
|
||||
Data: sig[:],
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("cannot sign with unsupported key type: %q", ki.Type)
|
||||
}
|
||||
return sigs.Sign(ki.Type, ki.PrivateKey, msg)
|
||||
}
|
||||
|
||||
func (w *Wallet) findKey(addr address.Address) (*Key, error) {
|
||||
@@ -204,29 +176,15 @@ func (w *Wallet) SetDefault(a address.Address) error {
|
||||
}
|
||||
|
||||
func GenerateKey(typ string) (*Key, error) {
|
||||
switch typ {
|
||||
case types.KTSecp256k1:
|
||||
priv, err := crypto.GenerateKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ki := types.KeyInfo{
|
||||
Type: typ,
|
||||
PrivateKey: priv,
|
||||
}
|
||||
|
||||
return NewKey(ki)
|
||||
case types.KTBLS:
|
||||
priv := bls.PrivateKeyGenerate()
|
||||
ki := types.KeyInfo{
|
||||
Type: typ,
|
||||
PrivateKey: priv[:],
|
||||
}
|
||||
|
||||
return NewKey(ki)
|
||||
default:
|
||||
return nil, xerrors.Errorf("invalid key type: %s", typ)
|
||||
pk, err := sigs.Generate(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ki := types.KeyInfo{
|
||||
Type: typ,
|
||||
PrivateKey: pk,
|
||||
}
|
||||
return NewKey(ki)
|
||||
}
|
||||
|
||||
func (w *Wallet) GenerateKey(typ string) (address.Address, error) {
|
||||
@@ -277,28 +235,23 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
KeyInfo: keyinfo,
|
||||
}
|
||||
|
||||
var err error
|
||||
k.PublicKey, err = sigs.ToPublic(k.Type, k.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch k.Type {
|
||||
case types.KTSecp256k1:
|
||||
k.PublicKey = crypto.PublicKey(k.PrivateKey)
|
||||
|
||||
var err error
|
||||
k.Address, err = address.NewSecp256k1Address(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||
}
|
||||
|
||||
case types.KTBLS:
|
||||
var pk bls.PrivateKey
|
||||
copy(pk[:], k.PrivateKey)
|
||||
pub := bls.PrivateKeyPublicKey(pk)
|
||||
k.PublicKey = pub[:]
|
||||
|
||||
var err error
|
||||
k.Address, err = address.NewBLSAddress(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting BLS to address: %w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, xerrors.Errorf("unknown key type")
|
||||
}
|
||||
|
||||
+237
-3
@@ -1,9 +1,13 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -12,6 +16,7 @@ import (
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -26,6 +31,9 @@ var chainCmd = &cli.Command{
|
||||
chainSetHeadCmd,
|
||||
chainListCmd,
|
||||
chainGetCmd,
|
||||
chainBisectCmd,
|
||||
chainExportCmd,
|
||||
slashConsensusFault,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -172,6 +180,10 @@ var chainGetMsgCmd = &cli.Command{
|
||||
Name: "getmessage",
|
||||
Usage: "Get and print a message by its cid",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must pass a cid of a message to get")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -238,7 +250,7 @@ var chainSetHeadCmd = &cli.Command{
|
||||
ts, err = api.ChainGetGenesis(ctx)
|
||||
}
|
||||
if ts == nil && cctx.IsSet("epoch") {
|
||||
ts, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("epoch"), nil)
|
||||
ts, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("epoch"), types.EmptyTSK)
|
||||
}
|
||||
if ts == nil {
|
||||
ts, err = parseTipSet(api, ctx, cctx.Args().Slice())
|
||||
@@ -251,7 +263,7 @@ var chainSetHeadCmd = &cli.Command{
|
||||
return fmt.Errorf("must pass cids for tipset to set as head")
|
||||
}
|
||||
|
||||
if err := api.ChainSetHead(ctx, ts); err != nil {
|
||||
if err := api.ChainSetHead(ctx, ts.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -301,7 +313,7 @@ var chainListCmd = &cli.Command{
|
||||
var head *types.TipSet
|
||||
|
||||
if cctx.IsSet("height") {
|
||||
head, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("height"), nil)
|
||||
head, err = api.ChainGetTipSetByHeight(ctx, cctx.Uint64("height"), types.EmptyTSK)
|
||||
} else {
|
||||
head, err = api.ChainHead(ctx)
|
||||
}
|
||||
@@ -380,8 +392,230 @@ func printTipSet(format string, ts *types.TipSet) {
|
||||
blks += fmt.Sprintf("%s: %s,", b.Cid(), b.Miner)
|
||||
}
|
||||
blks += " ]"
|
||||
|
||||
sCids := make([]string, 0, len(blks))
|
||||
|
||||
for _, c := range ts.Cids() {
|
||||
sCids = append(sCids, c.String())
|
||||
}
|
||||
|
||||
format = strings.ReplaceAll(format, "<tipset>", strings.Join(sCids, ","))
|
||||
format = strings.ReplaceAll(format, "<blocks>", blks)
|
||||
format = strings.ReplaceAll(format, "<weight>", fmt.Sprint(ts.Blocks()[0].ParentWeight))
|
||||
|
||||
fmt.Println(format)
|
||||
}
|
||||
|
||||
var chainBisectCmd = &cli.Command{
|
||||
Name: "bisect",
|
||||
Usage: "bisect chain for an event",
|
||||
Description: `Bisect the chain state tree:
|
||||
|
||||
lotus chain bisect [min height] [max height] '1/2/3/state/path' 'shell command' 'args'
|
||||
|
||||
Returns the first tipset in which condition is true
|
||||
v
|
||||
[start] FFFFFFFTTT [end]
|
||||
|
||||
Example: find height at which deal ID 100 000 appeared
|
||||
- lotus chain bisect 1 32000 '@Ha:t03/1' jq -e '.[2] > 100000'
|
||||
|
||||
For special path elements see 'chain get' help
|
||||
`,
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() < 4 {
|
||||
return xerrors.New("need at least 4 args")
|
||||
}
|
||||
|
||||
start, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
end, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subPath := cctx.Args().Get(2)
|
||||
|
||||
highest, err := api.ChainGetTipSetByHeight(ctx, end, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prev := highest.Height()
|
||||
|
||||
for {
|
||||
mid := (start + end) / 2
|
||||
if end-start == 1 {
|
||||
mid = end
|
||||
start = end
|
||||
}
|
||||
|
||||
midTs, err := api.ChainGetTipSetByHeight(ctx, mid, highest.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := "/ipld/" + midTs.ParentState().String() + "/" + subPath
|
||||
fmt.Printf("* Testing %d (%d - %d) (%s): ", mid, start, end, path)
|
||||
|
||||
nd, err := api.ChainGetNode(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(nd, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, cctx.Args().Get(3), cctx.Args().Slice()[4:]...)
|
||||
cmd.Stdin = bytes.NewReader(b)
|
||||
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
|
||||
switch cmd.Run().(type) {
|
||||
case nil:
|
||||
// it's lower
|
||||
end = mid
|
||||
highest = midTs
|
||||
fmt.Println("true")
|
||||
case *exec.ExitError:
|
||||
start = mid
|
||||
fmt.Println("false")
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
if start == end {
|
||||
if strings.TrimSpace(out.String()) == "true" {
|
||||
fmt.Println(midTs.Height())
|
||||
} else {
|
||||
fmt.Println(prev)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
prev = mid
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var chainExportCmd = &cli.Command{
|
||||
Name: "export",
|
||||
Usage: "export chain to a car file",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify filename to export chain to")
|
||||
}
|
||||
|
||||
fi, err := os.Create(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
|
||||
ts, err := loadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream, err := api.ChainExport(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for b := range stream {
|
||||
_, err := fi.Write(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var slashConsensusFault = &cli.Command{
|
||||
Name: "slash-consensus",
|
||||
Usage: "Report consensus fault",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
c1, err := cid.Parse(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing cid 1: %w", err)
|
||||
}
|
||||
|
||||
b1, err := api.ChainGetBlock(ctx, c1)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting block 1: %w", err)
|
||||
}
|
||||
|
||||
c2, err := cid.Parse(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing cid 2: %w", err)
|
||||
}
|
||||
|
||||
b2, err := api.ChainGetBlock(ctx, c2)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting block 2: %w", err)
|
||||
}
|
||||
|
||||
def, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&actors.ArbitrateConsensusFaultParams{
|
||||
Block1: b1,
|
||||
Block2: b2,
|
||||
})
|
||||
|
||||
msg := &types.Message{
|
||||
To: actors.StoragePowerAddress,
|
||||
From: def,
|
||||
Value: types.NewInt(0),
|
||||
GasPrice: types.NewInt(1),
|
||||
GasLimit: types.NewInt(10000000),
|
||||
Method: actors.SPAMethods.ArbitrateConsensusFault,
|
||||
Params: params,
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(smsg.Cid())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
+1
-1
@@ -295,7 +295,7 @@ var clientQueryAskCmd = &cli.Command{
|
||||
To: maddr,
|
||||
From: maddr,
|
||||
Method: actors.MAMethods.GetPeerID,
|
||||
}, nil)
|
||||
}, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get peerID for miner: %w", err)
|
||||
}
|
||||
|
||||
@@ -202,6 +202,7 @@ var Commands = []*cli.Command{
|
||||
clientCmd,
|
||||
fetchParamCmd,
|
||||
mpoolCmd,
|
||||
multisigCmd,
|
||||
netCmd,
|
||||
paychCmd,
|
||||
sendCmd,
|
||||
@@ -209,4 +210,5 @@ var Commands = []*cli.Command{
|
||||
syncCmd,
|
||||
versionCmd,
|
||||
walletCmd,
|
||||
logCmd,
|
||||
}
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
var logCmd = &cli.Command{
|
||||
Name: "log",
|
||||
Usage: "Manage logging",
|
||||
Subcommands: []*cli.Command{
|
||||
logList,
|
||||
logSetLevel,
|
||||
},
|
||||
}
|
||||
|
||||
var logList = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List log systems",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
systems, err := api.LogList(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, system := range systems {
|
||||
fmt.Println(system)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var logSetLevel = &cli.Command{
|
||||
Name: "set-level",
|
||||
Usage: "Set log level",
|
||||
ArgsUsage: "<level>",
|
||||
Description: `Set the log level for logging systems:
|
||||
|
||||
The system flag can be specified multiple times.
|
||||
|
||||
eg) log set-level --system chain --system blocksync debug
|
||||
|
||||
Available Levels:
|
||||
debug
|
||||
info
|
||||
warn
|
||||
error
|
||||
|
||||
Environment Variables:
|
||||
GOLOG_LOG_LEVEL - Default log level for all log systems
|
||||
GOLOG_LOG_FMT - Change output log format (json, nocolor)
|
||||
GOLOG_FILE - Write logs to file in addition to stderr
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "system",
|
||||
Usage: "limit to log system",
|
||||
Value: &cli.StringSlice{},
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("level is required")
|
||||
}
|
||||
|
||||
systems := cctx.StringSlice("system")
|
||||
if len(systems) == 0 {
|
||||
var err error
|
||||
systems, err = api.LogList(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, system := range systems {
|
||||
if err := api.LogSetLevel(ctx, system, cctx.Args().First()); err != nil {
|
||||
return xerrors.Errorf("setting log level on %s: %w", system, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
+5
-4
@@ -33,7 +33,7 @@ var mpoolPending = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msgs, err := api.MpoolPending(ctx, nil)
|
||||
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -103,7 +103,7 @@ var mpoolStat = &cli.Command{
|
||||
return xerrors.Errorf("getting chain head: %w", err)
|
||||
}
|
||||
|
||||
msgs, err := api.MpoolPending(ctx, nil)
|
||||
msgs, err := api.MpoolPending(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -122,9 +122,10 @@ var mpoolStat = &cli.Command{
|
||||
bkt.msgs[v.Message.Nonce] = v
|
||||
}
|
||||
for a, bkt := range buckets {
|
||||
act, err := api.StateGetActor(ctx, a, ts)
|
||||
act, err := api.StateGetActor(ctx, a, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
fmt.Printf("%s, err: %s\n", a, err)
|
||||
continue
|
||||
}
|
||||
|
||||
cur := act.Nonce
|
||||
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
actors "github.com/filecoin-project/lotus/chain/actors"
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
var multisigCmd = &cli.Command{
|
||||
Name: "msig",
|
||||
Usage: "Interact with a multisig wallet",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "source",
|
||||
Usage: "specify the account to send propose from",
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
msigCreateCmd,
|
||||
msigInspectCmd,
|
||||
msigProposeCmd,
|
||||
msigApproveCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var msigCreateCmd = &cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create a new multisig wallet",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Uint64Flag{
|
||||
Name: "required",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "initial funds to give to multisig",
|
||||
Value: "0",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
var addrs []address.Address
|
||||
for _, a := range cctx.Args().Slice() {
|
||||
addr, err := address.NewFromString(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
|
||||
// get the address we're going to use to create the multisig (can be one of the above, as long as they have funds)
|
||||
sendAddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val := cctx.String("value")
|
||||
filval, err := types.ParseFIL(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
required := cctx.Uint64("required")
|
||||
if required == 0 {
|
||||
required = uint64(len(addrs))
|
||||
}
|
||||
|
||||
// Set up constructor parameters for multisig
|
||||
msigParams := &actors.MultiSigConstructorParams{
|
||||
Signers: addrs,
|
||||
Required: required,
|
||||
}
|
||||
|
||||
enc, err := actors.SerializeParams(msigParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||
execParams := &actors.ExecParams{
|
||||
Code: actors.MultisigCodeCid,
|
||||
Params: enc,
|
||||
}
|
||||
|
||||
enc, err = actors.SerializeParams(execParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// now we create the message to send this with
|
||||
msg := types.Message{
|
||||
To: actors.InitAddress,
|
||||
From: sendAddr,
|
||||
Method: actors.IAMethods.Exec,
|
||||
Params: enc,
|
||||
GasPrice: types.NewInt(1),
|
||||
GasLimit: types.NewInt(1000000),
|
||||
Value: types.BigInt(filval),
|
||||
}
|
||||
|
||||
// send the message out to the network
|
||||
smsg, err := api.MpoolPushMessage(ctx, &msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
fmt.Println("actor creation failed!")
|
||||
return err
|
||||
}
|
||||
|
||||
// get address of newly created miner
|
||||
msigaddr, err := address.NewFromBytes(wait.Receipt.Return)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Created new multisig: ", msigaddr.String())
|
||||
// TODO: maybe register this somewhere
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigInspectCmd = &cli.Command{
|
||||
Name: "inspect",
|
||||
Usage: "Inspect a multisig wallet",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify address of multisig to inspect")
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
act, err := api.StateGetActor(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj, err := api.ChainReadObj(ctx, act.Head)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var mstate actors.MultiSigActorState
|
||||
if err := mstate.UnmarshalCBOR(bytes.NewReader(obj)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Balance: %sfil\n", types.FIL(act.Balance))
|
||||
fmt.Printf("Threshold: %d / %d\n", mstate.Required, len(mstate.Signers))
|
||||
fmt.Println("Signers:")
|
||||
for _, s := range mstate.Signers {
|
||||
fmt.Printf("\t%s\n", s)
|
||||
}
|
||||
fmt.Println("Transactions: ", len(mstate.Transactions))
|
||||
if len(mstate.Transactions) > 0 {
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', 0)
|
||||
fmt.Fprintf(w, "ID\tState\tTo\tValue\tMethod\tParams\n")
|
||||
for _, tx := range mstate.Transactions {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%x\n", tx.TxID, state(tx), tx.To, types.FIL(tx.Value), tx.Method, tx.Params)
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func state(tx actors.MTransaction) string {
|
||||
if tx.Complete {
|
||||
return "done"
|
||||
}
|
||||
if tx.Canceled {
|
||||
return "canceled"
|
||||
}
|
||||
return "pending"
|
||||
}
|
||||
|
||||
var msigProposeCmd = &cli.Command{
|
||||
Name: "propose",
|
||||
Usage: "Propose a multisig transaction",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() < 3 {
|
||||
return fmt.Errorf("must pass multisig address, destination, and value")
|
||||
}
|
||||
|
||||
if cctx.Args().Len() > 3 && cctx.Args().Len() != 5 {
|
||||
return fmt.Errorf("usage: msig propose <msig addr> <desination> <value> [ <method> <params> ]")
|
||||
}
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dest, err := address.NewFromString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value, err := types.ParseFIL(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var method uint64
|
||||
var params []byte
|
||||
if cctx.Args().Len() == 5 {
|
||||
m, err := strconv.ParseUint(cctx.Args().Get(3), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
method = m
|
||||
|
||||
p, err := hex.DecodeString(cctx.Args().Get(4))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params = p
|
||||
}
|
||||
|
||||
enc, err := actors.SerializeParams(&actors.MultiSigProposeParams{
|
||||
To: dest,
|
||||
Value: types.BigInt(value),
|
||||
Method: method,
|
||||
Params: params,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("source") {
|
||||
f, err := address.NewFromString(cctx.String("source"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: msig,
|
||||
From: from,
|
||||
Value: types.NewInt(0),
|
||||
Method: actors.MultiSigMethods.Propose,
|
||||
Params: enc,
|
||||
GasLimit: types.NewInt(100000),
|
||||
GasPrice: types.NewInt(1),
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("send proposal in message: ", smsg.Cid())
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("proposal returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
_, v, err := cbg.CborReadHeader(bytes.NewReader(wait.Receipt.Return))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Transaction ID: %d\n", v)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var msigApproveCmd = &cli.Command{
|
||||
Name: "approve",
|
||||
Usage: "Approve a multisig transaction",
|
||||
Flags: []cli.Flag{},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() < 2 {
|
||||
return fmt.Errorf("must pass multisig address and transaction ID")
|
||||
}
|
||||
|
||||
msig, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enc, err := actors.SerializeParams(&actors.MultiSigTxID{
|
||||
TxID: txid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var from address.Address
|
||||
if cctx.IsSet("source") {
|
||||
f, err := address.NewFromString(cctx.String("source"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = f
|
||||
} else {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
from = defaddr
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: msig,
|
||||
From: from,
|
||||
Value: types.NewInt(0),
|
||||
Method: actors.MultiSigMethods.Approve,
|
||||
Params: enc,
|
||||
GasLimit: types.NewInt(100000),
|
||||
GasPrice: types.NewInt(1),
|
||||
}
|
||||
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("sent approval in message: ", smsg.Cid())
|
||||
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return fmt.Errorf("approve returned exit %d", wait.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ var fetchParamCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
sectorSize := uint64(sectorSizeInt)
|
||||
err = paramfetch.GetParams(build.ParametersJson, sectorSize)
|
||||
err = paramfetch.GetParams(build.ParametersJson(), sectorSize)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ var sendCmd = &cli.Command{
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "source",
|
||||
Usage: "optinally specifiy the account to send funds from",
|
||||
Usage: "optionally specify the account to send funds from",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
+392
-16
@@ -1,17 +1,24 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
actors "github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
@@ -37,6 +44,10 @@ var stateCmd = &cli.Command{
|
||||
stateSectorSizeCmd,
|
||||
stateReadStateCmd,
|
||||
stateListMessagesCmd,
|
||||
stateComputeStateCmd,
|
||||
stateCallCmd,
|
||||
stateGetDealSetCmd,
|
||||
stateWaitMsgCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -104,17 +115,20 @@ var statePowerCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
power, err := api.StateMinerPower(ctx, maddr, ts)
|
||||
power, err := api.StateMinerPower(ctx, maddr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := power.TotalPower
|
||||
tp := power.TotalPower
|
||||
if cctx.Args().Present() {
|
||||
res = power.MinerPower
|
||||
mp := power.MinerPower
|
||||
percI := types.BigDiv(types.BigMul(mp, types.NewInt(1000000)), tp)
|
||||
fmt.Printf("%s(%s) / %s(%s) ~= %0.4f%%\n", mp.String(), mp.SizeStr(), tp.String(), tp.SizeStr(), float64(percI.Int64())/10000)
|
||||
} else {
|
||||
fmt.Printf("%s(%s)\n", tp.String(), tp.SizeStr())
|
||||
}
|
||||
|
||||
fmt.Println(res.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -145,7 +159,7 @@ var stateSectorsCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
sectors, err := api.StateMinerSectors(ctx, maddr, ts)
|
||||
sectors, err := api.StateMinerSectors(ctx, maddr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -184,7 +198,7 @@ var stateProvingSetCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
sectors, err := api.StateMinerProvingSet(ctx, maddr, ts)
|
||||
sectors, err := api.StateMinerProvingSet(ctx, maddr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -246,7 +260,7 @@ var stateReplaySetCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := api.StateReplay(ctx, ts, mcid)
|
||||
res, err := api.StateReplay(ctx, ts.Key(), mcid)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("replay call failed: %w", err)
|
||||
}
|
||||
@@ -280,7 +294,7 @@ var statePledgeCollateralCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
coll, err := api.StatePledgeCollateral(ctx, ts)
|
||||
coll, err := api.StatePledgeCollateral(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -290,6 +304,47 @@ var statePledgeCollateralCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var stateGetDealSetCmd = &cli.Command{
|
||||
Name: "get-deal",
|
||||
Usage: "View on-chain deal info",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify miner to list sectors for")
|
||||
}
|
||||
|
||||
dealid, err := strconv.ParseUint(cctx.Args().First(), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing deal ID: %w", err)
|
||||
}
|
||||
|
||||
ts, err := loadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deal, err := api.StateMarketStorageDeal(ctx, dealid, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(deal, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateListMinersCmd = &cli.Command{
|
||||
Name: "list-miners",
|
||||
Usage: "list all miners in the network",
|
||||
@@ -307,7 +362,7 @@ var stateListMinersCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
miners, err := api.StateListMiners(ctx, ts)
|
||||
miners, err := api.StateListMiners(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -337,7 +392,7 @@ var stateListActorsCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
actors, err := api.StateListActors(ctx, ts)
|
||||
actors, err := api.StateListActors(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -376,7 +431,7 @@ var stateGetActorCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := api.StateGetActor(ctx, addr, ts)
|
||||
a, err := api.StateGetActor(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -417,7 +472,7 @@ var stateLookupIDCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
a, err := api.StateLookupID(ctx, addr, ts)
|
||||
a, err := api.StateLookupID(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -454,7 +509,7 @@ var stateSectorSizeCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
ssize, err := api.StateMinerSectorSize(ctx, addr, ts)
|
||||
ssize, err := api.StateMinerSectorSize(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -490,12 +545,12 @@ var stateReadStateCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
act, err := api.StateGetActor(ctx, addr, ts)
|
||||
act, err := api.StateGetActor(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
as, err := api.StateReadState(ctx, act, ts)
|
||||
as, err := api.StateReadState(ctx, act, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -526,6 +581,10 @@ var stateListMessagesCmd = &cli.Command{
|
||||
Name: "toheight",
|
||||
Usage: "don't look before given block height",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "cids",
|
||||
Usage: "print message CIDs instead of messages",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@@ -560,12 +619,17 @@ var stateListMessagesCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, err := api.StateListMessages(ctx, &types.Message{To: toa, From: froma}, ts, toh)
|
||||
msgs, err := api.StateListMessages(ctx, &types.Message{To: toa, From: froma}, ts.Key(), toh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, c := range msgs {
|
||||
if cctx.Bool("cids") {
|
||||
fmt.Println(c.String())
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := api.ChainGetMessage(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -580,3 +644,315 @@ var stateListMessagesCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateComputeStateCmd = &cli.Command{
|
||||
Name: "compute-state",
|
||||
Usage: "Perform state computations",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Uint64Flag{
|
||||
Name: "height",
|
||||
Usage: "set the height to compute state at",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "apply-mpool-messages",
|
||||
Usage: "apply messages from the mempool to the computed state",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
ts, err := loadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h := cctx.Uint64("height")
|
||||
if h == 0 {
|
||||
if ts == nil {
|
||||
head, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts = head
|
||||
}
|
||||
h = ts.Height()
|
||||
}
|
||||
|
||||
var msgs []*types.Message
|
||||
if cctx.Bool("apply-mpool-messages") {
|
||||
pmsgs, err := api.MpoolPending(ctx, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pmsgs, err = miner.SelectMessages(ctx, api.StateGetActor, ts, pmsgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, sm := range pmsgs {
|
||||
msgs = append(msgs, &sm.Message)
|
||||
}
|
||||
}
|
||||
|
||||
nstate, err := api.StateCompute(ctx, h, msgs, ts.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("computed state cid: ", nstate)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateWaitMsgCmd = &cli.Command{
|
||||
Name: "wait-msg",
|
||||
Usage: "Wait for a message to appear on chain",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "timeout",
|
||||
Value: "10m",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify message cid to wait for")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
msg, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mw, err := api.StateWaitMsg(ctx, msg)
|
||||
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: %s", mw.Receipt.GasUsed)
|
||||
fmt.Printf("Return: %x", mw.Receipt.Return)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stateCallCmd = &cli.Command{
|
||||
Name: "call",
|
||||
Usage: "Invoke a method on an actor locally",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "",
|
||||
Value: actors.NetworkAddress.String(),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "specify value field for invocation",
|
||||
Value: "0",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ret",
|
||||
Usage: "specify how to parse output (auto, raw, addr, big)",
|
||||
Value: "auto",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.Args().Len() < 2 {
|
||||
return fmt.Errorf("must specify at least actor and method to invoke")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
toa, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("given 'to' address %q was invalid: %w", cctx.Args().First(), err)
|
||||
}
|
||||
|
||||
froma, err := address.NewFromString(cctx.String("from"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("given 'from' address %q was invalid: %w", cctx.String("from"), err)
|
||||
}
|
||||
|
||||
ts, err := loadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
method, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("must pass method as a number")
|
||||
}
|
||||
|
||||
value, err := types.ParseFIL(cctx.String("value"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse 'value': %s", err)
|
||||
}
|
||||
|
||||
act, err := api.StateGetActor(ctx, toa, ts.Key())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup target actor: %s", err)
|
||||
}
|
||||
|
||||
params, err := parseParamsForMethod(act.Code, method, cctx.Args().Slice()[2:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse params: %s", err)
|
||||
}
|
||||
|
||||
ret, err := api.StateCall(ctx, &types.Message{
|
||||
From: froma,
|
||||
To: toa,
|
||||
Value: types.BigInt(value),
|
||||
GasLimit: types.NewInt(10000000000),
|
||||
GasPrice: types.NewInt(0),
|
||||
Method: method,
|
||||
Params: params,
|
||||
}, ts.Key())
|
||||
if err != nil {
|
||||
return fmt.Errorf("state call failed: %s", err)
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return fmt.Errorf("invocation failed (exit: %d): %s", ret.ExitCode, ret.Error)
|
||||
}
|
||||
|
||||
s, err := formatOutput(cctx.String("ret"), ret.Return)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to format output: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("return: %s\n", s)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func formatOutput(t string, val []byte) (string, error) {
|
||||
switch t {
|
||||
case "raw", "hex":
|
||||
return fmt.Sprintf("%x", val), nil
|
||||
case "address", "addr", "a":
|
||||
a, err := address.NewFromBytes(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return a.String(), nil
|
||||
case "big", "int", "bigint":
|
||||
bi := types.BigFromBytes(val)
|
||||
return bi.String(), nil
|
||||
case "fil":
|
||||
bi := types.FIL(types.BigFromBytes(val))
|
||||
return bi.String(), nil
|
||||
case "pid", "peerid", "peer":
|
||||
pid, err := peer.IDFromBytes(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return pid.Pretty(), nil
|
||||
case "auto":
|
||||
if len(val) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
a, err := address.NewFromBytes(val)
|
||||
if err == nil {
|
||||
return "address: " + a.String(), nil
|
||||
}
|
||||
|
||||
pid, err := peer.IDFromBytes(val)
|
||||
if err == nil {
|
||||
return "peerID: " + pid.Pretty(), nil
|
||||
}
|
||||
|
||||
bi := types.BigFromBytes(val)
|
||||
return "bigint: " + bi.String(), nil
|
||||
default:
|
||||
return "", fmt.Errorf("unrecognized output type: %q", t)
|
||||
}
|
||||
}
|
||||
|
||||
func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, error) {
|
||||
if len(args) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var f interface{}
|
||||
switch act {
|
||||
case actors.StorageMarketCodeCid:
|
||||
f = actors.StorageMarketActor{}.Exports()[method]
|
||||
case actors.StorageMinerCodeCid:
|
||||
f = actors.StorageMinerActor{}.Exports()[method]
|
||||
case actors.StoragePowerCodeCid:
|
||||
f = actors.StoragePowerActor{}.Exports()[method]
|
||||
case actors.MultisigCodeCid:
|
||||
f = actors.MultiSigActor{}.Exports()[method]
|
||||
case actors.PaymentChannelCodeCid:
|
||||
f = actors.PaymentChannelActor{}.Exports()[method]
|
||||
default:
|
||||
return nil, fmt.Errorf("the lazy devs didnt add support for that actor to this call yet")
|
||||
}
|
||||
|
||||
rf := reflect.TypeOf(f)
|
||||
if rf.NumIn() != 3 {
|
||||
return nil, fmt.Errorf("expected referenced method to have three arguments")
|
||||
}
|
||||
|
||||
paramObj := rf.In(2).Elem()
|
||||
if paramObj.NumField() != len(args) {
|
||||
return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField())
|
||||
}
|
||||
|
||||
p := reflect.New(paramObj)
|
||||
for i := 0; i < len(args); i++ {
|
||||
switch paramObj.Field(i).Type {
|
||||
case reflect.TypeOf(address.Address{}):
|
||||
a, err := address.NewFromString(args[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse address: %s", err)
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(a))
|
||||
case reflect.TypeOf(uint64(0)):
|
||||
val, err := strconv.ParseUint(args[i], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(val))
|
||||
case reflect.TypeOf(peer.ID("")):
|
||||
pid, err := peer.IDB58Decode(args[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse peer ID: %s", err)
|
||||
}
|
||||
p.Elem().Field(i).Set(reflect.ValueOf(pid))
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type for call (TODO): %s", paramObj.Field(i).Type)
|
||||
}
|
||||
}
|
||||
|
||||
m := p.Interface().(cbg.CBORMarshaler)
|
||||
buf := new(bytes.Buffer)
|
||||
if err := m.MarshalCBOR(buf); err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal param object: %s", err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
+36
@@ -20,6 +20,7 @@ var syncCmd = &cli.Command{
|
||||
syncStatusCmd,
|
||||
syncWaitCmd,
|
||||
syncMarkBadCmd,
|
||||
syncCheckBadCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -115,6 +116,41 @@ var syncMarkBadCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var syncCheckBadCmd = &cli.Command{
|
||||
Name: "check-bad",
|
||||
Usage: "check if the given block was marked bad, and for what reason",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
napi, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("must specify block cid to check")
|
||||
}
|
||||
|
||||
bcid, err := cid.Decode(cctx.Args().First())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode input as a cid: %s", err)
|
||||
}
|
||||
|
||||
reason, err := napi.SyncCheckBad(ctx, bcid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if reason == "" {
|
||||
fmt.Println("block was not marked as bad")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Println(reason)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func SyncWait(ctx context.Context, napi api.FullNode) error {
|
||||
for {
|
||||
state, err := napi.SyncState(ctx)
|
||||
|
||||
@@ -146,7 +146,7 @@ func main() {
|
||||
Miner: maddr,
|
||||
SectorSize: sectorSize,
|
||||
WorkerThreads: 2,
|
||||
Dir: sbdir,
|
||||
Paths: sectorbuilder.SimplePath(sbdir),
|
||||
}
|
||||
|
||||
if robench == "" {
|
||||
@@ -155,7 +155,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
if err := paramfetch.GetParams(build.ParametersJson, sectorSize); err != nil {
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), sectorSize); err != nil {
|
||||
return xerrors.Errorf("getting params: %w", err)
|
||||
}
|
||||
sb, err := sectorbuilder.New(cfg, mds)
|
||||
@@ -174,7 +174,7 @@ func main() {
|
||||
|
||||
r := rand.New(rand.NewSource(100 + int64(i)))
|
||||
|
||||
pi, err := sb.AddPiece(dataSize, i, r, nil)
|
||||
pi, err := sb.AddPiece(context.TODO(), dataSize, i, r, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -225,7 +225,7 @@ func main() {
|
||||
|
||||
if !c.Bool("skip-unseal") {
|
||||
log.Info("Unsealing sector")
|
||||
rc, err := sb.ReadPieceFromSealedSector(1, 0, dataSize, ticket.TicketBytes[:], commD[:])
|
||||
rc, err := sb.ReadPieceFromSealedSector(context.TODO(), 1, 0, dataSize, ticket.TicketBytes[:], commD[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -303,8 +303,8 @@ func main() {
|
||||
|
||||
epost2 := time.Now()
|
||||
|
||||
if !bytes.Equal(proof1, proof2) {
|
||||
log.Warn("separate epost calls returned different proof values (this might be bad)")
|
||||
if bytes.Equal(proof1, proof2) {
|
||||
log.Warn("separate epost calls returned the same proof values (this might be bad)")
|
||||
}
|
||||
|
||||
ok, err := sectorbuilder.ProofVerifier.VerifyElectionPost(context.TODO(), sectorSize, sinfos, challenge[:], proof1, candidates[:1], maddr)
|
||||
@@ -351,7 +351,9 @@ func main() {
|
||||
fmt.Printf("seal: preCommit: %s (%s)\n", bo.SealingResults[0].PreCommit, bps(bo.SectorSize, bo.SealingResults[0].PreCommit))
|
||||
fmt.Printf("seal: commit: %s (%s)\n", bo.SealingResults[0].Commit, bps(bo.SectorSize, bo.SealingResults[0].Commit))
|
||||
fmt.Printf("seal: verify: %s\n", bo.SealingResults[0].Verify)
|
||||
fmt.Printf("unseal: %s (%s)\n", bo.SealingResults[0].Unseal, bps(bo.SectorSize, bo.SealingResults[0].Unseal))
|
||||
if !c.Bool("skip-unseal") {
|
||||
fmt.Printf("unseal: %s (%s)\n", bo.SealingResults[0].Unseal, bps(bo.SectorSize, bo.SealingResults[0].Unseal))
|
||||
}
|
||||
}
|
||||
fmt.Printf("generate candidates: %s (%s)\n", bo.PostGenerateCandidates, bps(bo.SectorSize*uint64(len(bo.SealingResults)), bo.PostGenerateCandidates))
|
||||
fmt.Printf("compute epost proof (cold): %s\n", bo.PostEProofCold)
|
||||
|
||||
+333
-24
@@ -2,16 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"golang.org/x/xerrors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
_ "github.com/lib/pq"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -75,13 +77,22 @@ create table if not exists blocks
|
||||
eprof bytea,
|
||||
prand bytea,
|
||||
ep0partial bytea,
|
||||
ep0sector bigint not null,
|
||||
ep0challangei bigint not null
|
||||
ep0sector numeric not null,
|
||||
ep0challangei numeric not null
|
||||
);
|
||||
|
||||
create unique index if not exists block_cid_uindex
|
||||
on blocks (cid);
|
||||
|
||||
create materialized view if not exists state_heights
|
||||
as select distinct height, parentstateroot from blocks;
|
||||
|
||||
create unique index if not exists state_heights_uindex
|
||||
on state_heights (height);
|
||||
|
||||
create index if not exists state_heights_height_index
|
||||
on state_heights (parentstateroot);
|
||||
|
||||
create table if not exists id_address_map
|
||||
(
|
||||
id text not null,
|
||||
@@ -117,6 +128,38 @@ create index if not exists id_address_map_address_index
|
||||
create index if not exists id_address_map_id_index
|
||||
on id_address_map (id);
|
||||
|
||||
create or replace function actor_tips(epoch bigint)
|
||||
returns table (id text,
|
||||
code text,
|
||||
head text,
|
||||
nonce int,
|
||||
balance text,
|
||||
stateroot text,
|
||||
height bigint,
|
||||
parentstateroot text) as
|
||||
$body$
|
||||
select distinct on (id) * from actors
|
||||
inner join state_heights sh on sh.parentstateroot = stateroot
|
||||
where height < $1
|
||||
order by id, height desc;
|
||||
$body$ language sql;
|
||||
|
||||
create table if not exists actor_states
|
||||
(
|
||||
head text not null,
|
||||
code text not null,
|
||||
state json not null
|
||||
);
|
||||
|
||||
create unique index if not exists actor_states_head_code_uindex
|
||||
on actor_states (head, code);
|
||||
|
||||
create index if not exists actor_states_head_index
|
||||
on actor_states (head);
|
||||
|
||||
create index if not exists actor_states_code_head_index
|
||||
on actor_states (head, code);
|
||||
|
||||
create table if not exists messages
|
||||
(
|
||||
cid text not null
|
||||
@@ -124,11 +167,11 @@ create table if not exists messages
|
||||
primary key,
|
||||
"from" text not null,
|
||||
"to" text not null,
|
||||
nonce int not null,
|
||||
nonce bigint not null,
|
||||
value text not null,
|
||||
gasprice int not null,
|
||||
gaslimit int not null,
|
||||
method int,
|
||||
gasprice bigint not null,
|
||||
gaslimit bigint not null,
|
||||
method bigint,
|
||||
params bytea
|
||||
);
|
||||
|
||||
@@ -184,7 +227,7 @@ create table if not exists miner_heads
|
||||
worker text not null,
|
||||
peerid text not null,
|
||||
sectorsize bigint not null,
|
||||
power bigint not null,
|
||||
power decimal not null,
|
||||
active bool,
|
||||
ppe bigint not null,
|
||||
slashed_at bigint not null,
|
||||
@@ -192,6 +235,104 @@ create table if not exists miner_heads
|
||||
primary key (head, addr)
|
||||
);
|
||||
|
||||
create or replace function miner_tips(epoch bigint)
|
||||
returns table (head text,
|
||||
addr text,
|
||||
stateroot text,
|
||||
sectorset text,
|
||||
setsize decimal,
|
||||
provingset text,
|
||||
provingsize decimal,
|
||||
owner text,
|
||||
worker text,
|
||||
peerid text,
|
||||
sectorsize bigint,
|
||||
power decimal,
|
||||
active bool,
|
||||
ppe bigint,
|
||||
slashed_at bigint,
|
||||
height bigint,
|
||||
parentstateroot text) as
|
||||
$body$
|
||||
select distinct on (addr) * from miner_heads
|
||||
inner join state_heights sh on sh.parentstateroot = stateroot
|
||||
where height < $1
|
||||
order by addr, height desc;
|
||||
$body$ language sql;
|
||||
|
||||
create table if not exists deals
|
||||
(
|
||||
id int not null,
|
||||
pieceRef text not null,
|
||||
pieceSize bigint not null,
|
||||
client text not null,
|
||||
provider text not null,
|
||||
expiration decimal not null,
|
||||
duration decimal not null,
|
||||
epochPrice decimal not null,
|
||||
collateral decimal not null,
|
||||
constraint deals_pk
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
create index if not exists deals_client_index
|
||||
on deals (client);
|
||||
|
||||
create unique index if not exists deals_id_uindex
|
||||
on deals (id);
|
||||
|
||||
create index if not exists deals_pieceRef_index
|
||||
on deals (pieceRef);
|
||||
|
||||
create index if not exists deals_provider_index
|
||||
on deals (provider);
|
||||
|
||||
create table if not exists deal_activations
|
||||
(
|
||||
deal bigint not null
|
||||
constraint deal_activations_deals_id_fk
|
||||
references deals,
|
||||
activation_epoch bigint not null,
|
||||
constraint deal_activations_pk
|
||||
primary key (deal)
|
||||
);
|
||||
|
||||
create index if not exists deal_activations_activation_epoch_index
|
||||
on deal_activations (activation_epoch);
|
||||
|
||||
create unique index if not exists deal_activations_deal_uindex
|
||||
on deal_activations (deal);
|
||||
|
||||
create table if not exists blocks_challenges
|
||||
(
|
||||
block text not null
|
||||
constraint blocks_challenges_pk_2
|
||||
primary key
|
||||
constraint blocks_challenges_blocks_cid_fk
|
||||
references blocks,
|
||||
index bigint not null,
|
||||
sector_id bigint not null,
|
||||
partial bytea not null,
|
||||
candidate bigint not null,
|
||||
constraint blocks_challenges_pk
|
||||
unique (block, index)
|
||||
);
|
||||
|
||||
create index if not exists blocks_challenges_block_index
|
||||
on blocks_challenges (block);
|
||||
|
||||
create index if not exists blocks_challenges_block_candidate_index
|
||||
on blocks_challenges (block,candidate);
|
||||
|
||||
create index if not exists blocks_challenges_block_index_index
|
||||
on blocks_challenges (block, index);
|
||||
|
||||
create index if not exists blocks_challenges_candidate_index
|
||||
on blocks_challenges (candidate);
|
||||
|
||||
create index if not exists blocks_challenges_index_index
|
||||
on blocks_challenges (index);
|
||||
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -226,17 +367,15 @@ func (st *storage) hasList() map[cid.Cid]struct{} {
|
||||
return out
|
||||
}
|
||||
|
||||
func (st *storage) storeActors(actors map[address.Address]map[types.Actor]cid.Cid) error {
|
||||
func (st *storage) storeActors(actors map[address.Address]map[types.Actor]actorInfo) error {
|
||||
// Basic
|
||||
tx, err := st.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := tx.Exec(`
|
||||
|
||||
create temp table a (like actors excluding constraints) on commit drop;
|
||||
|
||||
|
||||
`); err != nil {
|
||||
create temp table a (like actors excluding constraints) on commit drop;
|
||||
`); err != nil {
|
||||
return xerrors.Errorf("prep temp: %w", err)
|
||||
}
|
||||
|
||||
@@ -247,7 +386,7 @@ create temp table a (like actors excluding constraints) on commit drop;
|
||||
|
||||
for addr, acts := range actors {
|
||||
for act, st := range acts {
|
||||
if _, err := stmt.Exec(addr.String(), act.Code.String(), act.Head.String(), act.Nonce, act.Balance.String(), st.String()); err != nil {
|
||||
if _, err := stmt.Exec(addr.String(), act.Code.String(), act.Head.String(), act.Nonce, act.Balance.String(), st.stateroot.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -261,7 +400,47 @@ create temp table a (like actors excluding constraints) on commit drop;
|
||||
return xerrors.Errorf("actor put: %w", err)
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// States
|
||||
tx, err = st.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := tx.Exec(`
|
||||
create temp table a (like actor_states excluding constraints) on commit drop;
|
||||
`); err != nil {
|
||||
return xerrors.Errorf("prep temp: %w", err)
|
||||
}
|
||||
|
||||
stmt, err = tx.Prepare(`copy a (head, code, state) from stdin `)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, acts := range actors {
|
||||
for act, st := range acts {
|
||||
if _, err := stmt.Exec(act.Head.String(), act.Code.String(), st.state); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := stmt.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`insert into actor_states select * from a on conflict do nothing `); err != nil {
|
||||
return xerrors.Errorf("actor put: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *storage) storeMiners(miners map[minerKey]*minerInfo) error {
|
||||
@@ -329,6 +508,7 @@ func (st *storage) storeHeaders(bhs map[cid.Cid]*types.BlockHeader, sync bool) e
|
||||
create temp table tbp (like block_parents excluding constraints) on commit drop;
|
||||
create temp table bs (like blocks_synced excluding constraints) on commit drop;
|
||||
create temp table b (like blocks excluding constraints) on commit drop;
|
||||
create temp table c (like blocks_challenges excluding constraints) on commit drop;
|
||||
|
||||
|
||||
`); err != nil {
|
||||
@@ -379,7 +559,7 @@ create temp table b (like blocks excluding constraints) on commit drop;
|
||||
}
|
||||
}
|
||||
|
||||
stmt2, err := tx.Prepare(`copy b (cid, parentWeight, parentStateRoot, height, miner, "timestamp", vrfproof, tickets, eprof, prand, ep0partial, ep0sector, ep0challangei) from stdin `)
|
||||
stmt2, err := tx.Prepare(`copy b (cid, parentWeight, parentStateRoot, height, miner, "timestamp", vrfproof, tickets, eprof, prand, ep0partial, ep0sector, ep0challangei) from stdin`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -416,10 +596,36 @@ create temp table b (like blocks excluding constraints) on commit drop;
|
||||
return xerrors.Errorf("blk put: %w", err)
|
||||
}
|
||||
|
||||
stmt3, err := tx.Prepare(`copy c (block, index, sector_id, partial, candidate) from stdin`)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("s3 create: %w", err)
|
||||
}
|
||||
for _, bh := range bhs {
|
||||
for index, c := range bh.EPostProof.Candidates {
|
||||
if _, err := stmt3.Exec(
|
||||
bh.Cid().String(),
|
||||
index,
|
||||
c.SectorID,
|
||||
c.Partial,
|
||||
c.ChallengeIndex); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := stmt3.Close(); err != nil {
|
||||
return xerrors.Errorf("s2 close: %w", err)
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`insert into blocks_challenges select * from c on conflict do nothing `); err != nil {
|
||||
return xerrors.Errorf("blk put: %w", err)
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("commit: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -602,11 +808,8 @@ func (st *storage) storeMpoolInclusions(msgs []api.MpoolUpdate) error {
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
|
||||
create temp table mi (like mpool_messages excluding constraints) on commit drop;
|
||||
|
||||
|
||||
`); err != nil {
|
||||
create temp table mi (like mpool_messages excluding constraints) on commit drop;
|
||||
`); err != nil {
|
||||
return xerrors.Errorf("prep temp: %w", err)
|
||||
}
|
||||
|
||||
@@ -639,6 +842,112 @@ create temp table mi (like mpool_messages excluding constraints) on commit drop;
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (st *storage) storeDeals(deals map[string]actors.OnChainDeal) error {
|
||||
tx, err := st.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
create temp table d (like deals excluding constraints) on commit drop;
|
||||
`); err != nil {
|
||||
return xerrors.Errorf("prep temp: %w", err)
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(`copy d (id, pieceref, piecesize, client, "provider", expiration, duration, epochprice, collateral) from stdin `)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var bloat uint64
|
||||
|
||||
for id, deal := range deals {
|
||||
if len(deal.PieceRef) > 40 {
|
||||
bloat += uint64(len(deal.PieceRef))
|
||||
continue
|
||||
}
|
||||
if _, err := stmt.Exec(
|
||||
id,
|
||||
hex.EncodeToString(deal.PieceRef),
|
||||
deal.PieceSize,
|
||||
deal.Client.String(),
|
||||
deal.Provider.String(),
|
||||
fmt.Sprint(deal.ProposalExpiration),
|
||||
fmt.Sprint(deal.Duration),
|
||||
deal.StoragePricePerEpoch.String(),
|
||||
deal.StorageCollateral.String(),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if bloat > 0 {
|
||||
log.Warnf("deal PieceRefs had %d bytes of garbage", bloat)
|
||||
}
|
||||
|
||||
if err := stmt.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`insert into deals select * from d on conflict do nothing `); err != nil {
|
||||
return xerrors.Errorf("actor put: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Activations
|
||||
|
||||
tx, err = st.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
create temp table d (like deal_activations excluding constraints) on commit drop;
|
||||
`); err != nil {
|
||||
return xerrors.Errorf("prep temp: %w", err)
|
||||
}
|
||||
|
||||
stmt, err = tx.Prepare(`copy d (deal, activation_epoch) from stdin `)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for id, deal := range deals {
|
||||
if deal.ActivationEpoch == 0 {
|
||||
continue
|
||||
}
|
||||
if _, err := stmt.Exec(
|
||||
id,
|
||||
deal.ActivationEpoch,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := stmt.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`insert into deal_activations select * from d on conflict do nothing `); err != nil {
|
||||
return xerrors.Errorf("actor put: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *storage) refreshViews() error {
|
||||
if _, err := st.db.Exec(`refresh materialized view state_heights`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *storage) close() error {
|
||||
return st.db.Close()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
@@ -40,7 +41,6 @@ func runSyncer(ctx context.Context, api api.FullNode, st *storage) {
|
||||
go subMpool(ctx, api, st)
|
||||
go subBlocks(ctx, api, st)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -60,9 +60,14 @@ type minerInfo struct {
|
||||
psize uint64
|
||||
}
|
||||
|
||||
type actorInfo struct {
|
||||
stateroot cid.Cid
|
||||
state string
|
||||
}
|
||||
|
||||
func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipSet) {
|
||||
addresses := map[address.Address]address.Address{}
|
||||
actors := map[address.Address]map[types.Actor]cid.Cid{}
|
||||
actors := map[address.Address]map[types.Actor]actorInfo{}
|
||||
var alk sync.Mutex
|
||||
|
||||
log.Infof("Getting synced block list")
|
||||
@@ -138,24 +143,38 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
|
||||
if len(bh.Parents) == 0 { // genesis case
|
||||
ts, err := types.NewTipSet([]*types.BlockHeader{bh})
|
||||
aadrs, err := api.StateListActors(ctx, ts)
|
||||
aadrs, err := api.StateListActors(ctx, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
par(50, aadrs, func(addr address.Address) {
|
||||
act, err := api.StateGetActor(ctx, addr, ts)
|
||||
act, err := api.StateGetActor(ctx, addr, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
ast, err := api.StateReadState(ctx, act, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
state, err := json.Marshal(ast.State)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
alk.Lock()
|
||||
_, ok := actors[addr]
|
||||
if !ok {
|
||||
actors[addr] = map[types.Actor]cid.Cid{}
|
||||
actors[addr] = map[types.Actor]actorInfo{}
|
||||
}
|
||||
actors[addr][*act] = actorInfo{
|
||||
stateroot: bh.ParentStateRoot,
|
||||
state: string(state),
|
||||
}
|
||||
actors[addr][*act] = bh.ParentStateRoot
|
||||
addresses[addr] = address.Undef
|
||||
alk.Unlock()
|
||||
})
|
||||
@@ -181,13 +200,26 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
ast, err := api.StateReadState(ctx, &act, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
state, err := json.Marshal(ast.State)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
alk.Lock()
|
||||
_, ok := actors[addr]
|
||||
if !ok {
|
||||
actors[addr] = map[types.Actor]cid.Cid{}
|
||||
actors[addr] = map[types.Actor]actorInfo{}
|
||||
}
|
||||
actors[addr][act] = actorInfo{
|
||||
stateroot: bh.ParentStateRoot,
|
||||
state: string(state),
|
||||
}
|
||||
actors[addr][act] = bh.ParentStateRoot
|
||||
addresses[addr] = address.Undef
|
||||
alk.Unlock()
|
||||
}
|
||||
@@ -205,7 +237,7 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
}
|
||||
|
||||
par(50, kmaparr(addresses), func(addr address.Address) {
|
||||
raddr, err := api.StateLookupID(ctx, addr, nil)
|
||||
raddr, err := api.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
return
|
||||
@@ -221,14 +253,14 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
|
||||
for addr, m := range actors {
|
||||
for actor, c := range m {
|
||||
if actor.Code != actors2.StorageMinerCodeCid {
|
||||
if !(actor.Code == actors2.StorageMinerCodeCid || actor.Code == actors2.StorageMiner2CodeCid) {
|
||||
continue
|
||||
}
|
||||
|
||||
miners[minerKey{
|
||||
addr: addr,
|
||||
act: actor,
|
||||
stateroot: c,
|
||||
stateroot: c.stateroot,
|
||||
}] = &minerInfo{}
|
||||
}
|
||||
}
|
||||
@@ -236,7 +268,7 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
par(50, kvmaparr(miners), func(it func() (minerKey, *minerInfo)) {
|
||||
k, info := it()
|
||||
|
||||
sszs, err := api.StateMinerSectorCount(ctx, k.addr, nil)
|
||||
sszs, err := api.StateMinerSectorCount(ctx, k.addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
@@ -322,6 +354,29 @@ func syncHead(ctx context.Context, api api.FullNode, st *storage, ts *types.TipS
|
||||
log.Infof("Sync stage done")
|
||||
}
|
||||
|
||||
log.Infof("Get deals")
|
||||
|
||||
// TODO: incremental, gather expired
|
||||
deals, err := api.StateMarketDeals(ctx, ts.Key())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Store deals")
|
||||
|
||||
if err := st.storeDeals(deals); err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Refresh views")
|
||||
|
||||
if err := st.refreshViews(); err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Sync done")
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,8 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if owner.Protocol() != address.BLS {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("Miner address must use BLS"))
|
||||
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
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
collateral, err := h.api.StatePledgeCollateral(r.Context(), nil)
|
||||
collateral, err := h.api.StatePledgeCollateral(r.Context(), types.EmptyTSK)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
@@ -275,7 +276,7 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
|
||||
createStorageMinerMsg := &types.Message{
|
||||
To: actors.StoragePowerAddress,
|
||||
From: h.from,
|
||||
Value: collateral,
|
||||
Value: types.BigAdd(collateral, types.BigDiv(collateral, types.NewInt(100))),
|
||||
|
||||
Method: actors.SPAMethods.CreateStorageMiner,
|
||||
Params: params,
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/jsonrpc"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
type CidWindow [][]cid.Cid
|
||||
|
||||
var log = logging.Logger("lotus-health")
|
||||
|
||||
func main() {
|
||||
logging.SetLogLevel("*", "INFO")
|
||||
|
||||
log.Info("Starting health agent")
|
||||
|
||||
local := []*cli.Command{
|
||||
watchHeadCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
Name: "lotus-health",
|
||||
Usage: "Tools for monitoring lotus daemon health",
|
||||
Version: build.UserVersion,
|
||||
Commands: local,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
EnvVars: []string{"LOTUS_PATH"},
|
||||
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var watchHeadCmd = &cli.Command{
|
||||
Name: "watch-head",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "threshold",
|
||||
Value: 3,
|
||||
Usage: "number of times head remains unchanged before failing health check",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "interval",
|
||||
Value: build.BlockDelay,
|
||||
Usage: "interval in seconds between chain head checks",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "systemd-unit",
|
||||
Value: "lotus-daemon.service",
|
||||
Usage: "systemd unit name to restart on health check failure",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "api-timeout",
|
||||
Value: build.BlockDelay,
|
||||
Usage: "timeout between API retries",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "api-retries",
|
||||
Value: 8,
|
||||
Usage: "number of API retry attemps",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
var headCheckWindow CidWindow
|
||||
threshold := c.Int("threshold")
|
||||
interval := time.Duration(c.Int("interval")) * time.Second
|
||||
name := c.String("systemd-unit")
|
||||
apiRetries := c.Int("api-retries")
|
||||
apiTimeout := time.Duration(c.Int("api-timeout")) * time.Second
|
||||
|
||||
nCh := make(chan interface{}, 1)
|
||||
sCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sCh, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
api, closer, err := getFullNodeAPI(c, apiRetries, apiTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(c)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
log.Info("Waiting for sync to complete")
|
||||
if err := waitForSyncComplete(ctx, api, apiRetries, apiTimeout); err != nil {
|
||||
nCh <- err
|
||||
return
|
||||
}
|
||||
headCheckWindow, err = updateWindow(ctx, api, headCheckWindow, threshold, apiRetries, apiTimeout)
|
||||
if err != nil {
|
||||
log.Warn("Failed to connect to API. Restarting systemd service")
|
||||
nCh <- nil
|
||||
return
|
||||
}
|
||||
ok := checkWindow(headCheckWindow, threshold)
|
||||
if !ok {
|
||||
log.Warn("Chain head has not updated. Restarting systemd service")
|
||||
nCh <- nil
|
||||
break
|
||||
}
|
||||
log.Info("Chain head is healthy")
|
||||
time.Sleep(interval)
|
||||
}
|
||||
return
|
||||
}()
|
||||
|
||||
restart, err := notifyHandler(name, nCh, sCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if restart != "done" {
|
||||
return errors.New("Systemd unit failed to restart:" + restart)
|
||||
}
|
||||
log.Info("Restarting health agent")
|
||||
// Exit health agent and let supervisor restart health agent
|
||||
// Restarting lotus systemd unit kills api connection
|
||||
os.Exit(130)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
/*
|
||||
* reads channel of slices of Cids
|
||||
* compares slices of Cids when len is greater or equal to `t` - threshold
|
||||
* if all slices are equal, head has not updated and returns false
|
||||
*/
|
||||
func checkWindow(window CidWindow, t int) bool {
|
||||
var dup int
|
||||
windowLen := len(window)
|
||||
if windowLen >= t {
|
||||
cidWindow:
|
||||
for i := range window {
|
||||
next := windowLen - 1 - i
|
||||
// if array length is different, head is changing
|
||||
if next >= 1 && len(window[next]) != len(window[next-1]) {
|
||||
break cidWindow
|
||||
}
|
||||
// if cids are different, head is changing
|
||||
for j := range window[next] {
|
||||
if next >= 1 && window[next][j] != window[next-1][j] {
|
||||
break cidWindow
|
||||
}
|
||||
}
|
||||
if i < (t - 1) {
|
||||
dup++
|
||||
}
|
||||
}
|
||||
|
||||
if dup == (t - 1) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a slice of slices of Cids
|
||||
* len of slice <= `t` - threshold
|
||||
*/
|
||||
func updateWindow(ctx context.Context, a api.FullNode, w CidWindow, t int, r int, to time.Duration) (CidWindow, error) {
|
||||
head, err := getHead(ctx, a, r, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
window := appendCIDsToWindow(w, head.Cids(), t)
|
||||
return window, err
|
||||
}
|
||||
|
||||
/*
|
||||
* get chain head from API
|
||||
* retries if API no available
|
||||
* returns tipset
|
||||
*/
|
||||
func getHead(ctx context.Context, a api.FullNode, r int, t time.Duration) (*types.TipSet, error) {
|
||||
for i := 0; i < r; i++ {
|
||||
head, err := a.ChainHead(ctx)
|
||||
if err != nil && i == (r-1) {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("Call to API failed. Retrying in %.0fs", t.Seconds())
|
||||
time.Sleep(t)
|
||||
continue
|
||||
}
|
||||
return head, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
/*
|
||||
* appends slice of Cids to window slice
|
||||
* keeps a fixed window slice size, dropping older slices
|
||||
* returns new window
|
||||
*/
|
||||
func appendCIDsToWindow(w CidWindow, c []cid.Cid, t int) CidWindow {
|
||||
offset := len(w) - t + 1
|
||||
if offset >= 0 {
|
||||
return append(w[offset:], c)
|
||||
}
|
||||
return append(w, c)
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for node to sync
|
||||
*/
|
||||
func waitForSyncComplete(ctx context.Context, a api.FullNode, r int, t time.Duration) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(3 * time.Second):
|
||||
head, err := getHead(ctx, a, r, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if time.Now().Unix()-int64(head.MinTimestamp()) < build.BlockDelay {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A thin wrapper around lotus cli GetFullNodeAPI
|
||||
* Adds retry logic
|
||||
*/
|
||||
func getFullNodeAPI(ctx *cli.Context, r int, t time.Duration) (api.FullNode, jsonrpc.ClientCloser, error) {
|
||||
for i := 0; i < r; i++ {
|
||||
api, closer, err := lcli.GetFullNodeAPI(ctx)
|
||||
if err != nil && i == (r-1) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("API connection failed. Retrying in %.0fs", t.Seconds())
|
||||
time.Sleep(t)
|
||||
continue
|
||||
}
|
||||
return api, closer, err
|
||||
}
|
||||
return nil, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAppendCIDsToWindow(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
var window CidWindow
|
||||
threshold := 3
|
||||
cid0 := makeCID("0")
|
||||
cid1 := makeCID("1")
|
||||
cid2 := makeCID("2")
|
||||
cid3 := makeCID("3")
|
||||
window = appendCIDsToWindow(window, []cid.Cid{cid0}, threshold)
|
||||
window = appendCIDsToWindow(window, []cid.Cid{cid1}, threshold)
|
||||
window = appendCIDsToWindow(window, []cid.Cid{cid2}, threshold)
|
||||
window = appendCIDsToWindow(window, []cid.Cid{cid3}, threshold)
|
||||
assert.Len(window, 3)
|
||||
assert.Equal(window[0][0], cid1)
|
||||
assert.Equal(window[1][0], cid2)
|
||||
assert.Equal(window[2][0], cid3)
|
||||
}
|
||||
|
||||
func TestCheckWindow(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
threshold := 3
|
||||
|
||||
var healthyHeadCheckWindow CidWindow
|
||||
healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow = appendCIDsToWindow(healthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
ok := checkWindow(healthyHeadCheckWindow, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var healthyHeadCheckWindow1 CidWindow
|
||||
healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow1 = appendCIDsToWindow(healthyHeadCheckWindow1, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
ok = checkWindow(healthyHeadCheckWindow1, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var healthyHeadCheckWindow2 CidWindow
|
||||
healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow2 = appendCIDsToWindow(healthyHeadCheckWindow2, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
ok = checkWindow(healthyHeadCheckWindow2, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var healthyHeadCheckWindow3 CidWindow
|
||||
healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
healthyHeadCheckWindow3 = appendCIDsToWindow(healthyHeadCheckWindow3, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
ok = checkWindow(healthyHeadCheckWindow3, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var healthyHeadCheckWindow4 CidWindow
|
||||
healthyHeadCheckWindow4 = appendCIDsToWindow(healthyHeadCheckWindow4, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, threshold)
|
||||
ok = checkWindow(healthyHeadCheckWindow4, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var healthyHeadCheckWindow5 CidWindow
|
||||
healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
makeCID("bbff"),
|
||||
}, 5)
|
||||
healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
|
||||
makeCID("bbcd"),
|
||||
makeCID("bbfe"),
|
||||
}, 5)
|
||||
healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, 5)
|
||||
healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
|
||||
makeCID("cbcd"),
|
||||
makeCID("cbfe"),
|
||||
}, 5)
|
||||
healthyHeadCheckWindow5 = appendCIDsToWindow(healthyHeadCheckWindow5, []cid.Cid{
|
||||
makeCID("cbcd"),
|
||||
makeCID("cbfe"),
|
||||
}, 5)
|
||||
ok = checkWindow(healthyHeadCheckWindow5, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var unhealthyHeadCheckWindow CidWindow
|
||||
unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
makeCID("fbcd"),
|
||||
}, threshold)
|
||||
unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
makeCID("fbcd"),
|
||||
}, threshold)
|
||||
unhealthyHeadCheckWindow = appendCIDsToWindow(unhealthyHeadCheckWindow, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
makeCID("fbcd"),
|
||||
}, threshold)
|
||||
ok = checkWindow(unhealthyHeadCheckWindow, threshold)
|
||||
assert.False(ok)
|
||||
|
||||
var unhealthyHeadCheckWindow1 CidWindow
|
||||
unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
makeCID("fbcd"),
|
||||
}, threshold)
|
||||
unhealthyHeadCheckWindow1 = appendCIDsToWindow(unhealthyHeadCheckWindow1, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
makeCID("fbcd"),
|
||||
}, threshold)
|
||||
ok = checkWindow(unhealthyHeadCheckWindow1, threshold)
|
||||
assert.True(ok)
|
||||
|
||||
var unhealthyHeadCheckWindow2 CidWindow
|
||||
unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
unhealthyHeadCheckWindow2 = appendCIDsToWindow(unhealthyHeadCheckWindow2, []cid.Cid{
|
||||
makeCID("abcd"),
|
||||
}, threshold)
|
||||
ok = checkWindow(unhealthyHeadCheckWindow2, threshold)
|
||||
assert.False(ok)
|
||||
}
|
||||
|
||||
func makeCID(s string) cid.Cid {
|
||||
h1, err := mh.Sum([]byte(s), mh.SHA2_256, -1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return cid.NewCidV1(0x55, h1)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/coreos/go-systemd/v22/dbus"
|
||||
)
|
||||
|
||||
func notifyHandler(n string, ch chan interface{}, sCh chan os.Signal) (string, error) {
|
||||
select {
|
||||
// alerts to restart systemd unit
|
||||
case <-ch:
|
||||
statusCh := make(chan string, 1)
|
||||
c, err := dbus.New()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = c.TryRestartUnit(n, "fail", statusCh)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
select {
|
||||
case result := <-statusCh:
|
||||
return result, nil
|
||||
}
|
||||
// SIGTERM
|
||||
case <-sCh:
|
||||
os.Exit(1)
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
@@ -2,23 +2,32 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
manet "github.com/multiformats/go-multiaddr-net"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/lib/lotuslog"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
manet "github.com/multiformats/go-multiaddr-net"
|
||||
)
|
||||
|
||||
var log = logging.Logger("main")
|
||||
|
||||
const (
|
||||
workers = 1 // TODO: Configurability
|
||||
transfers = 1
|
||||
)
|
||||
|
||||
func main() {
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
@@ -67,6 +76,11 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
type limits struct {
|
||||
workLimit chan struct{}
|
||||
transferLimit chan struct{}
|
||||
}
|
||||
|
||||
var runCmd = &cli.Command{
|
||||
Name: "run",
|
||||
Usage: "Start lotus worker",
|
||||
@@ -106,6 +120,50 @@ var runCmd = &cli.Command{
|
||||
log.Warn("Shutting down..")
|
||||
}()
|
||||
|
||||
return acceptJobs(ctx, nodeApi, "http://"+storageAddr, ainfo.AuthHeader(), r, cctx.Bool("no-precommit"), cctx.Bool("no-commit"))
|
||||
limiter := &limits{
|
||||
workLimit: make(chan struct{}, workers),
|
||||
transferLimit: make(chan struct{}, transfers),
|
||||
}
|
||||
|
||||
act, err := nodeApi.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ssize, err := nodeApi.ActorSectorSize(ctx, act)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), ssize); err != nil {
|
||||
return xerrors.Errorf("get params: %w", err)
|
||||
}
|
||||
|
||||
sb, err := sectorbuilder.NewStandalone(§orbuilder.Config{
|
||||
SectorSize: ssize,
|
||||
Miner: act,
|
||||
WorkerThreads: workers,
|
||||
Paths: sectorbuilder.SimplePath(r),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nQueues := workers + transfers
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(nQueues)
|
||||
|
||||
for i := 0; i < nQueues; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
if err := acceptJobs(ctx, nodeApi, sb, limiter, "http://"+storageAddr, ainfo.AuthHeader(), r, cctx.Bool("no-precommit"), cctx.Bool("no-commit")); err != nil {
|
||||
log.Warnf("%+v", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
type worker struct {
|
||||
@@ -18,39 +16,19 @@ type worker struct {
|
||||
repo string
|
||||
auth http.Header
|
||||
|
||||
sb *sectorbuilder.SectorBuilder
|
||||
limiter *limits
|
||||
sb *sectorbuilder.SectorBuilder
|
||||
}
|
||||
|
||||
func acceptJobs(ctx context.Context, api lapi.StorageMiner, endpoint string, auth http.Header, repo string, noprecommit, nocommit bool) error {
|
||||
act, err := api.ActorAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ssize, err := api.ActorSectorSize(ctx, act)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sb, err := sectorbuilder.NewStandalone(§orbuilder.Config{
|
||||
SectorSize: ssize,
|
||||
Miner: act,
|
||||
WorkerThreads: 1,
|
||||
Dir: repo,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := paramfetch.GetParams(build.ParametersJson, ssize); err != nil {
|
||||
return xerrors.Errorf("get params: %w", err)
|
||||
}
|
||||
|
||||
func acceptJobs(ctx context.Context, api lapi.StorageMiner, sb *sectorbuilder.SectorBuilder, limiter *limits, endpoint string, auth http.Header, repo string, noprecommit, nocommit bool) error {
|
||||
w := &worker{
|
||||
api: api,
|
||||
minerEndpoint: endpoint,
|
||||
auth: auth,
|
||||
repo: repo,
|
||||
sb: sb,
|
||||
|
||||
limiter: limiter,
|
||||
sb: sb,
|
||||
}
|
||||
|
||||
tasks, err := api.WorkerQueue(ctx, sectorbuilder.WorkerCfg{
|
||||
@@ -103,7 +81,10 @@ func (w *worker) processTask(ctx context.Context, task sectorbuilder.WorkerTask)
|
||||
|
||||
switch task.Type {
|
||||
case sectorbuilder.WorkerPreCommit:
|
||||
w.limiter.workLimit <- struct{}{}
|
||||
rspco, err := w.sb.SealPreCommit(ctx, task.SectorID, task.SealTicket, task.Pieces)
|
||||
<-w.limiter.workLimit
|
||||
|
||||
if err != nil {
|
||||
return errRes(xerrors.Errorf("precomitting: %w", err))
|
||||
}
|
||||
@@ -116,8 +97,15 @@ func (w *worker) processTask(ctx context.Context, task sectorbuilder.WorkerTask)
|
||||
if err := w.push("cache", task.SectorID); err != nil {
|
||||
return errRes(xerrors.Errorf("pushing precommited data: %w", err))
|
||||
}
|
||||
|
||||
if err := w.remove("staging", task.SectorID); err != nil {
|
||||
return errRes(xerrors.Errorf("cleaning up staged sector: %w", err))
|
||||
}
|
||||
case sectorbuilder.WorkerCommit:
|
||||
w.limiter.workLimit <- struct{}{}
|
||||
proof, err := w.sb.SealCommit(ctx, task.SectorID, task.SealTicket, task.SealSeed, task.Pieces, task.Rspco)
|
||||
<-w.limiter.workLimit
|
||||
|
||||
if err != nil {
|
||||
return errRes(xerrors.Errorf("comitting: %w", err))
|
||||
}
|
||||
@@ -127,6 +115,10 @@ func (w *worker) processTask(ctx context.Context, task sectorbuilder.WorkerTask)
|
||||
if err := w.push("cache", task.SectorID); err != nil {
|
||||
return errRes(xerrors.Errorf("pushing precommited data: %w", err))
|
||||
}
|
||||
|
||||
if err := w.remove("sealed", task.SectorID); err != nil {
|
||||
return errRes(xerrors.Errorf("cleaning up sealed sector: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/filecoin-project/go-sectorbuilder/fs"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/cheggaaa/pb.v1"
|
||||
@@ -15,10 +17,18 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/tarutil"
|
||||
)
|
||||
|
||||
func (w *worker) sizeForType(typ string) int64 {
|
||||
size := int64(w.sb.SectorSize())
|
||||
if typ == "cache" {
|
||||
size *= 10
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func (w *worker) fetch(typ string, sectorID uint64) error {
|
||||
outname := filepath.Join(w.repo, typ, w.sb.SectorName(sectorID))
|
||||
|
||||
url := w.minerEndpoint + "/remote/" + typ + "/" + w.sb.SectorName(sectorID)
|
||||
url := w.minerEndpoint + "/remote/" + typ + "/" + fmt.Sprint(sectorID)
|
||||
log.Infof("Fetch %s %s", typ, url)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
@@ -37,7 +47,7 @@ func (w *worker) fetch(typ string, sectorID uint64) error {
|
||||
return xerrors.Errorf("non-200 code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
bar := pb.New64(resp.ContentLength)
|
||||
bar := pb.New64(w.sizeForType(typ))
|
||||
bar.ShowPercent = true
|
||||
bar.ShowSpeed = true
|
||||
bar.Units = pb.U_BYTES
|
||||
@@ -68,27 +78,35 @@ func (w *worker) fetch(typ string, sectorID uint64) error {
|
||||
}
|
||||
|
||||
func (w *worker) push(typ string, sectorID uint64) error {
|
||||
filename := filepath.Join(w.repo, typ, w.sb.SectorName(sectorID))
|
||||
w.limiter.transferLimit <- struct{}{}
|
||||
defer func() {
|
||||
<-w.limiter.transferLimit
|
||||
}()
|
||||
|
||||
url := w.minerEndpoint + "/remote/" + typ + "/" + w.sb.SectorName(sectorID)
|
||||
filename, err := w.sb.SectorPath(fs.DataType(typ), sectorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
url := w.minerEndpoint + "/remote/" + typ + "/" + fmt.Sprint(sectorID)
|
||||
log.Infof("Push %s %s", typ, url)
|
||||
|
||||
stat, err := os.Stat(filename)
|
||||
stat, err := os.Stat(string(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var r io.Reader
|
||||
if stat.IsDir() {
|
||||
r, err = tarutil.TarDirectory(filename)
|
||||
r, err = tarutil.TarDirectory(string(filename))
|
||||
} else {
|
||||
r, err = os.OpenFile(filename, os.O_RDONLY, 0644)
|
||||
r, err = os.OpenFile(string(filename), os.O_RDONLY, 0644)
|
||||
}
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening push reader: %w", err)
|
||||
}
|
||||
|
||||
bar := pb.New64(0)
|
||||
bar := pb.New64(w.sizeForType(typ))
|
||||
bar.ShowPercent = true
|
||||
bar.ShowSpeed = true
|
||||
bar.ShowCounters = true
|
||||
@@ -125,10 +143,20 @@ func (w *worker) push(typ string, sectorID uint64) error {
|
||||
}
|
||||
|
||||
// TODO: keep files around for later stages of sealing
|
||||
return w.remove(typ, sectorID)
|
||||
}
|
||||
|
||||
func (w *worker) remove(typ string, sectorID uint64) error {
|
||||
filename := filepath.Join(w.repo, typ, w.sb.SectorName(sectorID))
|
||||
return os.RemoveAll(filename)
|
||||
}
|
||||
|
||||
func (w *worker) fetchSector(sectorID uint64, typ sectorbuilder.WorkerTaskType) error {
|
||||
w.limiter.transferLimit <- struct{}{}
|
||||
defer func() {
|
||||
<-w.limiter.transferLimit
|
||||
}()
|
||||
|
||||
var err error
|
||||
switch typ {
|
||||
case sectorbuilder.WorkerPreCommit:
|
||||
|
||||
@@ -8,6 +8,9 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
badger "github.com/ipfs/go-ds-badger2"
|
||||
@@ -196,7 +199,7 @@ var aggregateSectorDirsCmd = &cli.Command{
|
||||
agsb, err := sectorbuilder.New(§orbuilder.Config{
|
||||
Miner: maddr,
|
||||
SectorSize: ssize,
|
||||
Dir: destdir,
|
||||
Paths: sectorbuilder.SimplePath(destdir),
|
||||
WorkerThreads: 2,
|
||||
}, namespace.Wrap(agmds, datastore.NewKey("/sectorbuilder")))
|
||||
if err != nil {
|
||||
@@ -257,7 +260,7 @@ var aggregateSectorDirsCmd = &cli.Command{
|
||||
sb, err := sectorbuilder.New(§orbuilder.Config{
|
||||
Miner: maddr,
|
||||
SectorSize: genm.SectorSize,
|
||||
Dir: dir,
|
||||
Paths: sectorbuilder.SimplePath(dir),
|
||||
WorkerThreads: 2,
|
||||
}, namespace.Wrap(mds, datastore.NewKey("/sectorbuilder")))
|
||||
if err != nil {
|
||||
|
||||
@@ -32,7 +32,7 @@ func PreSeal(maddr address.Address, ssize uint64, offset uint64, sectors int, sb
|
||||
Miner: maddr,
|
||||
SectorSize: ssize,
|
||||
FallbackLastID: offset,
|
||||
Dir: sbroot,
|
||||
Paths: sectorbuilder.SimplePath(sbroot),
|
||||
WorkerThreads: 2,
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func PreSeal(maddr address.Address, ssize uint64, offset uint64, sectors int, sb
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pi, err := sb.AddPiece(size, sid, rand.Reader, nil)
|
||||
pi, err := sb.AddPiece(context.TODO(), size, sid, rand.Reader, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func PreSeal(maddr address.Address, ssize uint64, offset uint64, sectors int, sb
|
||||
return nil, xerrors.Errorf("commit: %w", err)
|
||||
}
|
||||
|
||||
if err := sb.TrimCache(sid); err != nil {
|
||||
if err := sb.TrimCache(context.TODO(), sid); err != nil {
|
||||
return nil, xerrors.Errorf("trim cache: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
var bigIntParseCmd = &cli.Command{
|
||||
Name: "bigint",
|
||||
Description: "parse encoded big ints",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "enc",
|
||||
Value: "base64",
|
||||
Usage: "specify input encoding to parse",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
val := cctx.Args().Get(0)
|
||||
|
||||
var dec []byte
|
||||
switch cctx.String("enc") {
|
||||
case "base64":
|
||||
d, err := base64.StdEncoding.DecodeString(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding base64 value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
case "hex":
|
||||
d, err := hex.DecodeString(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding hex value: %w", err)
|
||||
}
|
||||
dec = d
|
||||
default:
|
||||
return fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
|
||||
}
|
||||
|
||||
iv := types.BigFromBytes(dec)
|
||||
fmt.Println(iv.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -11,6 +11,9 @@ import (
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
)
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
keyinfoCmd,
|
||||
peerkeyCmd,
|
||||
noncefix,
|
||||
bigIntParseCmd,
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
|
||||
@@ -38,27 +38,39 @@ var infoCmd = &cli.Command{
|
||||
fmt.Printf("Miner: %s\n", maddr)
|
||||
|
||||
// Sector size
|
||||
sizeByte, err := api.StateMinerSectorSize(ctx, maddr, nil)
|
||||
sizeByte, err := api.StateMinerSectorSize(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Sector Size: %s\n", types.NewInt(sizeByte).SizeStr())
|
||||
|
||||
pow, err := api.StateMinerPower(ctx, maddr, nil)
|
||||
pow, err := api.StateMinerPower(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
percI := types.BigDiv(types.BigMul(pow.MinerPower, types.NewInt(1000)), pow.TotalPower)
|
||||
fmt.Printf("Power: %s / %s (%0.4f%%)\n", pow.MinerPower.SizeStr(), pow.TotalPower.SizeStr(), float64(percI.Int64())/100000*10000)
|
||||
percI := types.BigDiv(types.BigMul(pow.MinerPower, types.NewInt(1000000)), pow.TotalPower)
|
||||
fmt.Printf("Power: %s / %s (%0.4f%%)\n", pow.MinerPower.SizeStr(), pow.TotalPower.SizeStr(), float64(percI.Int64())/10000)
|
||||
|
||||
secCounts, err := api.StateMinerSectorCount(ctx, maddr, nil)
|
||||
secCounts, err := api.StateMinerSectorCount(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
faults, err := api.StateMinerFaults(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("\tCommitted: %s\n", types.BigMul(types.NewInt(secCounts.Sset), types.NewInt(sizeByte)).SizeStr())
|
||||
fmt.Printf("\tProving: %s\n", types.BigMul(types.NewInt(secCounts.Pset), types.NewInt(sizeByte)).SizeStr())
|
||||
if len(faults) == 0 {
|
||||
fmt.Printf("\tProving: %s\n", types.BigMul(types.NewInt(secCounts.Pset), types.NewInt(sizeByte)).SizeStr())
|
||||
} else {
|
||||
fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n",
|
||||
types.BigMul(types.NewInt(secCounts.Pset-uint64(len(faults))), types.NewInt(sizeByte)).SizeStr(),
|
||||
types.BigMul(types.NewInt(uint64(len(faults))), types.NewInt(sizeByte)).SizeStr(),
|
||||
float64(10000*uint64(len(faults))/secCounts.Pset)/100.)
|
||||
}
|
||||
|
||||
// TODO: indicate whether the post worker is in use
|
||||
wstat, err := nodeApi.WorkerStats(ctx)
|
||||
@@ -76,7 +88,7 @@ var infoCmd = &cli.Command{
|
||||
fmt.Printf("\tCommit: %d\n", wstat.CommitWait)
|
||||
fmt.Printf("\tUnseal: %d\n", wstat.UnsealWait)
|
||||
|
||||
eps, err := api.StateMinerElectionPeriodStart(ctx, maddr, nil)
|
||||
eps, err := api.StateMinerElectionPeriodStart(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,12 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
deals "github.com/filecoin-project/go-fil-markets/storagemarket/impl"
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
badger "github.com/ipfs/go-ds-badger2"
|
||||
@@ -21,11 +26,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
cborutil "github.com/filecoin-project/go-cbor-util"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
deals "github.com/filecoin-project/go-fil-markets/storagemarket/impl"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
@@ -34,10 +34,12 @@ import (
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/markets/utils"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage"
|
||||
"github.com/filecoin-project/lotus/storage/sealing"
|
||||
)
|
||||
|
||||
var initCmd = &cli.Command{
|
||||
@@ -76,6 +78,10 @@ var initCmd = &cli.Command{
|
||||
Name: "pre-sealed-sectors",
|
||||
Usage: "specify set of presealed sectors for starting as a genesis miner",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pre-sealed-metadata",
|
||||
Usage: "specify the metadata file for the presealed sectors",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "nosync",
|
||||
Usage: "don't check full-node sync status",
|
||||
@@ -96,7 +102,7 @@ var initCmd = &cli.Command{
|
||||
}
|
||||
|
||||
log.Info("Checking proof parameters")
|
||||
if err := paramfetch.GetParams(build.ParametersJson, ssize); err != nil {
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), ssize); err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
@@ -176,7 +182,7 @@ var initCmd = &cli.Command{
|
||||
oldsb, err := sectorbuilder.New(§orbuilder.Config{
|
||||
SectorSize: ssize,
|
||||
WorkerThreads: 2,
|
||||
Dir: pssb,
|
||||
Paths: sectorbuilder.SimplePath(pssb),
|
||||
}, namespace.Wrap(oldmds, datastore.NewKey("/sectorbuilder")))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open up preseal sectorbuilder: %w", err)
|
||||
@@ -185,7 +191,7 @@ var initCmd = &cli.Command{
|
||||
nsb, err := sectorbuilder.New(§orbuilder.Config{
|
||||
SectorSize: ssize,
|
||||
WorkerThreads: 2,
|
||||
Dir: lr.Path(),
|
||||
Paths: sectorbuilder.SimplePath(lr.Path()),
|
||||
}, namespace.Wrap(mds, datastore.NewKey("/sectorbuilder")))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open up sectorbuilder: %w", err)
|
||||
@@ -219,13 +225,13 @@ var initCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func migratePreSealMeta(ctx context.Context, api lapi.FullNode, presealDir string, maddr address.Address, mds dtypes.MetadataDS) error {
|
||||
presealDir, err := homedir.Expand(presealDir)
|
||||
func migratePreSealMeta(ctx context.Context, api lapi.FullNode, metadata string, maddr address.Address, mds dtypes.MetadataDS) error {
|
||||
metadata, err := homedir.Expand(metadata)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expanding preseal dir: %w", err)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(filepath.Join(presealDir, "pre-seal-"+maddr.String()+".json"))
|
||||
b, err := ioutil.ReadFile(metadata)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading preseal metadata: %w", err)
|
||||
}
|
||||
@@ -242,17 +248,17 @@ func migratePreSealMeta(ctx context.Context, api lapi.FullNode, presealDir strin
|
||||
}
|
||||
|
||||
for _, sector := range meta.Sectors {
|
||||
sectorKey := datastore.NewKey(storage.SectorStorePrefix).ChildString(fmt.Sprint(sector.SectorID))
|
||||
sectorKey := datastore.NewKey(sealing.SectorStorePrefix).ChildString(fmt.Sprint(sector.SectorID))
|
||||
|
||||
dealID, err := findMarketDealID(ctx, api, sector.Deal)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("finding storage deal for pre-sealed sector %d: %w", sector.SectorID, err)
|
||||
}
|
||||
|
||||
info := &storage.SectorInfo{
|
||||
info := &sealing.SectorInfo{
|
||||
State: lapi.Proving,
|
||||
SectorID: sector.SectorID,
|
||||
Pieces: []storage.Piece{
|
||||
Pieces: []sealing.Piece{
|
||||
{
|
||||
DealID: dealID,
|
||||
Size: meta.SectorSize,
|
||||
@@ -262,9 +268,9 @@ func migratePreSealMeta(ctx context.Context, api lapi.FullNode, presealDir strin
|
||||
CommD: sector.CommD[:],
|
||||
CommR: sector.CommR[:],
|
||||
Proof: nil,
|
||||
Ticket: storage.SealTicket{},
|
||||
Ticket: sealing.SealTicket{},
|
||||
PreCommitMessage: nil,
|
||||
Seed: storage.SealSeed{},
|
||||
Seed: sealing.SealSeed{},
|
||||
CommitMessage: nil,
|
||||
}
|
||||
|
||||
@@ -318,7 +324,7 @@ func findMarketDealID(ctx context.Context, api lapi.FullNode, deal actors.Storag
|
||||
// TODO: find a better way
|
||||
// (this is only used by genesis miners)
|
||||
|
||||
deals, err := api.StateMarketDeals(ctx, nil)
|
||||
deals, err := api.StateMarketDeals(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("getting market deals: %w", err)
|
||||
}
|
||||
@@ -368,7 +374,22 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
|
||||
return err
|
||||
}
|
||||
|
||||
sbcfg, err := modules.SectorBuilderConfig(lr.Path(), 2, false, false)(mds, api)
|
||||
c, err := lr.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, ok := c.(*config.StorageMiner)
|
||||
if !ok {
|
||||
return xerrors.Errorf("invalid config from repo, got: %T", c)
|
||||
}
|
||||
|
||||
scfg := sectorbuilder.SimplePath(lr.Path())
|
||||
if len(cfg.SectorBuilder.Storage) > 0 {
|
||||
scfg = cfg.SectorBuilder.Storage
|
||||
}
|
||||
|
||||
sbcfg, err := modules.SectorBuilderConfig(scfg, 2, false, false)(mds, api)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis miner sector builder config: %w", err)
|
||||
}
|
||||
@@ -395,20 +416,20 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api lapi.FullNode,
|
||||
}
|
||||
}
|
||||
|
||||
if pssb := cctx.String("pre-sealed-sectors"); pssb != "" {
|
||||
pssb, err := homedir.Expand(pssb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infof("Importing pre-sealed sector metadata for %s", a)
|
||||
|
||||
if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil {
|
||||
return xerrors.Errorf("migrating presealed sector metadata: %w", err)
|
||||
}
|
||||
if pssb := cctx.String("pre-sealed-metadata"); pssb != "" {
|
||||
pssb, err := homedir.Expand(pssb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
log.Infof("Importing pre-sealed sector metadata for %s", a)
|
||||
|
||||
if err := migratePreSealMeta(ctx, api, pssb, a, mds); err != nil {
|
||||
return xerrors.Errorf("migrating presealed sector metadata: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := configureStorageMiner(ctx, api, a, peerid); err != nil {
|
||||
@@ -465,7 +486,7 @@ func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address.
|
||||
To: addr,
|
||||
From: addr,
|
||||
Method: actors.MAMethods.GetWorkerAddr,
|
||||
}, nil)
|
||||
}, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get worker address: %w", err)
|
||||
}
|
||||
@@ -538,7 +559,7 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID,
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
collateral, err := api.StatePledgeCollateral(ctx, nil)
|
||||
collateral, err := api.StatePledgeCollateral(ctx, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
@@ -556,7 +577,7 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID,
|
||||
createStorageMinerMsg := &types.Message{
|
||||
To: actors.StoragePowerAddress,
|
||||
From: owner,
|
||||
Value: collateral,
|
||||
Value: types.BigAdd(collateral, types.BigDiv(collateral, types.NewInt(100))),
|
||||
|
||||
Method: actors.SPAMethods.CreateStorageMiner,
|
||||
Params: params,
|
||||
|
||||
@@ -2,8 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
@@ -41,6 +45,12 @@ var sectorsCmd = &cli.Command{
|
||||
var sectorsStatusCmd = &cli.Command{
|
||||
Name: "status",
|
||||
Usage: "Get the seal status of a sector by its ID",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "log",
|
||||
Usage: "display event log",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -77,6 +87,17 @@ var sectorsStatusCmd = &cli.Command{
|
||||
if status.LastErr != "" {
|
||||
fmt.Printf("Last Error:\t\t%s\n", status.LastErr)
|
||||
}
|
||||
|
||||
if cctx.Bool("log") {
|
||||
fmt.Printf("--------\nEvent Log:\n")
|
||||
|
||||
for i, l := range status.Log {
|
||||
fmt.Printf("%d.\t%s:\t[%s]\t%s\n", i, time.Unix(int64(l.Timestamp), 0), l.Kind, l.Message)
|
||||
if l.Trace != "" {
|
||||
fmt.Printf("\t%s\n", l.Trace)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -109,7 +130,7 @@ var sectorsListCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
pset, err := fullApi.StateMinerProvingSet(ctx, maddr, nil)
|
||||
pset, err := fullApi.StateMinerProvingSet(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,7 +139,7 @@ var sectorsListCmd = &cli.Command{
|
||||
provingIDs[info.SectorID] = struct{}{}
|
||||
}
|
||||
|
||||
sset, err := fullApi.StateMinerSectors(ctx, maddr, nil)
|
||||
sset, err := fullApi.StateMinerSectors(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -131,17 +152,19 @@ var sectorsListCmd = &cli.Command{
|
||||
return list[i] < list[j]
|
||||
})
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 8, 4, 1, ' ', 0)
|
||||
|
||||
for _, s := range list {
|
||||
st, err := nodeApi.SectorsStatus(ctx, s)
|
||||
if err != nil {
|
||||
fmt.Printf("%d:\tError: %s\n", s, err)
|
||||
fmt.Fprintf(w, "%d:\tError: %s\n", s, err)
|
||||
continue
|
||||
}
|
||||
|
||||
_, inSSet := commitedIDs[s]
|
||||
_, inPSet := provingIDs[s]
|
||||
|
||||
fmt.Printf("%d: %s\tsSet: %s\tpSet: %s\ttktH: %d\tseedH: %d\tdeals: %v\n",
|
||||
fmt.Fprintf(w, "%d: %s\tsSet: %s\tpSet: %s\ttktH: %d\tseedH: %d\tdeals: %v\n",
|
||||
s,
|
||||
api.SectorStates[st.State],
|
||||
yesno(inSSet),
|
||||
@@ -151,7 +174,8 @@ var sectorsListCmd = &cli.Command{
|
||||
st.Deals,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
|
||||
return w.Flush()
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
+99
-1
@@ -5,14 +5,22 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
|
||||
paramfetch "github.com/filecoin-project/go-paramfetch"
|
||||
"github.com/filecoin-project/go-sectorbuilder"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/testing"
|
||||
@@ -56,9 +64,42 @@ var DaemonCmd = &cli.Command{
|
||||
Name: "bootstrap",
|
||||
Value: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "import-chain",
|
||||
Usage: "on first run, load chain from given file",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "halt-after-import",
|
||||
Usage: "halt the process after importing chain from file",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pprof",
|
||||
Usage: "specify name of file for writing cpu profile to",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if prof := cctx.String("pprof"); prof != "" {
|
||||
profile, err := os.Create(prof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := pprof.StartCPUProfile(profile); err != nil {
|
||||
return err
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
{
|
||||
dir, err := homedir.Expand(cctx.String("repo"))
|
||||
if err != nil {
|
||||
log.Warnw("could not expand repo location", "error", err)
|
||||
} else {
|
||||
log.Infof("lotus repo: %s", dir)
|
||||
}
|
||||
}
|
||||
|
||||
r, err := repo.NewFS(cctx.String("repo"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening fs repo: %w", err)
|
||||
@@ -68,7 +109,7 @@ var DaemonCmd = &cli.Command{
|
||||
return xerrors.Errorf("repo init error: %w", err)
|
||||
}
|
||||
|
||||
if err := paramfetch.GetParams(build.ParametersJson, 0); err != nil {
|
||||
if err := paramfetch.GetParams(build.ParametersJson(), 0); err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
@@ -81,6 +122,16 @@ var DaemonCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
chainfile := cctx.String("import-chain")
|
||||
if chainfile != "" {
|
||||
if err := ImportChain(r, chainfile); err != nil {
|
||||
return err
|
||||
}
|
||||
if cctx.Bool("halt-after-import") {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
genesis := node.Options()
|
||||
if len(genBytes) > 0 {
|
||||
genesis = node.Override(new(modules.Genesis), modules.LoadGenesis(genBytes))
|
||||
@@ -129,3 +180,50 @@ var DaemonCmd = &cli.Command{
|
||||
return serveRPC(api, stop, endpoint)
|
||||
},
|
||||
}
|
||||
|
||||
func ImportChain(r repo.Repo, fname string) error {
|
||||
fi, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.FullNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close()
|
||||
|
||||
ds, err := lr.Datastore("/blocks")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mds, err := lr.Datastore("/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bs := blockstore.NewBlockstore(ds)
|
||||
|
||||
cst := store.NewChainStore(bs, mds, vm.Syscalls(sectorbuilder.ProofVerifier))
|
||||
|
||||
log.Info("importing chain from file...")
|
||||
ts, err := cst.Import(fi)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("importing chain failed: %w", err)
|
||||
}
|
||||
|
||||
stm := stmgr.NewStateManager(cst)
|
||||
|
||||
log.Infof("validating imported chain...")
|
||||
if err := stm.ValidateChain(context.TODO(), ts); err != nil {
|
||||
return xerrors.Errorf("chain validation failed: %w", err)
|
||||
}
|
||||
|
||||
log.Info("accepting %s as new head", ts.Cids())
|
||||
if err := cst.SetHead(ts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
// +build debug
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
AdvanceBlockCmd = &cli.Command{
|
||||
Name: "advance-block",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
head, err := api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pending, err := api.MpoolPending(ctx, head.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgs, err := miner.SelectMessages(ctx, api.StateGetActor, head, pending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(msgs) > build.BlockMessageLimit {
|
||||
log.Error("SelectMessages returned too many messages: ", len(msgs))
|
||||
msgs = msgs[:build.BlockMessageLimit]
|
||||
}
|
||||
|
||||
addr, _ := address.NewIDAddress(101)
|
||||
var ticket *types.Ticket
|
||||
{
|
||||
vrfBase := head.MinTicket().VRFProof
|
||||
ret, err := api.StateCall(ctx, &types.Message{
|
||||
From: addr,
|
||||
To: addr,
|
||||
Method: actors.MAMethods.GetWorkerAddr,
|
||||
}, head.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get miner worker addr: %w", err)
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode)
|
||||
}
|
||||
|
||||
w, err := address.NewFromBytes(ret.Return)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err)
|
||||
}
|
||||
t, err := gen.ComputeVRF(ctx, api.WalletSign, w, addr, gen.DSepTicket, vrfBase)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("compute vrf failed: %w", err)
|
||||
}
|
||||
ticket = &types.Ticket{
|
||||
VRFProof: t,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
epostp := &types.EPostProof{
|
||||
Proof: []byte("valid proof"),
|
||||
Candidates: []types.EPostTicket{
|
||||
{
|
||||
ChallengeIndex: 0,
|
||||
SectorID: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
{
|
||||
r, err := api.ChainGetRandomness(ctx, head.Key(), int64(head.Height()+1)-build.EcRandomnessLookback)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("chain get randomness: %w", err)
|
||||
}
|
||||
mworker, err := api.StateMinerWorker(ctx, addr, head.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get miner worker: %w", err)
|
||||
}
|
||||
|
||||
vrfout, err := gen.ComputeVRF(ctx, api.WalletSign, mworker, addr, gen.DSepElectionPost, r)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute VRF: %w", err)
|
||||
}
|
||||
epostp.PostRand = vrfout
|
||||
}
|
||||
|
||||
uts := head.MinTimestamp() + uint64(build.BlockDelay)
|
||||
nheight := head.Height() + 1
|
||||
blk, err := api.MinerCreateBlock(ctx, addr, head.Key(), ticket, epostp, msgs, nheight, uts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("creating block: %w", err)
|
||||
}
|
||||
|
||||
return api.SyncSubmitBlock(ctx, blk)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,18 @@ import (
|
||||
"github.com/filecoin-project/lotus/tracing"
|
||||
)
|
||||
|
||||
var AdvanceBlockCmd *cli.Command
|
||||
|
||||
func main() {
|
||||
lotuslog.SetupLogLevels()
|
||||
|
||||
local := []*cli.Command{
|
||||
DaemonCmd,
|
||||
}
|
||||
if AdvanceBlockCmd != nil {
|
||||
local = append(local, AdvanceBlockCmd)
|
||||
}
|
||||
|
||||
jaeger := tracing.SetupJaegerTracing("lotus")
|
||||
defer func() {
|
||||
if jaeger != nil {
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
"github": "en/install-lotus-ubuntu.md",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"title": "Fedora Installation",
|
||||
"slug": "en+install-lotus-fedora",
|
||||
"github": "en/install-lotus-fedora.md",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"title": "MacOS Installation",
|
||||
"slug": "en+install-lotus-macos",
|
||||
@@ -154,6 +160,13 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "FAQs",
|
||||
"slug": "en+faqs",
|
||||
"github": "en/faqs.md",
|
||||
"value": null,
|
||||
"posts": []
|
||||
},
|
||||
{
|
||||
"title": "Glossary",
|
||||
"slug": "en+glossary",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user