Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48e8f54c6a | ||
|
|
776c216072 | ||
|
|
c60959ea9f | ||
|
|
62044c34b1 | ||
|
|
c8d328d386 | ||
|
|
fd879e0426 | ||
|
|
27f3170022 | ||
|
|
5b1241d213 | ||
|
|
eaee1578dd | ||
|
|
9e5c5b624b | ||
|
|
640d69f5cb | ||
|
|
36876c2601 | ||
|
|
39c1594505 | ||
|
|
86e1c854fa | ||
|
|
1af89236da | ||
|
|
9741867426 | ||
|
|
b7b98f94a6 | ||
|
|
fb50d68c32 | ||
|
|
692961e019 | ||
|
|
312cc94e6d | ||
|
|
ea71e4de60 | ||
|
|
4ed9cd152c | ||
|
|
0dbb1940f0 | ||
|
|
1452a361a9 | ||
|
|
503c08f999 | ||
|
|
6bee14d6fa | ||
|
|
839abdf910 | ||
|
|
6057f2e6d9 | ||
|
|
213dbc6bc8 | ||
|
|
fc77705229 | ||
|
|
12d7db4efb | ||
|
|
d7827da5bb | ||
|
|
b2ff2edd0c | ||
|
|
13e845ae51 | ||
|
|
0c90868929 | ||
|
|
44496afc66 | ||
|
|
8becd922cf | ||
|
|
16be5b5478 | ||
|
|
1e7095995b | ||
|
|
ffb995035f | ||
|
|
ffe7185443 | ||
|
|
44036d9a4a | ||
|
|
b6a7a8c987 | ||
|
|
905592a3dc | ||
|
|
1c30d07d68 | ||
|
|
d8431da9b9 | ||
|
|
9724248a49 | ||
|
|
fd9f5dc83c | ||
|
|
ed058ae193 | ||
|
|
ca5a2eaa74 | ||
|
|
35b39063ac | ||
|
|
1d9dcef878 | ||
|
|
25cd577d06 | ||
|
|
e003203bea | ||
|
|
33c347956c | ||
|
|
f07a370711 | ||
|
|
a03c5ac3d2 | ||
|
|
a259ee307f | ||
|
|
46b78406b1 | ||
|
|
ab2f159d54 | ||
|
|
d023026cb0 | ||
|
|
b2f8b4011a | ||
|
|
3e9ec01d04 | ||
|
|
a48a6a168a | ||
|
|
ac03c01e4a | ||
|
|
bdaa73a413 | ||
|
|
cf81c897df | ||
|
|
81d614a607 | ||
|
|
5e5b4b7191 | ||
|
|
dd0f4dea81 | ||
|
|
c738d1f7ef | ||
|
|
5a23f64b3b | ||
|
|
44d01712c8 | ||
|
|
3f3a12b75c | ||
|
|
023146803d | ||
|
|
3d77ae1f4d | ||
|
|
6f126c80bf | ||
|
|
ff093fae00 | ||
|
|
669b47cfc9 | ||
|
|
818b8de182 | ||
|
|
c93328b036 | ||
|
|
35180b4761 | ||
|
|
dc81c0e6a2 | ||
|
|
f0c9e4e8f2 | ||
|
|
71ddbdaf10 | ||
|
|
856cbb2ca0 | ||
|
|
a37ababc20 | ||
|
|
677c193e6c | ||
|
|
dd09666399 | ||
|
|
583a8a13d9 | ||
|
|
837322ea59 | ||
|
|
0678b3fa05 | ||
|
|
7526a074d9 | ||
|
|
2af02af1c1 | ||
|
|
c37401a1a3 | ||
|
|
6efd2e7335 | ||
|
|
af399529ec | ||
|
|
257423e917 | ||
|
|
04abd190ab | ||
|
|
60212c86cb | ||
|
|
759594d01c | ||
|
|
5c3e79e8d0 | ||
|
|
92ec239202 | ||
|
|
4433c3cd7c | ||
|
|
7728d6bfc3 | ||
|
|
83f2368507 | ||
|
|
4bc9fa04ba | ||
|
|
056136ef5a | ||
|
|
a423c46f2a | ||
|
|
d89ddb9315 | ||
|
|
16784aa2cc | ||
|
|
88ac2ebc0c | ||
|
|
13dcfec8fe | ||
|
|
20582037c5 | ||
|
|
e983d90a28 | ||
|
|
ea9ad8c5a8 | ||
|
|
93d929a10a | ||
|
|
df9670c58d | ||
|
|
0c5e336ff1 | ||
|
|
f7f5fd4809 | ||
|
|
dff097a992 | ||
|
|
870a47f55d | ||
|
|
f5ae10e3d1 | ||
|
|
41290383e2 | ||
|
|
b9a5ea8f7b | ||
|
|
c0a1cfffa1 | ||
|
|
18161fee38 | ||
|
|
095d7427ba | ||
|
|
da0feb3fa4 | ||
|
|
acc4c374ef | ||
|
|
872843e491 | ||
|
|
565faff754 | ||
|
|
4f89d260b0 | ||
|
|
de5e21bf1a | ||
|
|
909f7039d4 | ||
|
|
abdf4a161a | ||
|
|
77a1a8a23f | ||
|
|
dbc721af3a | ||
|
|
b6611125b6 | ||
|
|
60dd97c7fc | ||
|
|
44e81424f2 | ||
|
|
ed0cc0b56d | ||
|
|
10825e3a95 | ||
|
|
8f7bf1df86 | ||
|
|
79b0bfb272 | ||
|
|
c0537848b3 | ||
|
|
fa30ac8c5d | ||
|
|
616fcb974c | ||
|
|
00d7772f57 | ||
|
|
e258e7c353 | ||
|
|
5cf1e09e81 | ||
|
|
9aa4f3b3b2 | ||
|
|
4dd59b566c | ||
|
|
140a2e0200 | ||
|
|
e6eacbdd56 | ||
|
|
48f13a43b7 | ||
|
|
f5c45bd517 | ||
|
|
9bdea91a70 | ||
|
|
4f808367f8 | ||
|
|
fee50b13a2 | ||
|
|
c6421f8a75 | ||
|
|
d0e87a7487 | ||
|
|
2dc27d6ab4 | ||
|
|
ee97aa0a8a | ||
|
|
c7bb326c78 | ||
|
|
8f5c0c60f5 | ||
|
|
82efe01c70 | ||
|
|
bb466ede66 | ||
|
|
aec2ba2c82 | ||
|
|
ec586a852a | ||
|
|
451ddf50ab | ||
|
|
9dbb2e0abd | ||
|
|
49896afe9f | ||
|
|
1fe08f5973 | ||
|
|
6b014f57e5 | ||
|
|
caa366bc6a | ||
|
|
42ae876711 | ||
|
|
a5ba556fff | ||
|
|
44d088be1e | ||
|
|
dcfbb1998f | ||
|
|
b40985a57c | ||
|
|
f8d32f5328 | ||
|
|
83c30dc4c0 | ||
|
|
6cc2112749 | ||
|
|
05dbbe9681 | ||
|
|
ba236fe258 | ||
|
|
2b5164c956 | ||
|
|
ca2d441b6d | ||
|
|
90da6227b3 | ||
|
|
0e2af11f6a | ||
|
|
88c578bc54 | ||
|
|
f268068457 | ||
|
|
251214dfd9 | ||
|
|
a8ca7baa93 | ||
|
|
9977a6d1d7 | ||
|
|
9d6d1f5715 | ||
|
|
566a9d5541 | ||
|
|
9f83da836d | ||
|
|
2a7af38538 | ||
|
|
7a78527fde | ||
|
|
b572c2b7bc | ||
|
|
10dc90f7fe | ||
|
|
898687ea2e | ||
|
|
8cf3accc53 | ||
|
|
604be5fc82 | ||
|
|
51696bb35d | ||
|
|
f2f4af669d | ||
|
|
ff2772a58c | ||
|
|
9839d5701b | ||
|
|
c1c25868cc | ||
|
|
fdff1bebc9 | ||
|
|
5c514504f7 | ||
|
|
dc8139a1d2 | ||
|
|
8697edc8b7 | ||
|
|
bed4c03a50 | ||
|
|
e041fe130b | ||
|
|
c4ae3e0c3d | ||
|
|
169ab262f5 | ||
|
|
55a9e0ccd1 | ||
|
|
bf7aeb3167 | ||
|
|
0659235e21 | ||
|
|
a07a0935fe | ||
|
|
525a2c71dd | ||
|
|
c6ad8fdaed | ||
|
|
2cbd3faf5a | ||
|
|
51ab891d5c | ||
|
|
bd436ab9de | ||
|
|
e859942fa4 | ||
|
|
3477d265c6 | ||
|
|
97207df705 | ||
|
|
73d07999bf | ||
|
|
af8cf712be | ||
|
|
17c0b9be44 | ||
|
|
d76cbf805a | ||
|
|
5e5de9b41b | ||
|
|
a56b6fea99 | ||
|
|
5a099b7d05 | ||
|
|
59639a0788 | ||
|
|
5a87f04e71 | ||
|
|
fa195bede2 | ||
|
|
4be0a7a215 | ||
|
|
a544fa0f97 | ||
|
|
add113f585 | ||
|
|
59936ef468 | ||
|
|
44985722d2 | ||
|
|
0b7153be86 | ||
|
|
d8b8d75e0f | ||
|
|
d7709deb2b | ||
|
|
3ec834b2e3 | ||
|
|
918a7ec749 | ||
|
|
2ea2abc07d | ||
|
|
839f7bd2b5 | ||
|
|
c81ae5fc20 | ||
|
|
4c41f52828 | ||
|
|
3597192d58 | ||
|
|
1726eb993c | ||
|
|
8ecdc929b4 | ||
|
|
db53859e7a | ||
|
|
b08e0b7102 | ||
|
|
94efae419e | ||
|
|
f33d4e79aa | ||
|
|
40c271cda1 | ||
|
|
13d612f72f | ||
|
|
f124389b66 | ||
|
|
4d286da593 | ||
|
|
680af8eb09 | ||
|
|
1f02428225 | ||
|
|
2c7a89a1db | ||
|
|
028a5c4942 | ||
|
|
8e56fffb33 | ||
|
|
95c3aaec9a | ||
|
|
190cb18ab0 | ||
|
|
19d1b1f532 | ||
|
|
0a1d7b3732 | ||
|
|
08cad30be2 | ||
|
|
eafffc1634 | ||
|
|
36f93649ef | ||
|
|
6fa2cd232d | ||
|
|
5f7ae1f489 | ||
|
|
1f2b604c07 | ||
|
|
d476a3db2c | ||
|
|
68a83500bc | ||
|
|
00fcf6dd72 | ||
|
|
642f0e4740 | ||
|
|
c5cf8e226b | ||
|
|
d79e4da7aa | ||
|
|
6f58fdcb22 | ||
|
|
2b03316cd9 | ||
|
|
184d3802b6 | ||
|
|
228a435ba7 | ||
|
|
9d6cabd18a | ||
|
|
8157f889ce | ||
|
|
736d6a3c19 | ||
|
|
39723bbe60 | ||
|
|
5834231e58 | ||
|
|
e4bb4be855 | ||
|
|
68bc5d2291 | ||
|
|
b87295db93 | ||
|
|
637fbf6c5b | ||
|
|
9d6bcd7705 | ||
|
|
484dfaebce | ||
|
|
1d41e1544a | ||
|
|
da00fc66ee | ||
|
|
4071488ef2 | ||
|
|
bd92c230da | ||
|
|
a98a062347 | ||
|
|
13a674330f | ||
|
|
982867317e | ||
|
|
4de0cd9fcb | ||
|
|
b3ddaa5f02 | ||
|
|
2faa4aa993 | ||
|
|
aeaa59d4b5 | ||
|
|
3e8e9273ca | ||
|
|
d0bfe421b5 | ||
|
|
7f473f56eb | ||
|
|
a29947d47c | ||
|
|
be6cc2c3e6 | ||
|
|
e472cacb3e | ||
|
|
6a3cbea790 | ||
|
|
f97535d87e | ||
|
|
90dc274113 | ||
|
|
40f42db7fa | ||
|
|
09efed50fd | ||
|
|
7de0771883 | ||
|
|
e29b64c5de | ||
|
|
4bed3161f0 | ||
|
|
7307eb54dc | ||
|
|
57e25ae1cd | ||
|
|
b2b13bbe89 | ||
|
|
0b315e97c8 | ||
|
|
dec61fa333 | ||
|
|
7ebef6d838 | ||
|
|
40ff5bf164 | ||
|
|
9fda61abec | ||
|
|
4a71c68e06 | ||
|
|
31497f4bd3 | ||
|
|
6af3a23dd4 | ||
|
|
65ccc99e79 | ||
|
|
cb665d07e0 | ||
|
|
649b7dd162 | ||
|
|
50ebaf25aa | ||
|
|
375a1790e7 | ||
|
|
b187b5c301 | ||
|
|
a53c4e1597 | ||
|
|
fce7b8dc9b | ||
|
|
fc247e4223 | ||
|
|
0390285c4e | ||
|
|
30dbe4978b | ||
|
|
a21f55919b | ||
|
|
79d21489df | ||
|
|
a25ac80777 | ||
|
|
a178c1fb93 | ||
|
|
c4d95de987 | ||
|
|
b7897595eb | ||
|
|
933c786421 | ||
|
|
66f1630f14 | ||
|
|
bb17608ae0 | ||
|
|
421f05eab9 | ||
|
|
9b6448518c | ||
|
|
3fe4261f12 | ||
|
|
7b02673620 | ||
|
|
997f2c098b | ||
|
|
7c814cd2e3 | ||
|
|
41573f1fb2 | ||
|
|
fa6481401d | ||
|
|
fda291b876 | ||
|
|
d33a44e67f | ||
|
|
bdb97d6186 | ||
|
|
7cf75e667d | ||
|
|
e9f531b4aa | ||
|
|
b2b7eb2ded | ||
|
|
3a9b7c592d | ||
|
|
d7ceef104e | ||
|
|
e3cbeec6ee | ||
|
|
04f2e102a1 | ||
|
|
5cca29d1db | ||
|
|
4d3c73f4ca | ||
|
|
a577bf340e | ||
|
|
5c643d6141 | ||
|
|
069fd0a244 | ||
|
|
de13b6edc5 | ||
|
|
303d5d6ff6 | ||
|
|
40b30d1fb1 | ||
|
|
dae6c757b5 | ||
|
|
31ecce3a72 | ||
|
|
13d4563c25 | ||
|
|
e2f48b21ab | ||
|
|
8a94ab676e | ||
|
|
bcb839a7d3 | ||
|
|
30efcf21f0 | ||
|
|
ca40234031 | ||
|
|
592b8c4f4a | ||
|
|
35c0e3cf8c | ||
|
|
60ecbdee8f | ||
|
|
adba1a792a | ||
|
|
e9d0a25436 | ||
|
|
ab6e01e379 | ||
|
|
724f728f60 | ||
|
|
8dbae00847 | ||
|
|
287e06995a | ||
|
|
9e85492b85 | ||
|
|
96245c3cfa | ||
|
|
4194c7fa24 | ||
|
|
71e1577a62 | ||
|
|
df53b97fe4 | ||
|
|
fe3ad4fd60 | ||
|
|
20c8250872 | ||
|
|
1869de7662 | ||
|
|
7c2c8b2a95 | ||
|
|
c094aa82ec | ||
|
|
98a4be475c | ||
|
|
88bb9f422e | ||
|
|
73e58f7af1 | ||
|
|
d02a2a2cfa | ||
|
|
3091e2a771 | ||
|
|
3aa6d03cc1 | ||
|
|
6a5b94ca3b | ||
|
|
229d5e5c80 | ||
|
|
2dad06d59f | ||
|
|
f45340461d | ||
|
|
19a536d869 | ||
|
|
4f0a96c9c7 | ||
|
|
9ec7cd7239 | ||
|
|
ed2d7964ad | ||
|
|
b0b070ffe7 | ||
|
|
3dd3476bfd | ||
|
|
a4342f3997 | ||
|
|
022d4b548a | ||
|
|
49de60d33b | ||
|
|
7b1b082381 | ||
|
|
7d4887b1f1 | ||
|
|
df86efbd43 | ||
|
|
73704c92ba | ||
|
|
5c3d67a811 | ||
|
|
07487b6d20 | ||
|
|
b8866f1d16 | ||
|
|
a8d5ae5213 | ||
|
|
4217ec5308 | ||
|
|
21b51328f9 | ||
|
|
99646d209e | ||
|
|
7fb93d4585 | ||
|
|
51a4657ef7 | ||
|
|
d98eca7260 | ||
|
|
fc7feffaad | ||
|
|
aa584475cc | ||
|
|
218c9199f3 | ||
|
|
4f2d8b0a85 | ||
|
|
a828b15fbe | ||
|
|
9567807144 | ||
|
|
e656aad298 | ||
|
|
b0d1668ab9 | ||
|
|
00618672f5 | ||
|
|
5e10d53ca8 | ||
|
|
6720463799 | ||
|
|
577b730415 | ||
|
|
89df3cc207 | ||
|
|
338bd042b9 | ||
|
|
d45bb14015 | ||
|
|
323c78ef44 | ||
|
|
090a16316c | ||
|
|
c0feb36e70 | ||
|
|
31e6fb154e | ||
|
|
beb5bffaf6 | ||
|
|
9ab84bdc0a | ||
|
|
30ba9a2751 | ||
|
|
3f5f96dcbd | ||
|
|
4dd093b160 | ||
|
|
c0607a0e2a | ||
|
|
9f3ec82cc1 | ||
|
|
de646a5b93 | ||
|
|
b0cb0c1a4a | ||
|
|
042ac8240f | ||
|
|
ded5341da0 | ||
|
|
ed634bc3a4 | ||
|
|
c4d10bc44e | ||
|
|
6f125cc129 | ||
|
|
d9a7348ae1 | ||
|
|
8bd09e39ca | ||
|
|
c877166b4a | ||
|
|
7f234809fc | ||
|
|
88756f3ebf | ||
|
|
0a79f49dc5 | ||
|
|
e4136b0d42 | ||
|
|
d195a12565 | ||
|
|
46a368d2b9 | ||
|
|
c311520968 | ||
|
|
9979de24db | ||
|
|
8d3d3c88d4 | ||
|
|
9a7b0b657e | ||
|
|
19bd5beb96 | ||
|
|
1a9b5760a7 | ||
|
|
90928991b3 | ||
|
|
4693c61305 | ||
|
|
76bb424de0 | ||
|
|
cb603c62d9 | ||
|
|
c12d802811 | ||
|
|
2562f2e9a6 | ||
|
|
2aad7b6979 | ||
|
|
1295c924e1 | ||
|
|
83e55dc09e | ||
|
|
55401116bb | ||
|
|
e275b54f55 | ||
|
|
87ed228fd3 | ||
|
|
a989f60e27 | ||
|
|
2cb3c89570 | ||
|
|
640d6fa474 | ||
|
|
ef08bd48b5 |
@@ -806,11 +806,21 @@ workflows:
|
||||
suite: itest-gateway
|
||||
target: "./itests/gateway_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-get_messages_in_ts
|
||||
suite: itest-get_messages_in_ts
|
||||
target: "./itests/get_messages_in_ts_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-multisig
|
||||
suite: itest-multisig
|
||||
target: "./itests/multisig_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-nonce
|
||||
suite: itest-nonce
|
||||
target: "./itests/nonce_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-paych_api
|
||||
suite: itest-paych_api
|
||||
@@ -831,6 +841,11 @@ workflows:
|
||||
suite: itest-sector_finalize_early
|
||||
target: "./itests/sector_finalize_early_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_miner_collateral
|
||||
suite: itest-sector_miner_collateral
|
||||
target: "./itests/sector_miner_collateral_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-sector_pledge
|
||||
suite: itest-sector_pledge
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Reference
|
||||
# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners
|
||||
|
||||
# Global owners
|
||||
# Ensure maintainers team is a requested reviewer for non-draft PRs
|
||||
* @filecoin-project/lotus-maintainers
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Close and mark stale issue
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 24 hours.'
|
||||
close-issue-message: 'This issue was closed because it is missing author input.'
|
||||
stale-issue-label: 'kind/stale'
|
||||
any-of-labels: 'hint/needs-author-input'
|
||||
days-before-issue-stale: 5
|
||||
days-before-issue-close: 1
|
||||
enable-statistics: true
|
||||
|
||||
|
||||
-257
@@ -1,262 +1,5 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 1.11.0 / 2021-07-22
|
||||
|
||||
This is a **highly recommended** release of Lotus that have many bug fixes, improvements and new features.
|
||||
|
||||
## Highlights
|
||||
- Miner SimultaneousTransfers config ([filecoin-project/lotus#6612](https://github.com/filecoin-project/lotus/pull/6612))
|
||||
- Set `SimultaneousTransfers` in lotus miner config to configure the maximum number of parallel online data transfers, including both storage and retrieval deals.
|
||||
- Dynamic Retrieval pricing ([filecoin-project/lotus#6175](https://github.com/filecoin-project/lotus/pull/6175))
|
||||
- Customize your retrieval ask price, see a quick tutorial [here](https://github.com/filecoin-project/lotus/discussions/6780).
|
||||
- Robust message management ([filecoin-project/lotus#5822](https://github.com/filecoin-project/lotus/pull/5822))
|
||||
- run `lotus mpool manage and follow the instructions!
|
||||
- Demo available at https://www.youtube.com/watch?v=QDocpLQjZgQ.
|
||||
- Add utils to use multisigs as miner owners ([filecoin-project/lotus#6490](https://github.com/filecoin-project/lotus/pull/6490))
|
||||
|
||||
## More New Features
|
||||
- feat: implement lotus-sim ([filecoin-project/lotus#6406](https://github.com/filecoin-project/lotus/pull/6406))
|
||||
- implement a command to export a car ([filecoin-project/lotus#6405](https://github.com/filecoin-project/lotus/pull/6405))
|
||||
- Add a command to get the fees of a deal ([filecoin-project/lotus#5307](https://github.com/filecoin-project/lotus/pull/5307))
|
||||
- run `lotus-shed market get-deal-fees`
|
||||
- Add a command to list retrievals ([filecoin-project/lotus#6337](https://github.com/filecoin-project/lotus/pull/6337))
|
||||
- run `lotus client list-retrievals`
|
||||
- lotus-gateway: add check command ([filecoin-project/lotus#6373](https://github.com/filecoin-project/lotus/pull/6373))
|
||||
- lotus-wallet: JWT Support ([filecoin-project/lotus#6360](https://github.com/filecoin-project/lotus/pull/6360))
|
||||
- Allow starting networks from arbitrary actor versions ([filecoin-project/lotus#6305](https://github.com/filecoin-project/lotus/pull/6305))
|
||||
- oh, snap! ([filecoin-project/lotus#6202](https://github.com/filecoin-project/lotus/pull/6202))
|
||||
- Add a shed util to count 64 GiB miner stats ([filecoin-project/lotus#6290](https://github.com/filecoin-project/lotus/pull/6290))
|
||||
- Introduce stateless offline dealflow, bypassing the FSM/deallists ([filecoin-project/lotus#5961](https://github.com/filecoin-project/lotus/pull/5961))
|
||||
- Transplant some useful commands to lotus-shed actor ([filecoin-project/lotus#5913](https://github.com/filecoin-project/lotus/pull/5913))
|
||||
- run `lotus-shed actor`
|
||||
- actor wrapper codegen ([filecoin-project/lotus#6108](https://github.com/filecoin-project/lotus/pull/6108))
|
||||
- Add a shed util to count miners by post type ([filecoin-project/lotus#6169](https://github.com/filecoin-project/lotus/pull/6169))
|
||||
- shed: command to list duplicate messages in tipsets (steb) ([filecoin-project/lotus#5847](https://github.com/filecoin-project/lotus/pull/5847))
|
||||
- feat: allow checkpointing to forks ([filecoin-project/lotus#6107](https://github.com/filecoin-project/lotus/pull/6107))
|
||||
- Add a CLI tool for miner proving deadline ([filecoin-project/lotus#6132](https://github.com/filecoin-project/lotus/pull/6132))
|
||||
- run `lotus state miner-proving-deadline`
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
- Fix wallet error messages ([filecoin-project/lotus#6594](https://github.com/filecoin-project/lotus/pull/6594))
|
||||
- Fix CircleCI gen ([filecoin-project/lotus#6589](https://github.com/filecoin-project/lotus/pull/6589))
|
||||
- Make query-ask CLI more graceful ([filecoin-project/lotus#6590](https://github.com/filecoin-project/lotus/pull/6590))
|
||||
- scale up sector expiration to avoid sector expire in batch-pre-commit waitting ([filecoin-project/lotus#6566](https://github.com/filecoin-project/lotus/pull/6566))
|
||||
- Fix an error in msigLockCancel ([filecoin-project/lotus#6582](https://github.com/filecoin-project/lotus/pull/6582)
|
||||
- fix circleci being out of sync. ([filecoin-project/lotus#6573](https://github.com/filecoin-project/lotus/pull/6573))
|
||||
- Fix helptext for ask price([filecoin-project/lotus#6560](https://github.com/filecoin-project/lotus/pull/6560))
|
||||
- fix commit finalize failed ([filecoin-project/lotus#6521](https://github.com/filecoin-project/lotus/pull/6521))
|
||||
- Fix soup ([filecoin-project/lotus#6501](https://github.com/filecoin-project/lotus/pull/6501))
|
||||
- fix: pick the correct partitions-per-post limit ([filecoin-project/lotus#6502](https://github.com/filecoin-project/lotus/pull/6502))
|
||||
- sealing: Fix restartSectors race ([filecoin-project/lotus#6495](https://github.com/filecoin-project/lotus/pull/6495))
|
||||
- Fix: correct the change of message size limit ([filecoin-project/lotus#6430](https://github.com/filecoin-project/lotus/pull/6430))
|
||||
- Fix logging of stringified CIDs double-encoded in hex ([filecoin-project/lotus#6413](https://github.com/filecoin-project/lotus/pull/6413))
|
||||
- Fix success handling in Retreival ([filecoin-project/lotus#5921](https://github.com/filecoin-project/lotus/pull/5921))
|
||||
- storagefsm: Fix batch deal packing behavior ([filecoin-project/lotus#6041](https://github.com/filecoin-project/lotus/pull/6041))
|
||||
- events: Fix handling of multiple matched events per epoch ([filecoin-project/lotus#6355](https://github.com/filecoin-project/lotus/pull/6355))
|
||||
- Fix logging around mineOne ([filecoin-project/lotus#6310](https://github.com/filecoin-project/lotus/pull/6310))
|
||||
- Fix shell completions ([filecoin-project/lotus#6316](https://github.com/filecoin-project/lotus/pull/6316))
|
||||
- Allow 8MB sectors in devnet ([filecoin-project/lotus#6312](https://github.com/filecoin-project/lotus/pull/6312))
|
||||
- fix ticket expired ([filecoin-project/lotus#6304](https://github.com/filecoin-project/lotus/pull/6304))
|
||||
- Revert "chore: update go-libp2p" ([filecoin-project/lotus#6306](https://github.com/filecoin-project/lotus/pull/6306))
|
||||
- fix: wait-api should use GetAPI to acquire binary specific API ([filecoin-project/lotus#6246](https://github.com/filecoin-project/lotus/pull/6246))
|
||||
- fix(ci): Updates to lotus CI build process ([filecoin-project/lotus#6256](https://github.com/filecoin-project/lotus/pull/6256))
|
||||
- fix: use a consistent tipset in commands ([filecoin-project/lotus#6142](https://github.com/filecoin-project/lotus/pull/6142))
|
||||
- go mod tidy for lotus-soup testplans ([filecoin-project/lotus#6124](https://github.com/filecoin-project/lotus/pull/6124))
|
||||
- fix testground payment channel tests: use 1 miner ([filecoin-project/lotus#6126](https://github.com/filecoin-project/lotus/pull/6126))
|
||||
- fix: use the parent state when listing actors ([filecoin-project/lotus#6143](https://github.com/filecoin-project/lotus/pull/6143))
|
||||
- Speed up StateListMessages in some cases ([filecoin-project/lotus#6007](https://github.com/filecoin-project/lotus/pull/6007))
|
||||
- fix(splitstore): fix a panic on revert-only head changes ([filecoin-project/lotus#6133](https://github.com/filecoin-project/lotus/pull/6133))
|
||||
- drand: fix beacon cache ([filecoin-project/lotus#6164](https://github.com/filecoin-project/lotus/pull/6164))
|
||||
|
||||
## Improvements
|
||||
- gateway: Add support for Version method ([filecoin-project/lotus#6618](https://github.com/filecoin-project/lotus/pull/6618))
|
||||
- revamped integration test kit (aka. Operation Sparks Joy) ([filecoin-project/lotus#6329](https://github.com/filecoin-project/lotus/pull/6329))
|
||||
- move with changed name ([filecoin-project/lotus#6587](https://github.com/filecoin-project/lotus/pull/6587))
|
||||
- dynamic circleci config for streamlining test execution ([filecoin-project/lotus#6561](https://github.com/filecoin-project/lotus/pull/6561))
|
||||
- extern/storage: add ability to ignore worker resources when scheduling. ([filecoin-project/lotus#6542](https://github.com/filecoin-project/lotus/pull/6542))
|
||||
- Adjust various CLI display ratios to arbitrary precision ([filecoin-project/lotus#6309](https://github.com/filecoin-project/lotus/pull/6309))
|
||||
- Test multicore SDR support ([filecoin-project/lotus#6479](https://github.com/filecoin-project/lotus/pull/6479))
|
||||
- Unit tests for sector batchers ([filecoin-project/lotus#6432](https://github.com/filecoin-project/lotus/pull/6432))
|
||||
- Update chain list with correct help instructions ([filecoin-project/lotus#6465](https://github.com/filecoin-project/lotus/pull/6465))
|
||||
- clean failed sectors in batch commit ([filecoin-project/lotus#6451](https://github.com/filecoin-project/lotus/pull/6451))
|
||||
- itests/kit: add guard to ensure imports from tests only. ([filecoin-project/lotus#6445](https://github.com/filecoin-project/lotus/pull/6445))
|
||||
- consolidate integration tests into `itests` package; create test kit; cleanup ([filecoin-project/lotus#6311](https://github.com/filecoin-project/lotus/pull/6311))
|
||||
- Fee config for sector batching ([filecoin-project/lotus#6420](https://github.com/filecoin-project/lotus/pull/6420))
|
||||
- UX: lotus state power CLI should fail if called with a not-miner ([filecoin-project/lotus#6425](https://github.com/filecoin-project/lotus/pull/6425))
|
||||
- Increase message size limit ([filecoin-project/lotus#6419](https://github.com/filecoin-project/lotus/pull/6419))
|
||||
- polish(stmgr): define ExecMonitor for message application callback ([filecoin-project/lotus#6389](https://github.com/filecoin-project/lotus/pull/6389))
|
||||
- upgrade testground action version ([filecoin-project/lotus#6403](https://github.com/filecoin-project/lotus/pull/6403))
|
||||
- Bypass task scheduler for reading unsealed pieces ([filecoin-project/lotus#6280](https://github.com/filecoin-project/lotus/pull/6280))
|
||||
- testplans: lotus-soup: use default WPoStChallengeWindow ([filecoin-project/lotus#6400](https://github.com/filecoin-project/lotus/pull/6400))
|
||||
- Integration tests for offline deals ([filecoin-project/lotus#6081](https://github.com/filecoin-project/lotus/pull/6081))
|
||||
- Fix some flaky tests ([filecoin-project/lotus#6397](https://github.com/filecoin-project/lotus/pull/6397))
|
||||
- build appimage in CI ([filecoin-project/lotus#6384](https://github.com/filecoin-project/lotus/pull/6384))
|
||||
- Generate AppImage ([filecoin-project/lotus#6208](https://github.com/filecoin-project/lotus/pull/6208))
|
||||
- Add test for AddVerifiedClient ([filecoin-project/lotus#6317](https://github.com/filecoin-project/lotus/pull/6317))
|
||||
- Typo fix in error message: "pubusb" -> "pubsub" ([filecoin-project/lotus#6365](https://github.com/filecoin-project/lotus/pull/6365))
|
||||
- Improve the cli state call command ([filecoin-project/lotus#6226](https://github.com/filecoin-project/lotus/pull/6226))
|
||||
- Upscale mineOne message to a WARN on unexpected ineligibility ([filecoin-project/lotus#6358](https://github.com/filecoin-project/lotus/pull/6358))
|
||||
- Remove few useless variable assignments ([filecoin-project/lotus#6359](https://github.com/filecoin-project/lotus/pull/6359))
|
||||
- Reduce noise from 'peer has different genesis' messages ([filecoin-project/lotus#6357](https://github.com/filecoin-project/lotus/pull/6357))
|
||||
- Get current seal proof when necessary ([filecoin-project/lotus#6339](https://github.com/filecoin-project/lotus/pull/6339))
|
||||
- Remove log line when tracing is not configured ([filecoin-project/lotus#6334](https://github.com/filecoin-project/lotus/pull/6334))
|
||||
- separate tracing environment variables ([filecoin-project/lotus#6323](https://github.com/filecoin-project/lotus/pull/6323))
|
||||
- feat: log dispute rate ([filecoin-project/lotus#6322](https://github.com/filecoin-project/lotus/pull/6322))
|
||||
- Move verifreg shed utils to CLI ([filecoin-project/lotus#6135](https://github.com/filecoin-project/lotus/pull/6135))
|
||||
- consider storiface.PathStorage when calculating storage requirements ([filecoin-project/lotus#6233](https://github.com/filecoin-project/lotus/pull/6233))
|
||||
- `storage` module: add go docs and minor code quality refactors ([filecoin-project/lotus#6259](https://github.com/filecoin-project/lotus/pull/6259))
|
||||
- Increase data transfer timeouts ([filecoin-project/lotus#6300](https://github.com/filecoin-project/lotus/pull/6300))
|
||||
- gateway: spin off from cmd to package ([filecoin-project/lotus#6294](https://github.com/filecoin-project/lotus/pull/6294))
|
||||
- Return total power when GetPowerRaw doesn't find miner claim ([filecoin-project/lotus#4938](https://github.com/filecoin-project/lotus/pull/4938))
|
||||
- add flags to control gateway lookback parameters ([filecoin-project/lotus#6247](https://github.com/filecoin-project/lotus/pull/6247))
|
||||
- chore(ci): Enable build on RC tags ([filecoin-project/lotus#6238](https://github.com/filecoin-project/lotus/pull/6238))
|
||||
- cron-wc ([filecoin-project/lotus#6178](https://github.com/filecoin-project/lotus/pull/6178))
|
||||
- Allow creation of state tree v3s ([filecoin-project/lotus#6167](https://github.com/filecoin-project/lotus/pull/6167))
|
||||
- mpool: Cleanup pre-nv12 selection logic ([filecoin-project/lotus#6148](https://github.com/filecoin-project/lotus/pull/6148))
|
||||
- attempt to do better padding on pieces being written into sectors ([filecoin-project/lotus#5988](https://github.com/filecoin-project/lotus/pull/5988))
|
||||
- remove duplicate ask and calculate ping before lock ([filecoin-project/lotus#5968](https://github.com/filecoin-project/lotus/pull/5968))
|
||||
- flaky tests improvement: separate TestBatchDealInput from TestAPIDealFlow ([filecoin-project/lotus#6141](https://github.com/filecoin-project/lotus/pull/6141))
|
||||
- Testground checks on push ([filecoin-project/lotus#5887](https://github.com/filecoin-project/lotus/pull/5887))
|
||||
- Use EmptyTSK where appropriate ([filecoin-project/lotus#6134](https://github.com/filecoin-project/lotus/pull/6134))
|
||||
- upgrade `lotus-soup` testplans and reduce deals concurrency to a single miner ([filecoin-project/lotus#6122](https://github.com/filecoin-project/lotus/pull/6122)
|
||||
|
||||
## Dependency Updates
|
||||
- downgrade libp2p/go-libp2p-yamux to v0.5.1. ([filecoin-project/lotus#6605](https://github.com/filecoin-project/lotus/pull/6605))
|
||||
- Update libp2p to 0.14.2 ([filecoin-project/lotus#6404](https://github.com/filecoin-project/lotus/pull/6404))
|
||||
- update to markets-v1.4.0 ([filecoin-project/lotus#6369](https://github.com/filecoin-project/lotus/pull/6369))
|
||||
- Use new actor tags ([filecoin-project/lotus#6291](https://github.com/filecoin-project/lotus/pull/6291))
|
||||
- chore: update go-libp2p ([filecoin-project/lotus#6231](https://github.com/filecoin-project/lotus/pull/6231))
|
||||
- Update ffi to proofs v7 ([filecoin-project/lotus#6150](https://github.com/filecoin-project/lotus/pull/6150))
|
||||
|
||||
## Others
|
||||
- Initial draft: basic build instructions on Readme ([filecoin-project/lotus#6498](https://github.com/filecoin-project/lotus/pull/6498))
|
||||
- Remove rc changelog, compile the new changelog for final release only ([filecoin-project/lotus#6444](https://github.com/filecoin-project/lotus/pull/6444))
|
||||
- updated configuration comments for docs ([filecoin-project/lotus#6440](https://github.com/filecoin-project/lotus/pull/6440))
|
||||
- Set ntwk v13 HyperDrive Calibration upgrade epoch ([filecoin-project/lotus#6441](https://github.com/filecoin-project/lotus/pull/6441))
|
||||
- build snapcraft ([filecoin-project/lotus#6388](https://github.com/filecoin-project/lotus/pull/6388))
|
||||
- Fix the doc errors of the sealing config funcs ([filecoin-project/lotus#6399](https://github.com/filecoin-project/lotus/pull/6399))
|
||||
- Add doc on gas balancing ([filecoin-project/lotus#6392](https://github.com/filecoin-project/lotus/pull/6392))
|
||||
- Add interop network ([filecoin-project/lotus#6387](https://github.com/filecoin-project/lotus/pull/6387))
|
||||
- Network version 13 (v1.11) ([filecoin-project/lotus#6342](https://github.com/filecoin-project/lotus/pull/6342))
|
||||
- Add a warning to the release issue template ([filecoin-project/lotus#6374](https://github.com/filecoin-project/lotus/pull/6374))
|
||||
- Update RELEASE_ISSUE_TEMPLATE.md ([filecoin-project/lotus#6236](https://github.com/filecoin-project/lotus/pull/6236))
|
||||
- Delete CODEOWNERS ([filecoin-project/lotus#6289](https://github.com/filecoin-project/lotus/pull/6289))
|
||||
- Feat/nerpa v4 ([filecoin-project/lotus#6248](https://github.com/filecoin-project/lotus/pull/6248))
|
||||
- Introduce a release issue template ([filecoin-project/lotus#5826](https://github.com/filecoin-project/lotus/pull/5826))
|
||||
- This is a 1:1 forward-port of PR#6183 from 1.9.x to master ([filecoin-project/lotus#6196](https://github.com/filecoin-project/lotus/pull/6196))
|
||||
- Update cli gen ([filecoin-project/lotus#6155](https://github.com/filecoin-project/lotus/pull/6155))
|
||||
- Generate CLI docs ([filecoin-project/lotus#6145](https://github.com/filecoin-project/lotus/pull/6145))
|
||||
|
||||
## Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| @raulk | 118 | +11972/-10860 | 472 |
|
||||
| @magik6k | 65 | +10824/-4158 | 353 |
|
||||
| @aarshkshah1992 | 59 | +8057/-3355 | 224 |
|
||||
| @arajasek | 41 | +8786/-1691 | 331 |
|
||||
| @Stebalien | 106 | +7653/-2718 | 273 |
|
||||
| dirkmc | 11 | +2580/-1371 | 77 |
|
||||
| @dirkmc | 39 | +1865/-1194 | 79 |
|
||||
| @Kubuxu | 19 | +1973/-485 | 81 |
|
||||
| @vyzo | 4 | +1748/-330 | 50 |
|
||||
| @aarshkshah1992 | 5 | +1462/-213 | 27 |
|
||||
| @coryschwartz | 35 | +568/-206 | 59 |
|
||||
| @chadwick2143 | 3 | +739/-1 | 4 |
|
||||
| @ribasushi | 21 | +487/-164 | 36 |
|
||||
| @hannahhoward | 5 | +544/-5 | 19 |
|
||||
| @jennijuju | 9 | +241/-174 | 19 |
|
||||
| @frrist | 1 | +137/-88 | 7 |
|
||||
| @travisperson | 3 | +175/-6 | 7 |
|
||||
| @wadeAlexC | 1 | +48/-129 | 1 |
|
||||
| @whyrusleeping | 8 | +161/-13 | 11 |
|
||||
| lotus | 1 | +114/-46 | 1 |
|
||||
| @nonsense | 8 | +107/-53 | 20 |
|
||||
| @rjan90 | 4 | +115/-33 | 4 |
|
||||
| @ZenGround0 | 3 | +114/-1 | 4 |
|
||||
| @Aloxaf | 1 | +43/-61 | 7 |
|
||||
| @yaohcn | 4 | +89/-9 | 5 |
|
||||
| @mitchellsoo | 1 | +51/-0 | 1 |
|
||||
| @placer14 | 3 | +28/-18 | 4 |
|
||||
| @jennijuju | 6 | +9/-14 | 6 |
|
||||
| @Frank | 2 | +11/-10 | 2 |
|
||||
| @wangchao | 3 | +5/-4 | 4 |
|
||||
| @Steve Loeppky | 1 | +7/-1 | 1 |
|
||||
| @Lion | 1 | +4/-2 | 1 |
|
||||
| @Mimir | 1 | +2/-2 | 1 |
|
||||
| @raulk | 1 | +1/-1 | 1 |
|
||||
| @Jack Yao | 1 | +1/-1 | 1 |
|
||||
| @IPFSUnion | 1 | +1/-1 | 1 |
|
||||
|
||||
# 1.10.1 / 2021-07-05
|
||||
|
||||
This is an optional but **highly recommended** release of Lotus for lotus miners that has many bug fixes and improvements based on the feedback we got from the community since HyperDrive.
|
||||
|
||||
## New Features
|
||||
- commit batch: AggregateAboveBaseFee config #6650
|
||||
- `AggregateAboveBaseFee` is added to miner sealing configuration for setting the network base fee to start aggregating proofs. When the network base fee is lower than this value, the prove commits will be submitted individually via `ProveCommitSector`. According to the [Batch Incentive Alignment](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0013.md#batch-incentive-alignment) introduced in FIP-0013, we recommend miners to set this value to 0.15 nanoFIL(which is the default value) to avoid unexpected aggregation fee in burn and enjoy the most benefits of aggregation!
|
||||
|
||||
## Bug Fixes
|
||||
- storage: Fix FinalizeSector with sectors in storage paths #6652
|
||||
- Fix tiny error in check-client-datacap #6664
|
||||
- Fix: precommit_batch method used the wrong cfg.PreCommitBatchWait #6658
|
||||
- to optimize the batchwait #6636
|
||||
- fix getTicket: sector precommitted but expired case #6635
|
||||
- handleSubmitCommitAggregate() exception handling #6595
|
||||
- remove precommit check in handleCommitFailed #6634
|
||||
- ensure agg fee is adequate
|
||||
- fix: miner balance is not enough, so that ProveCommitAggregate msg exec failed #6623
|
||||
- commit batch: Initialize the FailedSectors map #6647
|
||||
|
||||
Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| @magik6k| 7 | +151/-56 | 21 |
|
||||
| @llifezou | 4 | +59/-20 | 4 |
|
||||
| @johnli-helloworld | 2 | +45/-14 | 4 |
|
||||
| @wangchao | 1 | +1/-27 | 1 |
|
||||
| Jerry | 2 | +9/-4 | 2 |
|
||||
| @zhoutian527 | 1 | +2/-2 | 1 |
|
||||
| @ribasushi| 1 | +1/-1 | 1 |
|
||||
|
||||
||||||| 764fa9dae
|
||||
=======
|
||||
# 1.10.1 / 2021-07-05
|
||||
|
||||
This is an optional but **highly recommended** release of Lotus for lotus miners that has many bug fixes and improvements based on the feedback we got from the community since HyperDrive.
|
||||
|
||||
## New Features
|
||||
- commit batch: AggregateAboveBaseFee config #6650
|
||||
- `AggregateAboveBaseFee` is added to miner sealing configuration for setting the network base fee to start aggregating proofs. When the network base fee is lower than this value, the prove commits will be submitted individually via `ProveCommitSector`. According to the [Batch Incentive Alignment](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0013.md#batch-incentive-alignment) introduced in FIP-0013, we recommend miners to set this value to 0.15 nanoFIL(which is the default value) to avoid unexpected aggregation fee in burn and enjoy the most benefits of aggregation!
|
||||
|
||||
## Bug Fixes
|
||||
- storage: Fix FinalizeSector with sectors in storage paths #6652
|
||||
- Fix tiny error in check-client-datacap #6664
|
||||
- Fix: precommit_batch method used the wrong cfg.PreCommitBatchWait #6658
|
||||
- to optimize the batchwait #6636
|
||||
- fix getTicket: sector precommitted but expired case #6635
|
||||
- handleSubmitCommitAggregate() exception handling #6595
|
||||
- remove precommit check in handleCommitFailed #6634
|
||||
- ensure agg fee is adequate
|
||||
- fix: miner balance is not enough, so that ProveCommitAggregate msg exec failed #6623
|
||||
- commit batch: Initialize the FailedSectors map #6647
|
||||
|
||||
Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| @magik6k| 7 | +151/-56 | 21 |
|
||||
| @llifezou | 4 | +59/-20 | 4 |
|
||||
| @johnli-helloworld | 2 | +45/-14 | 4 |
|
||||
| @wangchao | 1 | +1/-27 | 1 |
|
||||
| Jerry | 2 | +9/-4 | 2 |
|
||||
| @zhoutian527 | 1 | +2/-2 | 1 |
|
||||
| @ribasushi| 1 | +1/-1 | 1 |
|
||||
|
||||
|
||||
>>>>>>> releases
|
||||
# 1.10.0 / 2021-06-23
|
||||
|
||||
This is a mandatory release of Lotus that introduces Filecoin network v13, codenamed the HyperDrive upgrade. The
|
||||
|
||||
@@ -18,6 +18,8 @@ Lotus is an implementation of the Filecoin Distributed Storage Network. For more
|
||||
|
||||
## Building & Documentation
|
||||
|
||||
> Note: The default `master` branch is the dev branch, please use with caution. For the latest stable version, checkout the most recent [`Latest release`](https://github.com/filecoin-project/lotus/releases).
|
||||
|
||||
For complete instructions on how to build, install and setup lotus, please visit [https://docs.filecoin.io/get-started/lotus](https://docs.filecoin.io/get-started/lotus/). Basic build instructions can be found further down in this readme.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
+12
-8
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
@@ -14,7 +15,6 @@ import (
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -104,6 +104,9 @@ type FullNode interface {
|
||||
// specified block.
|
||||
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]Message, error) //perm:read
|
||||
|
||||
// ChainGetMessagesInTipset returns message stores in current tipset
|
||||
ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]Message, error) //perm:read
|
||||
|
||||
// ChainGetTipSetByHeight looks back for a tipset at the specified epoch.
|
||||
// If there are no blocks at the specified epoch, a tipset at an earlier epoch
|
||||
// will be returned.
|
||||
@@ -320,7 +323,7 @@ type FullNode interface {
|
||||
// ClientImport imports file under the specified path into filestore.
|
||||
ClientImport(ctx context.Context, ref FileRef) (*ImportRes, error) //perm:admin
|
||||
// ClientRemoveImport removes file import
|
||||
ClientRemoveImport(ctx context.Context, importID multistore.StoreID) error //perm:admin
|
||||
ClientRemoveImport(ctx context.Context, importID importmgr.ImportID) error //perm:admin
|
||||
// ClientStartDeal proposes a deal with a miner.
|
||||
ClientStartDeal(ctx context.Context, params *StartDealParams) (*cid.Cid, error) //perm:admin
|
||||
// ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking.
|
||||
@@ -712,16 +715,17 @@ type MinerSectors struct {
|
||||
|
||||
type ImportRes struct {
|
||||
Root cid.Cid
|
||||
ImportID multistore.StoreID
|
||||
ImportID importmgr.ImportID
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Key multistore.StoreID
|
||||
Key importmgr.ImportID
|
||||
Err string
|
||||
|
||||
Root *cid.Cid
|
||||
Source string
|
||||
FilePath string
|
||||
Root *cid.Cid
|
||||
Source string
|
||||
FilePath string
|
||||
CARv2FilePath string
|
||||
}
|
||||
|
||||
type DealInfo struct {
|
||||
@@ -904,7 +908,7 @@ type RetrievalOrder struct {
|
||||
Piece *cid.Cid
|
||||
Size uint64
|
||||
|
||||
LocalStore *multistore.StoreID // if specified, get data from local store
|
||||
LocalCARV2FilePath string // if specified, get data from a local CARv2 file.
|
||||
// TODO: support offset
|
||||
Total types.BigInt
|
||||
UnsealPrice types.BigInt
|
||||
|
||||
+35
-4
@@ -55,6 +55,13 @@ type StorageMiner interface {
|
||||
// Get the status of a given sector by ID
|
||||
SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (SectorInfo, error) //perm:read
|
||||
|
||||
// Add piece to an open sector. If no sectors with enough space are open,
|
||||
// either a new sector will be created, or this call will block until more
|
||||
// sectors can be created.
|
||||
SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPieceSize, r storage.Data, d PieceDealInfo) (SectorOffset, error) //perm:admin
|
||||
|
||||
SectorsUnsealPiece(ctx context.Context, sector storage.SectorRef, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, commd *cid.Cid) error //perm:admin
|
||||
|
||||
// List all staged sectors
|
||||
SectorsList(context.Context) ([]abi.SectorNumber, error) //perm:read
|
||||
|
||||
@@ -135,8 +142,8 @@ type StorageMiner interface {
|
||||
StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]stores.StorageInfo, error) //perm:admin
|
||||
StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error //perm:admin
|
||||
StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error) //perm:admin
|
||||
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error) //perm:admin
|
||||
|
||||
StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error) //perm:admin
|
||||
StorageLocal(ctx context.Context) (map[stores.ID]string, error) //perm:admin
|
||||
StorageStat(ctx context.Context, id stores.ID) (fsutil.FsStat, error) //perm:admin
|
||||
|
||||
@@ -279,15 +286,17 @@ type AddrUse int
|
||||
const (
|
||||
PreCommitAddr AddrUse = iota
|
||||
CommitAddr
|
||||
DealPublishAddr
|
||||
PoStAddr
|
||||
|
||||
TerminateSectorsAddr
|
||||
)
|
||||
|
||||
type AddressConfig struct {
|
||||
PreCommitControl []address.Address
|
||||
CommitControl []address.Address
|
||||
TerminateControl []address.Address
|
||||
PreCommitControl []address.Address
|
||||
CommitControl []address.Address
|
||||
TerminateControl []address.Address
|
||||
DealPublishControl []address.Address
|
||||
|
||||
DisableOwnerFallback bool
|
||||
DisableWorkerFallback bool
|
||||
@@ -300,3 +309,25 @@ type PendingDealInfo struct {
|
||||
PublishPeriodStart time.Time
|
||||
PublishPeriod time.Duration
|
||||
}
|
||||
|
||||
type SectorOffset struct {
|
||||
Sector abi.SectorNumber
|
||||
Offset abi.PaddedPieceSize
|
||||
}
|
||||
|
||||
// DealInfo is a tuple of deal identity and its schedule
|
||||
type PieceDealInfo struct {
|
||||
PublishCid *cid.Cid
|
||||
DealID abi.DealID
|
||||
DealProposal *market.DealProposal
|
||||
DealSchedule DealSchedule
|
||||
KeepUnsealed bool
|
||||
}
|
||||
|
||||
// DealSchedule communicates the time interval of a storage deal. The deal must
|
||||
// appear in a sealed (proven) sector no later than StartEpoch, otherwise it
|
||||
// is invalid.
|
||||
type DealSchedule struct {
|
||||
StartEpoch abi.ChainEpoch
|
||||
EndEpoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
+379
@@ -8,6 +8,7 @@ import (
|
||||
"sort"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
market "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -738,3 +739,381 @@ func (t *SealSeed) UnmarshalCBOR(r io.Reader) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
func (t *PieceDealInfo) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{165}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.PublishCid (cid.Cid) (struct)
|
||||
if len("PublishCid") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"PublishCid\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("PublishCid"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("PublishCid")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.PublishCid == nil {
|
||||
if _, err := w.Write(cbg.CborNull); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteCidBuf(scratch, w, *t.PublishCid); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.PublishCid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// t.DealID (abi.DealID) (uint64)
|
||||
if len("DealID") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealID\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealID"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealID")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.DealID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.DealProposal (market.DealProposal) (struct)
|
||||
if len("DealProposal") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealProposal\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealProposal"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealProposal")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.DealProposal.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.DealSchedule (api.DealSchedule) (struct)
|
||||
if len("DealSchedule") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealSchedule\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealSchedule"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealSchedule")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.DealSchedule.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.KeepUnsealed (bool) (bool)
|
||||
if len("KeepUnsealed") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"KeepUnsealed\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("KeepUnsealed"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("KeepUnsealed")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cbg.WriteBool(w, t.KeepUnsealed); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *PieceDealInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = PieceDealInfo{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajMap {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("PieceDealInfo: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// t.PublishCid (cid.Cid) (struct)
|
||||
case "PublishCid":
|
||||
|
||||
{
|
||||
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.PublishCid: %w", err)
|
||||
}
|
||||
|
||||
t.PublishCid = &c
|
||||
}
|
||||
|
||||
}
|
||||
// t.DealID (abi.DealID) (uint64)
|
||||
case "DealID":
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.DealID = abi.DealID(extra)
|
||||
|
||||
}
|
||||
// t.DealProposal (market.DealProposal) (struct)
|
||||
case "DealProposal":
|
||||
|
||||
{
|
||||
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.DealProposal = new(market.DealProposal)
|
||||
if err := t.DealProposal.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealProposal pointer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// t.DealSchedule (api.DealSchedule) (struct)
|
||||
case "DealSchedule":
|
||||
|
||||
{
|
||||
|
||||
if err := t.DealSchedule.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealSchedule: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.KeepUnsealed (bool) (bool)
|
||||
case "KeepUnsealed":
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajOther {
|
||||
return fmt.Errorf("booleans must be major type 7")
|
||||
}
|
||||
switch extra {
|
||||
case 20:
|
||||
t.KeepUnsealed = false
|
||||
case 21:
|
||||
t.KeepUnsealed = true
|
||||
default:
|
||||
return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra)
|
||||
}
|
||||
|
||||
default:
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
cbg.ScanForLinks(r, func(cid.Cid) {})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (t *DealSchedule) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{162}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.StartEpoch (abi.ChainEpoch) (int64)
|
||||
if len("StartEpoch") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"StartEpoch\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("StartEpoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("StartEpoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.StartEpoch >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.StartEpoch)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.StartEpoch-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.EndEpoch (abi.ChainEpoch) (int64)
|
||||
if len("EndEpoch") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"EndEpoch\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("EndEpoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("EndEpoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.EndEpoch >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.EndEpoch)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.EndEpoch-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DealSchedule) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = DealSchedule{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajMap {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("DealSchedule: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// t.StartEpoch (abi.ChainEpoch) (int64)
|
||||
case "StartEpoch":
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.StartEpoch = abi.ChainEpoch(extraI)
|
||||
}
|
||||
// t.EndEpoch (abi.ChainEpoch) (int64)
|
||||
case "EndEpoch":
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.EndEpoch = abi.ChainEpoch(extraI)
|
||||
}
|
||||
|
||||
default:
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
cbg.ScanForLinks(r, func(cid.Cid) {})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+28
-13
@@ -52,8 +52,30 @@ func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Heade
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func getPushUrl(addr string) (string, error) {
|
||||
pushUrl, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch pushUrl.Scheme {
|
||||
case "ws":
|
||||
pushUrl.Scheme = "http"
|
||||
case "wss":
|
||||
pushUrl.Scheme = "https"
|
||||
}
|
||||
///rpc/v0 -> /rpc/streams/v0/push
|
||||
|
||||
pushUrl.Path = path.Join(pushUrl.Path, "../streams/v0/push")
|
||||
return pushUrl.String(), nil
|
||||
}
|
||||
|
||||
// NewStorageMinerRPCV0 creates a new http jsonrpc client for miner
|
||||
func NewStorageMinerRPCV0(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (v0api.StorageMiner, jsonrpc.ClientCloser, error) {
|
||||
pushUrl, err := getPushUrl(addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var res v0api.StorageMinerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
@@ -61,26 +83,19 @@ func NewStorageMinerRPCV0(ctx context.Context, addr string, requestHeader http.H
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
opts...,
|
||||
append([]jsonrpc.Option{
|
||||
rpcenc.ReaderParamEncoder(pushUrl),
|
||||
}, opts...)...,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func NewWorkerRPCV0(ctx context.Context, addr string, requestHeader http.Header) (api.Worker, jsonrpc.ClientCloser, error) {
|
||||
u, err := url.Parse(addr)
|
||||
func NewWorkerRPCV0(ctx context.Context, addr string, requestHeader http.Header) (v0api.Worker, jsonrpc.ClientCloser, error) {
|
||||
pushUrl, err := getPushUrl(addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "ws":
|
||||
u.Scheme = "http"
|
||||
case "wss":
|
||||
u.Scheme = "https"
|
||||
}
|
||||
///rpc/v0 -> /rpc/streams/v0/push
|
||||
|
||||
u.Path = path.Join(u.Path, "../streams/v0/push")
|
||||
|
||||
var res api.WorkerStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
@@ -88,7 +103,7 @@ func NewWorkerRPCV0(ctx context.Context, addr string, requestHeader http.Header)
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
rpcenc.ReaderParamEncoder(u.String()),
|
||||
rpcenc.ReaderParamEncoder(pushUrl),
|
||||
jsonrpc.WithNoReconnect(),
|
||||
jsonrpc.WithTimeout(30*time.Second),
|
||||
)
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
@@ -27,7 +29,6 @@ import (
|
||||
filestore2 "github.com/filecoin-project/go-fil-markets/filestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -89,6 +90,7 @@ func init() {
|
||||
addExample(&pid)
|
||||
|
||||
multistoreIDExample := multistore.StoreID(50)
|
||||
storeIDExample := importmgr.ImportID(50)
|
||||
|
||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1_1)
|
||||
@@ -119,6 +121,8 @@ func init() {
|
||||
addExample(time.Minute)
|
||||
addExample(datatransfer.TransferID(3))
|
||||
addExample(datatransfer.Ongoing)
|
||||
addExample(storeIDExample)
|
||||
addExample(&storeIDExample)
|
||||
addExample(multistoreIDExample)
|
||||
addExample(&multistoreIDExample)
|
||||
addExample(retrievalmarket.ClientEventDealAccepted)
|
||||
@@ -175,7 +179,7 @@ func init() {
|
||||
|
||||
// miner specific
|
||||
addExample(filestore2.Path(".lotusminer/fstmp123"))
|
||||
si := multistore.StoreID(12)
|
||||
si := uint64(12)
|
||||
addExample(&si)
|
||||
addExample(retrievalmarket.DealID(5))
|
||||
addExample(abi.ActorID(1000))
|
||||
|
||||
+17
-2
@@ -14,7 +14,6 @@ import (
|
||||
retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
auth "github.com/filecoin-project/go-jsonrpc/auth"
|
||||
multistore "github.com/filecoin-project/go-multistore"
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
big "github.com/filecoin-project/go-state-types/big"
|
||||
crypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
dtypes "github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
importmgr "github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
@@ -194,6 +194,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetMessage(arg0, arg1 interface{}) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessage", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessage), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetMessagesInTipset mocks base method.
|
||||
func (m *MockFullNode) ChainGetMessagesInTipset(arg0 context.Context, arg1 types.TipSetKey) ([]api.Message, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChainGetMessagesInTipset", arg0, arg1)
|
||||
ret0, _ := ret[0].([]api.Message)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ChainGetMessagesInTipset indicates an expected call of ChainGetMessagesInTipset.
|
||||
func (mr *MockFullNodeMockRecorder) ChainGetMessagesInTipset(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessagesInTipset", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessagesInTipset), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetNode mocks base method.
|
||||
func (m *MockFullNode) ChainGetNode(arg0 context.Context, arg1 string) (*api.IpldObject, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -716,7 +731,7 @@ func (mr *MockFullNodeMockRecorder) ClientQueryAsk(arg0, arg1, arg2 interface{})
|
||||
}
|
||||
|
||||
// ClientRemoveImport mocks base method.
|
||||
func (m *MockFullNode) ClientRemoveImport(arg0 context.Context, arg1 multistore.StoreID) error {
|
||||
func (m *MockFullNode) ClientRemoveImport(arg0 context.Context, arg1 importmgr.ImportID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClientRemoveImport", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
+34
-4
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
@@ -29,6 +28,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -127,6 +127,8 @@ type FullNodeStruct struct {
|
||||
|
||||
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
|
||||
ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]Message, error) `perm:"read"`
|
||||
|
||||
ChainGetNode func(p0 context.Context, p1 string) (*IpldObject, error) `perm:"read"`
|
||||
|
||||
ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]Message, error) `perm:"read"`
|
||||
@@ -197,7 +199,7 @@ type FullNodeStruct struct {
|
||||
|
||||
ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"`
|
||||
|
||||
ClientRemoveImport func(p0 context.Context, p1 multistore.StoreID) error `perm:"admin"`
|
||||
ClientRemoveImport func(p0 context.Context, p1 importmgr.ImportID) error `perm:"admin"`
|
||||
|
||||
ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"`
|
||||
|
||||
@@ -665,6 +667,8 @@ type StorageMinerStruct struct {
|
||||
|
||||
SealingSchedDiag func(p0 context.Context, p1 bool) (interface{}, error) `perm:"admin"`
|
||||
|
||||
SectorAddPieceToAny func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storage.Data, p3 PieceDealInfo) (SectorOffset, error) `perm:"admin"`
|
||||
|
||||
SectorCommitFlush func(p0 context.Context) ([]sealiface.CommitBatchRes, error) `perm:"admin"`
|
||||
|
||||
SectorCommitPending func(p0 context.Context) ([]abi.SectorID, error) `perm:"admin"`
|
||||
@@ -703,6 +707,8 @@ type StorageMinerStruct struct {
|
||||
|
||||
SectorsSummary func(p0 context.Context) (map[SectorState]int, error) `perm:"read"`
|
||||
|
||||
SectorsUnsealPiece func(p0 context.Context, p1 storage.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error `perm:"admin"`
|
||||
|
||||
SectorsUpdate func(p0 context.Context, p1 abi.SectorNumber, p2 SectorState) error `perm:"admin"`
|
||||
|
||||
StorageAddLocal func(p0 context.Context, p1 string) error `perm:"admin"`
|
||||
@@ -1097,6 +1103,14 @@ func (s *FullNodeStub) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.M
|
||||
return nil, xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]Message, error) {
|
||||
return s.Internal.ChainGetMessagesInTipset(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]Message, error) {
|
||||
return *new([]Message), xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetNode(p0 context.Context, p1 string) (*IpldObject, error) {
|
||||
return s.Internal.ChainGetNode(p0, p1)
|
||||
}
|
||||
@@ -1377,11 +1391,11 @@ func (s *FullNodeStub) ClientQueryAsk(p0 context.Context, p1 peer.ID, p2 address
|
||||
return nil, xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 importmgr.ImportID) error {
|
||||
return s.Internal.ClientRemoveImport(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStub) ClientRemoveImport(p0 context.Context, p1 importmgr.ImportID) error {
|
||||
return xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
@@ -3153,6 +3167,14 @@ func (s *StorageMinerStub) SealingSchedDiag(p0 context.Context, p1 bool) (interf
|
||||
return nil, xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) SectorAddPieceToAny(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storage.Data, p3 PieceDealInfo) (SectorOffset, error) {
|
||||
return s.Internal.SectorAddPieceToAny(p0, p1, p2, p3)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) SectorAddPieceToAny(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storage.Data, p3 PieceDealInfo) (SectorOffset, error) {
|
||||
return *new(SectorOffset), xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) SectorCommitFlush(p0 context.Context) ([]sealiface.CommitBatchRes, error) {
|
||||
return s.Internal.SectorCommitFlush(p0)
|
||||
}
|
||||
@@ -3305,6 +3327,14 @@ func (s *StorageMinerStub) SectorsSummary(p0 context.Context) (map[SectorState]i
|
||||
return *new(map[SectorState]int), xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) SectorsUnsealPiece(p0 context.Context, p1 storage.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error {
|
||||
return s.Internal.SectorsUnsealPiece(p0, p1, p2, p3, p4, p5)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) SectorsUnsealPiece(p0 context.Context, p1 storage.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error {
|
||||
return xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) SectorsUpdate(p0 context.Context, p1 abi.SectorNumber, p2 SectorState) error {
|
||||
return s.Internal.SectorsUpdate(p0, p1, p2)
|
||||
}
|
||||
|
||||
+5
-2
@@ -8,10 +8,10 @@ import (
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
@@ -92,6 +92,9 @@ type FullNode interface {
|
||||
// specified block.
|
||||
ChainGetParentMessages(ctx context.Context, blockCid cid.Cid) ([]api.Message, error) //perm:read
|
||||
|
||||
// ChainGetMessagesInTipset returns message stores in current tipset
|
||||
ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) //perm:read
|
||||
|
||||
// ChainGetTipSetByHeight looks back for a tipset at the specified epoch.
|
||||
// If there are no blocks at the specified epoch, a tipset at an earlier epoch
|
||||
// will be returned.
|
||||
@@ -301,7 +304,7 @@ type FullNode interface {
|
||||
// ClientImport imports file under the specified path into filestore.
|
||||
ClientImport(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) //perm:admin
|
||||
// ClientRemoveImport removes file import
|
||||
ClientRemoveImport(ctx context.Context, importID multistore.StoreID) error //perm:admin
|
||||
ClientRemoveImport(ctx context.Context, importID importmgr.ImportID) error //perm:admin
|
||||
// ClientStartDeal proposes a deal with a miner.
|
||||
ClientStartDeal(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) //perm:admin
|
||||
// ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking.
|
||||
|
||||
+14
-4
@@ -10,7 +10,6 @@ import (
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
@@ -22,6 +21,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -45,6 +45,8 @@ type FullNodeStruct struct {
|
||||
|
||||
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
|
||||
ChainGetMessagesInTipset func(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) `perm:"read"`
|
||||
|
||||
ChainGetNode func(p0 context.Context, p1 string) (*api.IpldObject, error) `perm:"read"`
|
||||
|
||||
ChainGetParentMessages func(p0 context.Context, p1 cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
@@ -115,7 +117,7 @@ type FullNodeStruct struct {
|
||||
|
||||
ClientQueryAsk func(p0 context.Context, p1 peer.ID, p2 address.Address) (*storagemarket.StorageAsk, error) `perm:"read"`
|
||||
|
||||
ClientRemoveImport func(p0 context.Context, p1 multistore.StoreID) error `perm:"admin"`
|
||||
ClientRemoveImport func(p0 context.Context, p1 importmgr.ImportID) error `perm:"admin"`
|
||||
|
||||
ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"`
|
||||
|
||||
@@ -514,6 +516,14 @@ func (s *FullNodeStub) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.M
|
||||
return nil, xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) {
|
||||
return s.Internal.ChainGetMessagesInTipset(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]api.Message, error) {
|
||||
return *new([]api.Message), xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetNode(p0 context.Context, p1 string) (*api.IpldObject, error) {
|
||||
return s.Internal.ChainGetNode(p0, p1)
|
||||
}
|
||||
@@ -794,11 +804,11 @@ func (s *FullNodeStub) ClientQueryAsk(p0 context.Context, p1 peer.ID, p2 address
|
||||
return nil, xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 importmgr.ImportID) error {
|
||||
return s.Internal.ClientRemoveImport(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStub) ClientRemoveImport(p0 context.Context, p1 importmgr.ImportID) error {
|
||||
return xerrors.New("method not supported")
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
auth "github.com/filecoin-project/go-jsonrpc/auth"
|
||||
multistore "github.com/filecoin-project/go-multistore"
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
big "github.com/filecoin-project/go-state-types/big"
|
||||
crypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
dtypes "github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
importmgr "github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
@@ -194,6 +194,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetMessage(arg0, arg1 interface{}) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessage", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessage), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetMessagesInTipset mocks base method.
|
||||
func (m *MockFullNode) ChainGetMessagesInTipset(arg0 context.Context, arg1 types.TipSetKey) ([]api.Message, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChainGetMessagesInTipset", arg0, arg1)
|
||||
ret0, _ := ret[0].([]api.Message)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ChainGetMessagesInTipset indicates an expected call of ChainGetMessagesInTipset.
|
||||
func (mr *MockFullNodeMockRecorder) ChainGetMessagesInTipset(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetMessagesInTipset", reflect.TypeOf((*MockFullNode)(nil).ChainGetMessagesInTipset), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetNode mocks base method.
|
||||
func (m *MockFullNode) ChainGetNode(arg0 context.Context, arg1 string) (*api.IpldObject, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -716,7 +731,7 @@ func (mr *MockFullNodeMockRecorder) ClientQueryAsk(arg0, arg1, arg2 interface{})
|
||||
}
|
||||
|
||||
// ClientRemoveImport mocks base method.
|
||||
func (m *MockFullNode) ClientRemoveImport(arg0 context.Context, arg1 multistore.StoreID) error {
|
||||
func (m *MockFullNode) ClientRemoveImport(arg0 context.Context, arg1 importmgr.ImportID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClientRemoveImport", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ var (
|
||||
FullAPIVersion0 = newVer(1, 3, 0)
|
||||
FullAPIVersion1 = newVer(2, 1, 0)
|
||||
|
||||
MinerAPIVersion0 = newVer(1, 1, 0)
|
||||
MinerAPIVersion0 = newVer(1, 2, 0)
|
||||
WorkerAPIVersion0 = newVer(1, 1, 0)
|
||||
)
|
||||
|
||||
|
||||
+133
-48
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"sync"
|
||||
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"github.com/dgraph-io/badger/v2/options"
|
||||
@@ -73,20 +73,16 @@ func (b *badgerLogger) Warningf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
const (
|
||||
stateOpen int64 = iota
|
||||
stateOpen = iota
|
||||
stateClosing
|
||||
stateClosed
|
||||
)
|
||||
|
||||
// Blockstore is a badger-backed IPLD blockstore.
|
||||
//
|
||||
// NOTE: once Close() is called, methods will try their best to return
|
||||
// ErrBlockstoreClosed. This will guaranteed to happen for all subsequent
|
||||
// operation calls after Close() has returned, but it may not happen for
|
||||
// operations in progress. Those are likely to fail with a different error.
|
||||
type Blockstore struct {
|
||||
// state is accessed atomically
|
||||
state int64
|
||||
stateLk sync.RWMutex
|
||||
state int
|
||||
viewers sync.WaitGroup
|
||||
|
||||
DB *badger.DB
|
||||
|
||||
@@ -97,6 +93,8 @@ type Blockstore struct {
|
||||
|
||||
var _ blockstore.Blockstore = (*Blockstore)(nil)
|
||||
var _ blockstore.Viewer = (*Blockstore)(nil)
|
||||
var _ blockstore.BlockstoreIterator = (*Blockstore)(nil)
|
||||
var _ blockstore.BlockstoreGC = (*Blockstore)(nil)
|
||||
var _ io.Closer = (*Blockstore)(nil)
|
||||
|
||||
// Open creates a new badger-backed blockstore, with the supplied options.
|
||||
@@ -124,53 +122,82 @@ func Open(opts Options) (*Blockstore, error) {
|
||||
// Close closes the store. If the store has already been closed, this noops and
|
||||
// returns an error, even if the first closure resulted in error.
|
||||
func (b *Blockstore) Close() error {
|
||||
if !atomic.CompareAndSwapInt64(&b.state, stateOpen, stateClosing) {
|
||||
b.stateLk.Lock()
|
||||
if b.state != stateOpen {
|
||||
b.stateLk.Unlock()
|
||||
return nil
|
||||
}
|
||||
b.state = stateClosing
|
||||
b.stateLk.Unlock()
|
||||
|
||||
defer func() {
|
||||
b.stateLk.Lock()
|
||||
b.state = stateClosed
|
||||
b.stateLk.Unlock()
|
||||
}()
|
||||
|
||||
// wait for all accesses to complete
|
||||
b.viewers.Wait()
|
||||
|
||||
defer atomic.StoreInt64(&b.state, stateClosed)
|
||||
return b.DB.Close()
|
||||
}
|
||||
|
||||
func (b *Blockstore) access() error {
|
||||
b.stateLk.RLock()
|
||||
defer b.stateLk.RUnlock()
|
||||
|
||||
if b.state != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
}
|
||||
|
||||
b.viewers.Add(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Blockstore) isOpen() bool {
|
||||
b.stateLk.RLock()
|
||||
defer b.stateLk.RUnlock()
|
||||
|
||||
return b.state == stateOpen
|
||||
}
|
||||
|
||||
// CollectGarbage runs garbage collection on the value log
|
||||
func (b *Blockstore) CollectGarbage() error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
// compact first to gather the necessary statistics for GC
|
||||
nworkers := runtime.NumCPU() / 2
|
||||
if nworkers < 2 {
|
||||
nworkers = 2
|
||||
}
|
||||
|
||||
err := b.DB.Flatten(nworkers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
for err == nil {
|
||||
err = b.DB.RunValueLogGC(0.125)
|
||||
}
|
||||
|
||||
if err == badger.ErrNoRewrite {
|
||||
// not really an error in this case
|
||||
// not really an error in this case, it signals the end of GC
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Compact runs a synchronous compaction
|
||||
func (b *Blockstore) Compact() error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
}
|
||||
|
||||
nworkers := runtime.NumCPU() / 2
|
||||
if nworkers < 2 {
|
||||
nworkers = 2
|
||||
}
|
||||
|
||||
return b.DB.Flatten(nworkers)
|
||||
}
|
||||
|
||||
// View implements blockstore.Viewer, which leverages zero-copy read-only
|
||||
// access to values.
|
||||
func (b *Blockstore) View(cid cid.Cid, fn func([]byte) error) error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(cid)
|
||||
if pooled {
|
||||
@@ -191,9 +218,10 @@ func (b *Blockstore) View(cid cid.Cid, fn func([]byte) error) error {
|
||||
|
||||
// Has implements Blockstore.Has.
|
||||
func (b *Blockstore) Has(cid cid.Cid) (bool, error) {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return false, ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(cid)
|
||||
if pooled {
|
||||
@@ -221,9 +249,10 @@ func (b *Blockstore) Get(cid cid.Cid) (blocks.Block, error) {
|
||||
return nil, blockstore.ErrNotFound
|
||||
}
|
||||
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return nil, ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(cid)
|
||||
if pooled {
|
||||
@@ -250,9 +279,10 @@ func (b *Blockstore) Get(cid cid.Cid) (blocks.Block, error) {
|
||||
|
||||
// GetSize implements Blockstore.GetSize.
|
||||
func (b *Blockstore) GetSize(cid cid.Cid) (int, error) {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return -1, ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(cid)
|
||||
if pooled {
|
||||
@@ -279,9 +309,10 @@ func (b *Blockstore) GetSize(cid cid.Cid) (int, error) {
|
||||
|
||||
// Put implements Blockstore.Put.
|
||||
func (b *Blockstore) Put(block blocks.Block) error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(block.Cid())
|
||||
if pooled {
|
||||
@@ -299,9 +330,10 @@ func (b *Blockstore) Put(block blocks.Block) error {
|
||||
|
||||
// PutMany implements Blockstore.PutMany.
|
||||
func (b *Blockstore) PutMany(blocks []blocks.Block) error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
// toReturn tracks the byte slices to return to the pool, if we're using key
|
||||
// prefixing. we can't return each slice to the pool after each Set, because
|
||||
@@ -338,9 +370,10 @@ func (b *Blockstore) PutMany(blocks []blocks.Block) error {
|
||||
|
||||
// DeleteBlock implements Blockstore.DeleteBlock.
|
||||
func (b *Blockstore) DeleteBlock(cid cid.Cid) error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
k, pooled := b.PooledStorageKey(cid)
|
||||
if pooled {
|
||||
@@ -353,9 +386,10 @@ func (b *Blockstore) DeleteBlock(cid cid.Cid) error {
|
||||
}
|
||||
|
||||
func (b *Blockstore) DeleteMany(cids []cid.Cid) error {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
// toReturn tracks the byte slices to return to the pool, if we're using key
|
||||
// prefixing. we can't return each slice to the pool after each Set, because
|
||||
@@ -392,8 +426,8 @@ func (b *Blockstore) DeleteMany(cids []cid.Cid) error {
|
||||
|
||||
// AllKeysChan implements Blockstore.AllKeysChan.
|
||||
func (b *Blockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
return nil, ErrBlockstoreClosed
|
||||
if err := b.access(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txn := b.DB.NewTransaction(false)
|
||||
@@ -405,6 +439,7 @@ func (b *Blockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
|
||||
ch := make(chan cid.Cid)
|
||||
go func() {
|
||||
defer b.viewers.Done()
|
||||
defer close(ch)
|
||||
defer iter.Close()
|
||||
|
||||
@@ -415,7 +450,7 @@ func (b *Blockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
if ctx.Err() != nil {
|
||||
return // context has fired.
|
||||
}
|
||||
if atomic.LoadInt64(&b.state) != stateOpen {
|
||||
if !b.isOpen() {
|
||||
// open iterators will run even after the database is closed...
|
||||
return // closing, yield.
|
||||
}
|
||||
@@ -442,6 +477,56 @@ func (b *Blockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// Implementation of BlockstoreIterator interface
|
||||
func (b *Blockstore) ForEachKey(f func(cid.Cid) error) error {
|
||||
if err := b.access(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer b.viewers.Done()
|
||||
|
||||
txn := b.DB.NewTransaction(false)
|
||||
defer txn.Discard()
|
||||
|
||||
opts := badger.IteratorOptions{PrefetchSize: 100}
|
||||
if b.prefixing {
|
||||
opts.Prefix = b.prefix
|
||||
}
|
||||
|
||||
iter := txn.NewIterator(opts)
|
||||
defer iter.Close()
|
||||
|
||||
var buf []byte
|
||||
for iter.Rewind(); iter.Valid(); iter.Next() {
|
||||
if !b.isOpen() {
|
||||
return ErrBlockstoreClosed
|
||||
}
|
||||
|
||||
k := iter.Item().Key()
|
||||
if b.prefixing {
|
||||
k = k[b.prefixLen:]
|
||||
}
|
||||
|
||||
klen := base32.RawStdEncoding.DecodedLen(len(k))
|
||||
if klen > len(buf) {
|
||||
buf = make([]byte, klen)
|
||||
}
|
||||
|
||||
n, err := base32.RawStdEncoding.Decode(buf, k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c := cid.NewCidV1(cid.Raw, buf[:n])
|
||||
|
||||
err = f(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HashOnRead implements Blockstore.HashOnRead. It is not supported by this
|
||||
// blockstore.
|
||||
func (b *Blockstore) HashOnRead(_ bool) {
|
||||
|
||||
@@ -30,6 +30,16 @@ type BatchDeleter interface {
|
||||
DeleteMany(cids []cid.Cid) error
|
||||
}
|
||||
|
||||
// BlockstoreIterator is a trait for efficient iteration
|
||||
type BlockstoreIterator interface {
|
||||
ForEachKey(func(cid.Cid) error) error
|
||||
}
|
||||
|
||||
// BlockstoreGC is a trait for blockstores that support online garbage collection
|
||||
type BlockstoreGC interface {
|
||||
CollectGarbage() error
|
||||
}
|
||||
|
||||
// WrapIDStore wraps the underlying blockstore in an "identity" blockstore.
|
||||
// The ID store filters out all puts for blocks with CIDs using the "identity"
|
||||
// hash function. It also extracts inlined blocks from CIDs using the identity
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package blockstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
var _ Blockstore = (*discardstore)(nil)
|
||||
|
||||
type discardstore struct {
|
||||
bs Blockstore
|
||||
}
|
||||
|
||||
func NewDiscardStore(bs Blockstore) Blockstore {
|
||||
return &discardstore{bs: bs}
|
||||
}
|
||||
|
||||
func (b *discardstore) Has(cid cid.Cid) (bool, error) {
|
||||
return b.bs.Has(cid)
|
||||
}
|
||||
|
||||
func (b *discardstore) HashOnRead(hor bool) {
|
||||
b.bs.HashOnRead(hor)
|
||||
}
|
||||
|
||||
func (b *discardstore) Get(cid cid.Cid) (blocks.Block, error) {
|
||||
return b.bs.Get(cid)
|
||||
}
|
||||
|
||||
func (b *discardstore) GetSize(cid cid.Cid) (int, error) {
|
||||
return b.bs.GetSize(cid)
|
||||
}
|
||||
|
||||
func (b *discardstore) View(cid cid.Cid, f func([]byte) error) error {
|
||||
return b.bs.View(cid, f)
|
||||
}
|
||||
|
||||
func (b *discardstore) Put(blk blocks.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *discardstore) PutMany(blks []blocks.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *discardstore) DeleteBlock(cid cid.Cid) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *discardstore) DeleteMany(cids []cid.Cid) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *discardstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
return b.bs.AllKeysChan(ctx)
|
||||
}
|
||||
|
||||
func (b *discardstore) Close() error {
|
||||
if c, ok := b.bs.(io.Closer); ok {
|
||||
return c.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
# SplitStore: An actively scalable blockstore for the Filecoin chain
|
||||
|
||||
The SplitStore was first introduced in lotus v1.5.1, as an experiment
|
||||
in reducing the performance impact of large blockstores.
|
||||
|
||||
With lotus v1.11.1, we introduce the next iteration in design and
|
||||
implementation, which we call SplitStore v1.
|
||||
|
||||
The new design (see [#6474](https://github.com/filecoin-project/lotus/pull/6474)
|
||||
evolves the splitstore to be a freestanding compacting blockstore that
|
||||
allows us to keep a small (60-100GB) working set in a hot blockstore
|
||||
and reliably archive out of scope objects in a coldstore. The
|
||||
coldstore can also be a discard store, whereby out of scope objects
|
||||
are discarded or a regular badger blockstore (the default), which can
|
||||
be periodically garbage collected according to configurable user
|
||||
retention policies.
|
||||
|
||||
To enable the splitstore, edit `.lotus/config.toml` and add the following:
|
||||
```
|
||||
[Chainstore]
|
||||
EnableSplitstore = true
|
||||
```
|
||||
|
||||
If you intend to use the discard coldstore, your also need to add the following:
|
||||
```
|
||||
[Chainstore.Splitstore]
|
||||
ColdStoreType = "discard"
|
||||
```
|
||||
In general you _should not_ have to use the discard store, unless you
|
||||
are running a network booster or have very constrained hardware with
|
||||
not enough disk space to maintain a coldstore, even with garbage
|
||||
collection.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
When the splitstore is first enabled, the existing blockstore becomes
|
||||
the coldstore and a fresh hotstore is initialized.
|
||||
|
||||
The hotstore is warmed up on first startup so as to load all chain
|
||||
headers and state roots in the current head. This allows us to
|
||||
immediately gain the performance benefits of a smallerblockstore which
|
||||
can be substantial for full archival nodes.
|
||||
|
||||
All new writes are directed to the hotstore, while reads first hit the
|
||||
hotstore, with fallback to the coldstore.
|
||||
|
||||
Once 5 finalities have ellapsed, and every finality henceforth, the
|
||||
blockstore _compacts_. Compaction is the process of moving all
|
||||
unreachable objects within the last 4 finalities from the hotstore to
|
||||
the coldstore. If the system is configured with a discard coldstore,
|
||||
these objects are discarded. Note that chain headers, all the way to
|
||||
genesis, are considered reachable. Stateroots and messages are
|
||||
considered reachable only within the last 4 finalities, unless there
|
||||
is a live reference to them.
|
||||
|
||||
## Compaction
|
||||
|
||||
Compaction works transactionally with the following algorithm:
|
||||
- We prepare a transaction, whereby all i/o referenced objects through the API are tracked.
|
||||
- We walk the chain and mark reachable objects, keeping 4 finalities of state roots and messages and all headers all the way to genesis.
|
||||
- Once the chain walk is complete, we begin full transaction protection with concurrent marking; we walk and mark all references created during the chain walk. On the same time, all I/O through the API concurrently marks objects as live references.
|
||||
- We collect cold objects by iterating through the hotstore and checking the mark set; if an object is not marked, then it is candidate for purge.
|
||||
- When running with a coldstore, we next copy all cold objects to the coldstore.
|
||||
- At this point we are ready to begin purging:
|
||||
- We sort cold objects heaviest first, so as to never delete the consituents of a DAG before the DAG itself (which would leave dangling references)
|
||||
- We delete in small batches taking a lock; each batch is checked again for marks, from the concurrent transactional mark, so as to never delete anything live
|
||||
- We then end the transaction and compact/gc the hotstore.
|
||||
|
||||
## Coldstore Garbage Collection
|
||||
|
||||
TBD -- see [#6577](https://github.com/filecoin-project/lotus/issues/6577)
|
||||
@@ -0,0 +1,273 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type debugLog struct {
|
||||
readLog, writeLog, deleteLog, stackLog *debugLogOp
|
||||
|
||||
stackMx sync.Mutex
|
||||
stackMap map[string]string
|
||||
}
|
||||
|
||||
type debugLogOp struct {
|
||||
path string
|
||||
mx sync.Mutex
|
||||
log *os.File
|
||||
count int
|
||||
}
|
||||
|
||||
func openDebugLog(path string) (*debugLog, error) {
|
||||
basePath := filepath.Join(path, "debug")
|
||||
err := os.MkdirAll(basePath, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
readLog, err := openDebugLogOp(basePath, "read.log")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
writeLog, err := openDebugLogOp(basePath, "write.log")
|
||||
if err != nil {
|
||||
_ = readLog.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deleteLog, err := openDebugLogOp(basePath, "delete.log")
|
||||
if err != nil {
|
||||
_ = readLog.Close()
|
||||
_ = writeLog.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stackLog, err := openDebugLogOp(basePath, "stack.log")
|
||||
if err != nil {
|
||||
_ = readLog.Close()
|
||||
_ = writeLog.Close()
|
||||
_ = deleteLog.Close()
|
||||
return nil, xerrors.Errorf("error opening stack log: %w", err)
|
||||
}
|
||||
|
||||
return &debugLog{
|
||||
readLog: readLog,
|
||||
writeLog: writeLog,
|
||||
deleteLog: deleteLog,
|
||||
stackLog: stackLog,
|
||||
stackMap: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *debugLog) LogReadMiss(cid cid.Cid) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
stack := d.getStack()
|
||||
err := d.readLog.Log("%s %s %s\n", d.timestamp(), cid, stack)
|
||||
if err != nil {
|
||||
log.Warnf("error writing read log: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *debugLog) LogWrite(blk blocks.Block) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var stack string
|
||||
if enableDebugLogWriteTraces {
|
||||
stack = " " + d.getStack()
|
||||
}
|
||||
|
||||
err := d.writeLog.Log("%s %s%s\n", d.timestamp(), blk.Cid(), stack)
|
||||
if err != nil {
|
||||
log.Warnf("error writing write log: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *debugLog) LogWriteMany(blks []blocks.Block) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var stack string
|
||||
if enableDebugLogWriteTraces {
|
||||
stack = " " + d.getStack()
|
||||
}
|
||||
|
||||
now := d.timestamp()
|
||||
for _, blk := range blks {
|
||||
err := d.writeLog.Log("%s %s%s\n", now, blk.Cid(), stack)
|
||||
if err != nil {
|
||||
log.Warnf("error writing write log: %s", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *debugLog) LogDelete(cids []cid.Cid) {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := d.timestamp()
|
||||
for _, c := range cids {
|
||||
err := d.deleteLog.Log("%s %s\n", now, c)
|
||||
if err != nil {
|
||||
log.Warnf("error writing delete log: %s", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *debugLog) Flush() {
|
||||
if d == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// rotate non-empty logs
|
||||
d.readLog.Rotate()
|
||||
d.writeLog.Rotate()
|
||||
d.deleteLog.Rotate()
|
||||
d.stackLog.Rotate()
|
||||
}
|
||||
|
||||
func (d *debugLog) Close() error {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err1 := d.readLog.Close()
|
||||
err2 := d.writeLog.Close()
|
||||
err3 := d.deleteLog.Close()
|
||||
err4 := d.stackLog.Close()
|
||||
|
||||
return multierr.Combine(err1, err2, err3, err4)
|
||||
}
|
||||
|
||||
func (d *debugLog) getStack() string {
|
||||
sk := d.getNormalizedStackTrace()
|
||||
hash := sha256.Sum256([]byte(sk))
|
||||
key := string(hash[:])
|
||||
|
||||
d.stackMx.Lock()
|
||||
repr, ok := d.stackMap[key]
|
||||
if !ok {
|
||||
repr = hex.EncodeToString(hash[:])
|
||||
d.stackMap[key] = repr
|
||||
|
||||
err := d.stackLog.Log("%s\n%s\n", repr, sk)
|
||||
if err != nil {
|
||||
log.Warnf("error writing stack trace for %s: %s", repr, err)
|
||||
}
|
||||
}
|
||||
d.stackMx.Unlock()
|
||||
|
||||
return repr
|
||||
}
|
||||
|
||||
func (d *debugLog) getNormalizedStackTrace() string {
|
||||
sk := string(debug.Stack())
|
||||
|
||||
// Normalization for deduplication
|
||||
// skip first line -- it's the goroutine
|
||||
// for each line that ends in a ), remove the call args -- these are the registers
|
||||
lines := strings.Split(sk, "\n")[1:]
|
||||
for i, line := range lines {
|
||||
if len(line) > 0 && line[len(line)-1] == ')' {
|
||||
idx := strings.LastIndex(line, "(")
|
||||
if idx < 0 {
|
||||
continue
|
||||
}
|
||||
lines[i] = line[:idx]
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
func (d *debugLog) timestamp() string {
|
||||
ts, _ := time.Now().MarshalText()
|
||||
return string(ts)
|
||||
}
|
||||
|
||||
func openDebugLogOp(basePath, name string) (*debugLogOp, error) {
|
||||
path := filepath.Join(basePath, name)
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error opening %s: %w", name, err)
|
||||
}
|
||||
|
||||
return &debugLogOp{path: path, log: file}, nil
|
||||
}
|
||||
|
||||
func (d *debugLogOp) Close() error {
|
||||
d.mx.Lock()
|
||||
defer d.mx.Unlock()
|
||||
|
||||
return d.log.Close()
|
||||
}
|
||||
|
||||
func (d *debugLogOp) Log(template string, arg ...interface{}) error {
|
||||
d.mx.Lock()
|
||||
defer d.mx.Unlock()
|
||||
|
||||
d.count++
|
||||
_, err := fmt.Fprintf(d.log, template, arg...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *debugLogOp) Rotate() {
|
||||
d.mx.Lock()
|
||||
defer d.mx.Unlock()
|
||||
|
||||
if d.count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
err := d.log.Close()
|
||||
if err != nil {
|
||||
log.Warnf("error closing log (file: %s): %s", d.path, err)
|
||||
return
|
||||
}
|
||||
|
||||
arxivPath := fmt.Sprintf("%s-%d", d.path, time.Now().Unix())
|
||||
err = os.Rename(d.path, arxivPath)
|
||||
if err != nil {
|
||||
log.Warnf("error moving log (file: %s): %s", d.path, err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
cmd := exec.Command("gzip", arxivPath)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Warnf("error compressing log (file: %s): %s", arxivPath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
d.count = 0
|
||||
d.log, err = os.OpenFile(d.path, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Warnf("error opening log (file: %s): %s", d.path, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
var errMarkSetClosed = errors.New("markset closed")
|
||||
|
||||
// MarkSet is a utility to keep track of seen CID, and later query for them.
|
||||
//
|
||||
// * If the expected dataset is large, it can be backed by a datastore (e.g. bbolt).
|
||||
// * If a probabilistic result is acceptable, it can be backed by a bloom filter (default).
|
||||
// * If a probabilistic result is acceptable, it can be backed by a bloom filter
|
||||
type MarkSet interface {
|
||||
Mark(cid.Cid) error
|
||||
Has(cid.Cid) (bool, error)
|
||||
Close() error
|
||||
SetConcurrent()
|
||||
}
|
||||
|
||||
// markBytes is deliberately a non-nil empty byte slice for serialization.
|
||||
var markBytes = []byte{}
|
||||
|
||||
type MarkSetEnv interface {
|
||||
Create(name string, sizeHint int64) (MarkSet, error)
|
||||
Close() error
|
||||
@@ -28,10 +28,10 @@ type MarkSetEnv interface {
|
||||
|
||||
func OpenMarkSetEnv(path string, mtype string) (MarkSetEnv, error) {
|
||||
switch mtype {
|
||||
case "", "bloom":
|
||||
case "bloom":
|
||||
return NewBloomMarkSetEnv()
|
||||
case "bolt":
|
||||
return NewBoltMarkSetEnv(filepath.Join(path, "markset.bolt"))
|
||||
case "map":
|
||||
return NewMapMarkSetEnv()
|
||||
default:
|
||||
return nil, xerrors.Errorf("unknown mark set type %s", mtype)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package splitstore
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -21,7 +22,9 @@ var _ MarkSetEnv = (*BloomMarkSetEnv)(nil)
|
||||
|
||||
type BloomMarkSet struct {
|
||||
salt []byte
|
||||
mx sync.RWMutex
|
||||
bf *bbloom.Bloom
|
||||
ts bool
|
||||
}
|
||||
|
||||
var _ MarkSet = (*BloomMarkSet)(nil)
|
||||
@@ -64,14 +67,41 @@ func (s *BloomMarkSet) saltedKey(cid cid.Cid) []byte {
|
||||
}
|
||||
|
||||
func (s *BloomMarkSet) Mark(cid cid.Cid) error {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
}
|
||||
|
||||
if s.bf == nil {
|
||||
return errMarkSetClosed
|
||||
}
|
||||
|
||||
s.bf.Add(s.saltedKey(cid))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BloomMarkSet) Has(cid cid.Cid) (bool, error) {
|
||||
if s.ts {
|
||||
s.mx.RLock()
|
||||
defer s.mx.RUnlock()
|
||||
}
|
||||
|
||||
if s.bf == nil {
|
||||
return false, errMarkSetClosed
|
||||
}
|
||||
|
||||
return s.bf.Has(s.saltedKey(cid)), nil
|
||||
}
|
||||
|
||||
func (s *BloomMarkSet) Close() error {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
}
|
||||
s.bf = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BloomMarkSet) SetConcurrent() {
|
||||
s.ts = true
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
type BoltMarkSetEnv struct {
|
||||
db *bolt.DB
|
||||
}
|
||||
|
||||
var _ MarkSetEnv = (*BoltMarkSetEnv)(nil)
|
||||
|
||||
type BoltMarkSet struct {
|
||||
db *bolt.DB
|
||||
bucketId []byte
|
||||
}
|
||||
|
||||
var _ MarkSet = (*BoltMarkSet)(nil)
|
||||
|
||||
func NewBoltMarkSetEnv(path string) (*BoltMarkSetEnv, error) {
|
||||
db, err := bolt.Open(path, 0644,
|
||||
&bolt.Options{
|
||||
Timeout: 1 * time.Second,
|
||||
NoSync: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BoltMarkSetEnv{db: db}, nil
|
||||
}
|
||||
|
||||
func (e *BoltMarkSetEnv) Create(name string, hint int64) (MarkSet, error) {
|
||||
bucketId := []byte(name)
|
||||
err := e.db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(bucketId)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error creating bolt db bucket %s: %w", name, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BoltMarkSet{db: e.db, bucketId: bucketId}, nil
|
||||
}
|
||||
|
||||
func (e *BoltMarkSetEnv) Close() error {
|
||||
return e.db.Close()
|
||||
}
|
||||
|
||||
func (s *BoltMarkSet) Mark(cid cid.Cid) error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
return b.Put(cid.Hash(), markBytes)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltMarkSet) Has(cid cid.Cid) (result bool, err error) {
|
||||
err = s.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
v := b.Get(cid.Hash())
|
||||
result = v != nil
|
||||
return nil
|
||||
})
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *BoltMarkSet) Close() error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
return tx.DeleteBucket(s.bucketId)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type MapMarkSetEnv struct{}
|
||||
|
||||
var _ MarkSetEnv = (*MapMarkSetEnv)(nil)
|
||||
|
||||
type MapMarkSet struct {
|
||||
mx sync.RWMutex
|
||||
set map[string]struct{}
|
||||
|
||||
ts bool
|
||||
}
|
||||
|
||||
var _ MarkSet = (*MapMarkSet)(nil)
|
||||
|
||||
func NewMapMarkSetEnv() (*MapMarkSetEnv, error) {
|
||||
return &MapMarkSetEnv{}, nil
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
return &MapMarkSet{
|
||||
set: make(map[string]struct{}, sizeHint),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) Mark(cid cid.Cid) error {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
}
|
||||
|
||||
if s.set == nil {
|
||||
return errMarkSetClosed
|
||||
}
|
||||
|
||||
s.set[string(cid.Hash())] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) Has(cid cid.Cid) (bool, error) {
|
||||
if s.ts {
|
||||
s.mx.RLock()
|
||||
defer s.mx.RUnlock()
|
||||
}
|
||||
|
||||
if s.set == nil {
|
||||
return false, errMarkSetClosed
|
||||
}
|
||||
|
||||
_, ok := s.set[string(cid.Hash())]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) Close() error {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
}
|
||||
s.set = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) SetConcurrent() {
|
||||
s.ts = true
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
func TestBoltMarkSet(t *testing.T) {
|
||||
testMarkSet(t, "bolt")
|
||||
func TestMapMarkSet(t *testing.T) {
|
||||
testMarkSet(t, "map")
|
||||
}
|
||||
|
||||
func TestBloomMarkSet(t *testing.T) {
|
||||
|
||||
+263
-797
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
)
|
||||
|
||||
type exposedSplitStore struct {
|
||||
s *SplitStore
|
||||
}
|
||||
|
||||
var _ bstore.Blockstore = (*exposedSplitStore)(nil)
|
||||
|
||||
func (s *SplitStore) Expose() bstore.Blockstore {
|
||||
return &exposedSplitStore{s: s}
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) DeleteBlock(_ cid.Cid) error {
|
||||
return errors.New("DeleteBlock: operation not supported")
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) DeleteMany(_ []cid.Cid) error {
|
||||
return errors.New("DeleteMany: operation not supported")
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) Has(c cid.Cid) (bool, error) {
|
||||
if isIdentiyCid(c) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
has, err := es.s.hot.Has(c)
|
||||
if has || err != nil {
|
||||
return has, err
|
||||
}
|
||||
|
||||
return es.s.cold.Has(c)
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) Get(c cid.Cid) (blocks.Block, error) {
|
||||
if isIdentiyCid(c) {
|
||||
data, err := decodeIdentityCid(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return blocks.NewBlockWithCid(data, c)
|
||||
}
|
||||
|
||||
blk, err := es.s.hot.Get(c)
|
||||
switch err {
|
||||
case bstore.ErrNotFound:
|
||||
return es.s.cold.Get(c)
|
||||
default:
|
||||
return blk, err
|
||||
}
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) GetSize(c cid.Cid) (int, error) {
|
||||
if isIdentiyCid(c) {
|
||||
data, err := decodeIdentityCid(c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
size, err := es.s.hot.GetSize(c)
|
||||
switch err {
|
||||
case bstore.ErrNotFound:
|
||||
return es.s.cold.GetSize(c)
|
||||
default:
|
||||
return size, err
|
||||
}
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) Put(blk blocks.Block) error {
|
||||
return es.s.Put(blk)
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) PutMany(blks []blocks.Block) error {
|
||||
return es.s.PutMany(blks)
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
return es.s.AllKeysChan(ctx)
|
||||
}
|
||||
|
||||
func (es *exposedSplitStore) HashOnRead(enabled bool) {}
|
||||
|
||||
func (es *exposedSplitStore) View(c cid.Cid, f func([]byte) error) error {
|
||||
if isIdentiyCid(c) {
|
||||
data, err := decodeIdentityCid(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f(data)
|
||||
}
|
||||
|
||||
err := es.s.hot.View(c, f)
|
||||
switch err {
|
||||
case bstore.ErrNotFound:
|
||||
return es.s.cold.View(c, f)
|
||||
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
)
|
||||
|
||||
func (s *SplitStore) gcHotstore() {
|
||||
if err := s.gcBlockstoreOnline(s.hot); err != nil {
|
||||
log.Warnf("error garbage collecting hostore: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SplitStore) gcBlockstoreOnline(b bstore.Blockstore) error {
|
||||
if gc, ok := b.(bstore.BlockstoreGC); ok {
|
||||
log.Info("garbage collecting blockstore")
|
||||
startGC := time.Now()
|
||||
|
||||
if err := gc.CollectGarbage(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infow("garbage collecting hotstore done", "took", time.Since(startGC))
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("blockstore doesn't support online gc: %T", b)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package splitstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
@@ -21,22 +23,34 @@ import (
|
||||
|
||||
func init() {
|
||||
CompactionThreshold = 5
|
||||
CompactionCold = 1
|
||||
CompactionBoundary = 2
|
||||
logging.SetLogLevel("splitstore", "DEBUG")
|
||||
}
|
||||
|
||||
func testSplitStore(t *testing.T, cfg *Config) {
|
||||
chain := &mockChain{t: t}
|
||||
// genesis
|
||||
genBlock := mock.MkBlock(nil, 0, 0)
|
||||
genTs := mock.TipSet(genBlock)
|
||||
chain.push(genTs)
|
||||
|
||||
// the myriads of stores
|
||||
ds := dssync.MutexWrap(datastore.NewMapDatastore())
|
||||
hot := blockstore.NewMemorySync()
|
||||
cold := blockstore.NewMemorySync()
|
||||
hot := newMockStore()
|
||||
cold := newMockStore()
|
||||
|
||||
// this is necessary to avoid the garbage mock puts in the blocks
|
||||
garbage := blocks.NewBlock([]byte{1, 2, 3})
|
||||
err := cold.Put(garbage)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// genesis
|
||||
genBlock := mock.MkBlock(nil, 0, 0)
|
||||
genBlock.Messages = garbage.Cid()
|
||||
genBlock.ParentMessageReceipts = garbage.Cid()
|
||||
genBlock.ParentStateRoot = garbage.Cid()
|
||||
genBlock.Timestamp = uint64(time.Now().Unix())
|
||||
|
||||
genTs := mock.TipSet(genBlock)
|
||||
chain.push(genTs)
|
||||
|
||||
// put the genesis block to cold store
|
||||
blk, err := genBlock.ToStorageBlock()
|
||||
@@ -62,12 +76,22 @@ func testSplitStore(t *testing.T, cfg *Config) {
|
||||
}
|
||||
|
||||
// make some tipsets, but not enough to cause compaction
|
||||
mkBlock := func(curTs *types.TipSet, i int) *types.TipSet {
|
||||
mkBlock := func(curTs *types.TipSet, i int, stateRoot blocks.Block) *types.TipSet {
|
||||
blk := mock.MkBlock(curTs, uint64(i), uint64(i))
|
||||
|
||||
blk.Messages = garbage.Cid()
|
||||
blk.ParentMessageReceipts = garbage.Cid()
|
||||
blk.ParentStateRoot = stateRoot.Cid()
|
||||
blk.Timestamp = uint64(time.Now().Unix())
|
||||
|
||||
sblk, err := blk.ToStorageBlock()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ss.Put(stateRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ss.Put(sblk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -78,18 +102,6 @@ func testSplitStore(t *testing.T, cfg *Config) {
|
||||
return ts
|
||||
}
|
||||
|
||||
mkGarbageBlock := func(curTs *types.TipSet, i int) {
|
||||
blk := mock.MkBlock(curTs, uint64(i), uint64(i))
|
||||
sblk, err := blk.ToStorageBlock()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ss.Put(sblk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
waitForCompaction := func() {
|
||||
for atomic.LoadInt32(&ss.compacting) == 1 {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -98,105 +110,63 @@ func testSplitStore(t *testing.T, cfg *Config) {
|
||||
|
||||
curTs := genTs
|
||||
for i := 1; i < 5; i++ {
|
||||
curTs = mkBlock(curTs, i)
|
||||
stateRoot := blocks.NewBlock([]byte{byte(i), 3, 3, 7})
|
||||
curTs = mkBlock(curTs, i, stateRoot)
|
||||
waitForCompaction()
|
||||
}
|
||||
|
||||
mkGarbageBlock(genTs, 1)
|
||||
|
||||
// count objects in the cold and hot stores
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
countBlocks := func(bs blockstore.Blockstore) int {
|
||||
count := 0
|
||||
ch, err := bs.AllKeysChan(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for range ch {
|
||||
_ = bs.(blockstore.BlockstoreIterator).ForEachKey(func(_ cid.Cid) error {
|
||||
count++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return count
|
||||
}
|
||||
|
||||
coldCnt := countBlocks(cold)
|
||||
hotCnt := countBlocks(hot)
|
||||
|
||||
if coldCnt != 1 {
|
||||
t.Errorf("expected %d blocks, but got %d", 1, coldCnt)
|
||||
if coldCnt != 2 {
|
||||
t.Errorf("expected %d blocks, but got %d", 2, coldCnt)
|
||||
}
|
||||
|
||||
if hotCnt != 5 {
|
||||
t.Errorf("expected %d blocks, but got %d", 5, hotCnt)
|
||||
if hotCnt != 10 {
|
||||
t.Errorf("expected %d blocks, but got %d", 10, hotCnt)
|
||||
}
|
||||
|
||||
// trigger a compaction
|
||||
for i := 5; i < 10; i++ {
|
||||
curTs = mkBlock(curTs, i)
|
||||
stateRoot := blocks.NewBlock([]byte{byte(i), 3, 3, 7})
|
||||
curTs = mkBlock(curTs, i, stateRoot)
|
||||
waitForCompaction()
|
||||
}
|
||||
|
||||
coldCnt = countBlocks(cold)
|
||||
hotCnt = countBlocks(hot)
|
||||
|
||||
if !cfg.EnableFullCompaction {
|
||||
if coldCnt != 5 {
|
||||
t.Errorf("expected %d cold blocks, but got %d", 5, coldCnt)
|
||||
}
|
||||
|
||||
if hotCnt != 5 {
|
||||
t.Errorf("expected %d hot blocks, but got %d", 5, hotCnt)
|
||||
}
|
||||
if coldCnt != 5 {
|
||||
t.Errorf("expected %d cold blocks, but got %d", 5, coldCnt)
|
||||
}
|
||||
|
||||
if cfg.EnableFullCompaction && !cfg.EnableGC {
|
||||
if coldCnt != 3 {
|
||||
t.Errorf("expected %d cold blocks, but got %d", 3, coldCnt)
|
||||
}
|
||||
|
||||
if hotCnt != 7 {
|
||||
t.Errorf("expected %d hot blocks, but got %d", 7, hotCnt)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.EnableFullCompaction && cfg.EnableGC {
|
||||
if coldCnt != 2 {
|
||||
t.Errorf("expected %d cold blocks, but got %d", 2, coldCnt)
|
||||
}
|
||||
|
||||
if hotCnt != 7 {
|
||||
t.Errorf("expected %d hot blocks, but got %d", 7, hotCnt)
|
||||
}
|
||||
if hotCnt != 17 {
|
||||
t.Errorf("expected %d hot blocks, but got %d", 17, hotCnt)
|
||||
}
|
||||
|
||||
// Make sure we can revert without panicking.
|
||||
chain.revert(2)
|
||||
}
|
||||
|
||||
func TestSplitStoreSimpleCompaction(t *testing.T) {
|
||||
testSplitStore(t, &Config{TrackingStoreType: "mem"})
|
||||
}
|
||||
|
||||
func TestSplitStoreFullCompactionWithoutGC(t *testing.T) {
|
||||
testSplitStore(t, &Config{
|
||||
TrackingStoreType: "mem",
|
||||
EnableFullCompaction: true,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSplitStoreFullCompactionWithGC(t *testing.T) {
|
||||
testSplitStore(t, &Config{
|
||||
TrackingStoreType: "mem",
|
||||
EnableFullCompaction: true,
|
||||
EnableGC: true,
|
||||
})
|
||||
func TestSplitStoreCompaction(t *testing.T) {
|
||||
testSplitStore(t, &Config{MarkSetType: "map"})
|
||||
}
|
||||
|
||||
type mockChain struct {
|
||||
t testing.TB
|
||||
|
||||
sync.Mutex
|
||||
genesis *types.BlockHeader
|
||||
tipsets []*types.TipSet
|
||||
listener func(revert []*types.TipSet, apply []*types.TipSet) error
|
||||
}
|
||||
@@ -204,6 +174,9 @@ type mockChain struct {
|
||||
func (c *mockChain) push(ts *types.TipSet) {
|
||||
c.Lock()
|
||||
c.tipsets = append(c.tipsets, ts)
|
||||
if c.genesis == nil {
|
||||
c.genesis = ts.Blocks()[0]
|
||||
}
|
||||
c.Unlock()
|
||||
|
||||
if c.listener != nil {
|
||||
@@ -242,7 +215,7 @@ func (c *mockChain) GetTipsetByHeight(_ context.Context, epoch abi.ChainEpoch, _
|
||||
return nil, fmt.Errorf("bad epoch %d", epoch)
|
||||
}
|
||||
|
||||
return c.tipsets[iEpoch-1], nil
|
||||
return c.tipsets[iEpoch], nil
|
||||
}
|
||||
|
||||
func (c *mockChain) GetHeaviestTipSet() *types.TipSet {
|
||||
@@ -256,24 +229,105 @@ func (c *mockChain) SubscribeHeadChanges(change func(revert []*types.TipSet, app
|
||||
c.listener = change
|
||||
}
|
||||
|
||||
func (c *mockChain) WalkSnapshot(_ context.Context, ts *types.TipSet, epochs abi.ChainEpoch, _ bool, _ bool, f func(cid.Cid) error) error {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
type mockStore struct {
|
||||
mx sync.Mutex
|
||||
set map[cid.Cid]blocks.Block
|
||||
}
|
||||
|
||||
start := int(ts.Height()) - 1
|
||||
end := start - int(epochs)
|
||||
if end < 0 {
|
||||
end = -1
|
||||
func newMockStore() *mockStore {
|
||||
return &mockStore{set: make(map[cid.Cid]blocks.Block)}
|
||||
}
|
||||
|
||||
func (b *mockStore) Has(cid cid.Cid) (bool, error) {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
_, ok := b.set[cid]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (b *mockStore) HashOnRead(hor bool) {}
|
||||
|
||||
func (b *mockStore) Get(cid cid.Cid) (blocks.Block, error) {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
blk, ok := b.set[cid]
|
||||
if !ok {
|
||||
return nil, blockstore.ErrNotFound
|
||||
}
|
||||
for i := start; i > end; i-- {
|
||||
ts := c.tipsets[i]
|
||||
for _, cid := range ts.Cids() {
|
||||
err := f(cid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
func (b *mockStore) GetSize(cid cid.Cid) (int, error) {
|
||||
blk, err := b.Get(cid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return len(blk.RawData()), nil
|
||||
}
|
||||
|
||||
func (b *mockStore) View(cid cid.Cid, f func([]byte) error) error {
|
||||
blk, err := b.Get(cid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f(blk.RawData())
|
||||
}
|
||||
|
||||
func (b *mockStore) Put(blk blocks.Block) error {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
b.set[blk.Cid()] = blk
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *mockStore) PutMany(blks []blocks.Block) error {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
for _, blk := range blks {
|
||||
b.set[blk.Cid()] = blk
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *mockStore) DeleteBlock(cid cid.Cid) error {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
delete(b.set, cid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *mockStore) DeleteMany(cids []cid.Cid) error {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
for _, c := range cids {
|
||||
delete(b.set, c)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *mockStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (b *mockStore) ForEachKey(f func(cid.Cid) error) error {
|
||||
b.mx.Lock()
|
||||
defer b.mx.Unlock()
|
||||
|
||||
for c := range b.set {
|
||||
err := f(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *mockStore) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
)
|
||||
|
||||
func epochToBytes(epoch abi.ChainEpoch) []byte {
|
||||
return uint64ToBytes(uint64(epoch))
|
||||
}
|
||||
|
||||
func bytesToEpoch(buf []byte) abi.ChainEpoch {
|
||||
return abi.ChainEpoch(bytesToUint64(buf))
|
||||
}
|
||||
|
||||
func int64ToBytes(i int64) []byte {
|
||||
return uint64ToBytes(uint64(i))
|
||||
}
|
||||
|
||||
func bytesToInt64(buf []byte) int64 {
|
||||
return int64(bytesToUint64(buf))
|
||||
}
|
||||
|
||||
func uint64ToBytes(i uint64) []byte {
|
||||
buf := make([]byte, 16)
|
||||
n := binary.PutUvarint(buf, i)
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
func bytesToUint64(buf []byte) uint64 {
|
||||
i, _ := binary.Uvarint(buf)
|
||||
return i
|
||||
}
|
||||
|
||||
func isUnitaryObject(c cid.Cid) bool {
|
||||
pre := c.Prefix()
|
||||
switch pre.Codec {
|
||||
case cid.FilCommitmentSealed, cid.FilCommitmentUnsealed:
|
||||
return true
|
||||
default:
|
||||
return pre.MhType == mh.IDENTITY
|
||||
}
|
||||
}
|
||||
|
||||
func isIdentiyCid(c cid.Cid) bool {
|
||||
return c.Prefix().MhType == mh.IDENTITY
|
||||
}
|
||||
|
||||
func decodeIdentityCid(c cid.Cid) ([]byte, error) {
|
||||
dmh, err := mh.Decode(c.Hash())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error decoding identity cid %s: %w", c, err)
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if dmh.Code != mh.IDENTITY {
|
||||
return nil, xerrors.Errorf("error decoding identity cid %s: hash type is not identity", c)
|
||||
}
|
||||
|
||||
return dmh.Digest, nil
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// warmup acuiqres the compaction lock and spawns a goroutine to warm up the hotstore;
|
||||
// this is necessary when we sync from a snapshot or when we enable the splitstore
|
||||
// on top of an existing blockstore (which becomes the coldstore).
|
||||
func (s *SplitStore) warmup(curTs *types.TipSet) error {
|
||||
if !atomic.CompareAndSwapInt32(&s.compacting, 0, 1) {
|
||||
return xerrors.Errorf("error locking compaction")
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer atomic.StoreInt32(&s.compacting, 0)
|
||||
|
||||
log.Info("warming up hotstore")
|
||||
start := time.Now()
|
||||
|
||||
err := s.doWarmup(curTs)
|
||||
if err != nil {
|
||||
log.Errorf("error warming up hotstore: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infow("warm up done", "took", time.Since(start))
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// the actual warmup procedure; it walks the chain loading all state roots at the boundary
|
||||
// and headers all the way up to genesis.
|
||||
// objects are written in batches so as to minimize overhead.
|
||||
func (s *SplitStore) doWarmup(curTs *types.TipSet) error {
|
||||
epoch := curTs.Height()
|
||||
batchHot := make([]blocks.Block, 0, batchSize)
|
||||
count := int64(0)
|
||||
xcount := int64(0)
|
||||
missing := int64(0)
|
||||
err := s.walkChain(curTs, epoch, false,
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
count++
|
||||
|
||||
has, err := s.hot.Has(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if has {
|
||||
return nil
|
||||
}
|
||||
|
||||
blk, err := s.cold.Get(c)
|
||||
if err != nil {
|
||||
if err == bstore.ErrNotFound {
|
||||
missing++
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
xcount++
|
||||
|
||||
batchHot = append(batchHot, blk)
|
||||
if len(batchHot) == batchSize {
|
||||
err = s.hot.PutMany(batchHot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
batchHot = batchHot[:0]
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(batchHot) > 0 {
|
||||
err = s.hot.PutMany(batchHot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("warmup stats", "visited", count, "warm", xcount, "missing", missing)
|
||||
|
||||
s.markSetSize = count + count>>2 // overestimate a bit
|
||||
err = s.ds.Put(markSetSizeKey, int64ToBytes(s.markSetSize))
|
||||
if err != nil {
|
||||
log.Warnf("error saving mark set size: %s", err)
|
||||
}
|
||||
|
||||
// save the warmup epoch
|
||||
err = s.ds.Put(warmupEpochKey, epochToBytes(epoch))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error saving warm up epoch: %w", err)
|
||||
}
|
||||
s.mx.Lock()
|
||||
s.warmupEpoch = epoch
|
||||
s.mx.Unlock()
|
||||
|
||||
// also save the compactionIndex, as this is used as an indicator of warmup for upgraded nodes
|
||||
err = s.ds.Put(compactionIndexKey, int64ToBytes(s.compactionIndex))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error saving compaction index: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// TrackingStore is a persistent store that tracks blocks that are added
|
||||
// to the hotstore, tracking the epoch at which they are written.
|
||||
type TrackingStore interface {
|
||||
Put(cid.Cid, abi.ChainEpoch) error
|
||||
PutBatch([]cid.Cid, abi.ChainEpoch) error
|
||||
Get(cid.Cid) (abi.ChainEpoch, error)
|
||||
Delete(cid.Cid) error
|
||||
DeleteBatch([]cid.Cid) error
|
||||
ForEach(func(cid.Cid, abi.ChainEpoch) error) error
|
||||
Sync() error
|
||||
Close() error
|
||||
}
|
||||
|
||||
// OpenTrackingStore opens a tracking store of the specified type in the
|
||||
// specified path.
|
||||
func OpenTrackingStore(path string, ttype string) (TrackingStore, error) {
|
||||
switch ttype {
|
||||
case "", "bolt":
|
||||
return OpenBoltTrackingStore(filepath.Join(path, "tracker.bolt"))
|
||||
case "mem":
|
||||
return NewMemTrackingStore(), nil
|
||||
default:
|
||||
return nil, xerrors.Errorf("unknown tracking store type %s", ttype)
|
||||
}
|
||||
}
|
||||
|
||||
// NewMemTrackingStore creates an in-memory tracking store.
|
||||
// This is only useful for test or situations where you don't want to open the
|
||||
// real tracking store (eg concurrent read only access on a node's datastore)
|
||||
func NewMemTrackingStore() *MemTrackingStore {
|
||||
return &MemTrackingStore{tab: make(map[cid.Cid]abi.ChainEpoch)}
|
||||
}
|
||||
|
||||
// MemTrackingStore is a simple in-memory tracking store
|
||||
type MemTrackingStore struct {
|
||||
sync.Mutex
|
||||
tab map[cid.Cid]abi.ChainEpoch
|
||||
}
|
||||
|
||||
var _ TrackingStore = (*MemTrackingStore)(nil)
|
||||
|
||||
func (s *MemTrackingStore) Put(cid cid.Cid, epoch abi.ChainEpoch) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.tab[cid] = epoch
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) PutBatch(cids []cid.Cid, epoch abi.ChainEpoch) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for _, cid := range cids {
|
||||
s.tab[cid] = epoch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) Get(cid cid.Cid) (abi.ChainEpoch, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
epoch, ok := s.tab[cid]
|
||||
if ok {
|
||||
return epoch, nil
|
||||
}
|
||||
return 0, xerrors.Errorf("missing tracking epoch for %s", cid)
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) Delete(cid cid.Cid) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
delete(s.tab, cid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) DeleteBatch(cids []cid.Cid) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for _, cid := range cids {
|
||||
delete(s.tab, cid)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) ForEach(f func(cid.Cid, abi.ChainEpoch) error) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for cid, epoch := range s.tab {
|
||||
err := f(cid, epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MemTrackingStore) Sync() error { return nil }
|
||||
func (s *MemTrackingStore) Close() error { return nil }
|
||||
@@ -1,120 +0,0 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
)
|
||||
|
||||
type BoltTrackingStore struct {
|
||||
db *bolt.DB
|
||||
bucketId []byte
|
||||
}
|
||||
|
||||
var _ TrackingStore = (*BoltTrackingStore)(nil)
|
||||
|
||||
func OpenBoltTrackingStore(path string) (*BoltTrackingStore, error) {
|
||||
opts := &bolt.Options{
|
||||
Timeout: 1 * time.Second,
|
||||
NoSync: true,
|
||||
}
|
||||
db, err := bolt.Open(path, 0644, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bucketId := []byte("tracker")
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(bucketId)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error creating bolt db bucket %s: %w", string(bucketId), err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
_ = db.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BoltTrackingStore{db: db, bucketId: bucketId}, nil
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) Put(cid cid.Cid, epoch abi.ChainEpoch) error {
|
||||
val := epochToBytes(epoch)
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
return b.Put(cid.Hash(), val)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) PutBatch(cids []cid.Cid, epoch abi.ChainEpoch) error {
|
||||
val := epochToBytes(epoch)
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
for _, cid := range cids {
|
||||
err := b.Put(cid.Hash(), val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) Get(cid cid.Cid) (epoch abi.ChainEpoch, err error) {
|
||||
err = s.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
val := b.Get(cid.Hash())
|
||||
if val == nil {
|
||||
return xerrors.Errorf("missing tracking epoch for %s", cid)
|
||||
}
|
||||
epoch = bytesToEpoch(val)
|
||||
return nil
|
||||
})
|
||||
return epoch, err
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) Delete(cid cid.Cid) error {
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
return b.Delete(cid.Hash())
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) DeleteBatch(cids []cid.Cid) error {
|
||||
return s.db.Batch(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
for _, cid := range cids {
|
||||
err := b.Delete(cid.Hash())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error deleting %s", cid)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) ForEach(f func(cid.Cid, abi.ChainEpoch) error) error {
|
||||
return s.db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(s.bucketId)
|
||||
return b.ForEach(func(k, v []byte) error {
|
||||
cid := cid.NewCidV1(cid.Raw, k)
|
||||
epoch := bytesToEpoch(v)
|
||||
return f(cid, epoch)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) Sync() error {
|
||||
return s.db.Sync()
|
||||
}
|
||||
|
||||
func (s *BoltTrackingStore) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
)
|
||||
|
||||
func TestBoltTrackingStore(t *testing.T) {
|
||||
testTrackingStore(t, "bolt")
|
||||
}
|
||||
|
||||
func testTrackingStore(t *testing.T, tsType string) {
|
||||
t.Helper()
|
||||
|
||||
makeCid := func(key string) cid.Cid {
|
||||
h, err := multihash.Sum([]byte(key), multihash.SHA2_256, -1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return cid.NewCidV1(cid.Raw, h)
|
||||
}
|
||||
|
||||
mustHave := func(s TrackingStore, cid cid.Cid, epoch abi.ChainEpoch) {
|
||||
val, err := s.Get(cid)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if val != epoch {
|
||||
t.Fatal("epoch mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
mustNotHave := func(s TrackingStore, cid cid.Cid) {
|
||||
_, err := s.Get(cid)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
path, err := ioutil.TempDir("", "snoop-test.*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err := OpenTrackingStore(path, tsType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
k1 := makeCid("a")
|
||||
k2 := makeCid("b")
|
||||
k3 := makeCid("c")
|
||||
k4 := makeCid("d")
|
||||
|
||||
s.Put(k1, 1) //nolint
|
||||
s.Put(k2, 2) //nolint
|
||||
s.Put(k3, 3) //nolint
|
||||
s.Put(k4, 4) //nolint
|
||||
|
||||
mustHave(s, k1, 1)
|
||||
mustHave(s, k2, 2)
|
||||
mustHave(s, k3, 3)
|
||||
mustHave(s, k4, 4)
|
||||
|
||||
s.Delete(k1) // nolint
|
||||
s.Delete(k2) // nolint
|
||||
|
||||
mustNotHave(s, k1)
|
||||
mustNotHave(s, k2)
|
||||
mustHave(s, k3, 3)
|
||||
mustHave(s, k4, 4)
|
||||
|
||||
s.PutBatch([]cid.Cid{k1}, 1) //nolint
|
||||
s.PutBatch([]cid.Cid{k2}, 2) //nolint
|
||||
|
||||
mustHave(s, k1, 1)
|
||||
mustHave(s, k2, 2)
|
||||
mustHave(s, k3, 3)
|
||||
mustHave(s, k4, 4)
|
||||
|
||||
allKeys := map[string]struct{}{
|
||||
k1.String(): {},
|
||||
k2.String(): {},
|
||||
k3.String(): {},
|
||||
k4.String(): {},
|
||||
}
|
||||
|
||||
err = s.ForEach(func(k cid.Cid, _ abi.ChainEpoch) error {
|
||||
_, ok := allKeys[k.String()]
|
||||
if !ok {
|
||||
t.Fatal("unexpected key")
|
||||
}
|
||||
|
||||
delete(allKeys, k.String())
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(allKeys) != 0 {
|
||||
t.Fatal("not all keys were returned")
|
||||
}
|
||||
|
||||
// no close and reopen and ensure the keys still exist
|
||||
err = s.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s, err = OpenTrackingStore(path, tsType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mustHave(s, k1, 1)
|
||||
mustHave(s, k2, 2)
|
||||
mustHave(s, k3, 3)
|
||||
mustHave(s, k4, 4)
|
||||
|
||||
s.Close() //nolint:errcheck
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
/dns4/bootstrap-0.interop.fildev.network/tcp/1347/p2p/12D3KooWN86wA54r3v9M8bBYbc1vK9W1ehHDxVGPRaoeUYuXF8R7
|
||||
/dns4/bootstrap-1.interop.fildev.network/tcp/1347/p2p/12D3KooWNZ41kev8mtBZgWe43qam1VX9pJyf87jnaisQP2urZZ2M
|
||||
/dns4/bootstrap-0.interop.fildev.network/tcp/1347/p2p/12D3KooWLGPq9JL1xwL6gHok7HSNxtK1Q5kyfg4Hk69ifRPghn4i
|
||||
/dns4/bootstrap-1.interop.fildev.network/tcp/1347/p2p/12D3KooWFYS1f31zafv8mqqYu8U3hEqYvaZ6avWzYU3BmZdpyH3h
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -34,7 +34,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "1.11.0"
|
||||
const BuildVersion = "1.11.1-dev"
|
||||
|
||||
func UserVersion() string {
|
||||
if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" {
|
||||
|
||||
@@ -196,6 +196,33 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) ab
|
||||
}
|
||||
}
|
||||
|
||||
// SetProviderCollateralSupplyTarget sets the percentage of normalized circulating
|
||||
// supply that must be covered by provider collateral in a deal. This should
|
||||
// only be used for testing.
|
||||
func SetProviderCollateralSupplyTarget(num, denom big.Int) {
|
||||
|
||||
market2.ProviderCollateralSupplyTarget = builtin2.BigFrac{
|
||||
Numerator: num,
|
||||
Denominator: denom,
|
||||
}
|
||||
|
||||
market3.ProviderCollateralSupplyTarget = builtin3.BigFrac{
|
||||
Numerator: num,
|
||||
Denominator: denom,
|
||||
}
|
||||
|
||||
market4.ProviderCollateralSupplyTarget = builtin4.BigFrac{
|
||||
Numerator: num,
|
||||
Denominator: denom,
|
||||
}
|
||||
|
||||
market5.ProviderCollateralSupplyTarget = builtin5.BigFrac{
|
||||
Numerator: num,
|
||||
Denominator: denom,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func DealProviderCollateralBounds(
|
||||
size abi.PaddedPieceSize, verified bool,
|
||||
rawBytePower, qaPower, baselinePower abi.StoragePower,
|
||||
|
||||
@@ -132,6 +132,20 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) ab
|
||||
}
|
||||
}
|
||||
|
||||
// SetProviderCollateralSupplyTarget sets the percentage of normalized circulating
|
||||
// supply that must be covered by provider collateral in a deal. This should
|
||||
// only be used for testing.
|
||||
func SetProviderCollateralSupplyTarget(num, denom big.Int) {
|
||||
{{range .versions}}
|
||||
{{if (ge . 2)}}
|
||||
market{{.}}.ProviderCollateralSupplyTarget = builtin{{.}}.BigFrac{
|
||||
Numerator: num,
|
||||
Denominator: denom,
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
}
|
||||
|
||||
func DealProviderCollateralBounds(
|
||||
size abi.PaddedPieceSize, verified bool,
|
||||
rawBytePower, qaPower, baselinePower abi.StoragePower,
|
||||
|
||||
+31
-26
@@ -547,7 +547,7 @@ func (st *StateTree) Version() types.StateTreeVersion {
|
||||
return st.version
|
||||
}
|
||||
|
||||
func Diff(oldTree, newTree *StateTree) (map[string]types.Actor, error) {
|
||||
func Diff(ctx context.Context, oldTree, newTree *StateTree) (map[string]types.Actor, error) {
|
||||
out := map[string]types.Actor{}
|
||||
|
||||
var (
|
||||
@@ -555,33 +555,38 @@ func Diff(oldTree, newTree *StateTree) (map[string]types.Actor, error) {
|
||||
buf = bytes.NewReader(nil)
|
||||
)
|
||||
if err := newTree.root.ForEach(&ncval, func(k string) error {
|
||||
var act types.Actor
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
var act types.Actor
|
||||
|
||||
addr, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("address in state tree was not valid: %w", err)
|
||||
addr, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("address in state tree was not valid: %w", err)
|
||||
}
|
||||
|
||||
found, err := oldTree.root.Get(abi.AddrKey(addr), &ocval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found && bytes.Equal(ocval.Raw, ncval.Raw) {
|
||||
return nil // not changed
|
||||
}
|
||||
|
||||
buf.Reset(ncval.Raw)
|
||||
err = act.UnmarshalCBOR(buf)
|
||||
buf.Reset(nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out[addr.String()] = act
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
found, err := oldTree.root.Get(abi.AddrKey(addr), &ocval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found && bytes.Equal(ocval.Raw, ncval.Raw) {
|
||||
return nil // not changed
|
||||
}
|
||||
|
||||
buf.Reset(ncval.Raw)
|
||||
err = act.UnmarshalCBOR(buf)
|
||||
buf.Reset(nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out[addr.String()] = act
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -297,22 +297,26 @@ func TestForkRefuseCall(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pts, err := cg.ChainStore().LoadTipSet(ts.TipSet.TipSet().Parents())
|
||||
require.NoError(t, err)
|
||||
parentHeight := pts.Height()
|
||||
currentHeight := ts.TipSet.TipSet().Height()
|
||||
|
||||
// CallWithGas calls _at_ the current tipset.
|
||||
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight, testForkHeight + 1:
|
||||
if parentHeight <= testForkHeight && currentHeight >= testForkHeight {
|
||||
// If I had a fork, or I _will_ have a fork, it should fail.
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
// Call just runs on the parent state for a tipset, so we only
|
||||
// expect an error at the fork height.
|
||||
|
||||
// Call always applies the message to the "next block" after the tipset's parent state.
|
||||
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight + 1:
|
||||
if parentHeight == testForkHeight {
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
|
||||
+4
-3
@@ -279,7 +279,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Base(),
|
||||
node.Repo(sourceRepo),
|
||||
node.MockHost(tu.mn),
|
||||
node.Test(),
|
||||
@@ -310,10 +310,11 @@ func (tu *syncTestUtil) addClientNode() int {
|
||||
|
||||
var out api.FullNode
|
||||
|
||||
r := repo.NewMemory(nil)
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
node.Base(),
|
||||
node.Repo(r),
|
||||
node.MockHost(tu.mn),
|
||||
node.Test(),
|
||||
|
||||
|
||||
+3
-1
@@ -1030,7 +1030,9 @@ var ChainExportCmd = &cli.Command{
|
||||
ArgsUsage: "[outputPath]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
Name: "tipset",
|
||||
Usage: "specify tipset to start the export from",
|
||||
Value: "@head",
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "recent-stateroots",
|
||||
|
||||
+56
-57
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/fatih/color"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/lotus/node/repo/importmgr"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cidutil/cidenc"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -34,7 +35,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
@@ -174,18 +174,18 @@ var clientDropCmd = &cli.Command{
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
var ids []multistore.StoreID
|
||||
var ids []uint64
|
||||
for i, s := range cctx.Args().Slice() {
|
||||
id, err := strconv.ParseInt(s, 10, 0)
|
||||
id, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing %d-th import ID: %w", i, err)
|
||||
}
|
||||
|
||||
ids = append(ids, multistore.StoreID(id))
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
if err := api.ClientRemoveImport(ctx, id); err != nil {
|
||||
if err := api.ClientRemoveImport(ctx, importmgr.ImportID(id)); err != nil {
|
||||
return xerrors.Errorf("removing import %d: %w", id, err)
|
||||
}
|
||||
}
|
||||
@@ -1104,8 +1104,8 @@ var clientRetrieveCmd = &cli.Command{
|
||||
for _, i := range imports {
|
||||
if i.Root != nil && i.Root.Equals(file) {
|
||||
order = &lapi.RetrievalOrder{
|
||||
Root: file,
|
||||
LocalStore: &i.Key,
|
||||
Root: file,
|
||||
LocalCARV2FilePath: i.CARv2FilePath,
|
||||
|
||||
Total: big.Zero(),
|
||||
UnsealPrice: big.Zero(),
|
||||
@@ -1231,9 +1231,9 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
Usage: "print verbose deal details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
@@ -1250,6 +1250,10 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1258,7 +1262,6 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
verbose := cctx.Bool("verbose")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
completed := cctx.Bool("completed")
|
||||
@@ -1278,7 +1281,7 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
tm.Clear()
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
err = outputRetrievalDeals(ctx, tm.Screen, localDeals, verbose, color, showFailed, completed)
|
||||
err = outputRetrievalDeals(ctx, tm.Screen, localDeals, verbose, showFailed, completed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1304,7 +1307,7 @@ var clientListRetrievalsCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
return outputRetrievalDeals(ctx, cctx.App.Writer, localDeals, verbose, color, showFailed, completed)
|
||||
return outputRetrievalDeals(ctx, cctx.App.Writer, localDeals, verbose, showFailed, completed)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1312,7 +1315,7 @@ func isTerminalError(status retrievalmarket.DealStatus) bool {
|
||||
// should patch this in go-fil-markets but to solve the problem immediate and not have buggy output
|
||||
return retrievalmarket.IsTerminalError(status) || status == retrievalmarket.DealStatusErrored || status == retrievalmarket.DealStatusCancelled
|
||||
}
|
||||
func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.RetrievalInfo, verbose bool, color bool, showFailed bool, completed bool) error {
|
||||
func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.RetrievalInfo, verbose bool, showFailed bool, completed bool) error {
|
||||
var deals []api.RetrievalInfo
|
||||
for _, deal := range localDeals {
|
||||
if !showFailed && isTerminalError(deal.Status) {
|
||||
@@ -1348,13 +1351,13 @@ func outputRetrievalDeals(ctx context.Context, out io.Writer, localDeals []lapi.
|
||||
w := tablewriter.New(tableColumns...)
|
||||
|
||||
for _, d := range deals {
|
||||
w.Write(toRetrievalOutput(d, color, verbose))
|
||||
w.Write(toRetrievalOutput(d, verbose))
|
||||
}
|
||||
|
||||
return w.Flush(out)
|
||||
}
|
||||
|
||||
func toRetrievalOutput(d api.RetrievalInfo, color bool, verbose bool) map[string]interface{} {
|
||||
func toRetrievalOutput(d api.RetrievalInfo, verbose bool) map[string]interface{} {
|
||||
|
||||
payloadCID := d.PayloadCID.String()
|
||||
provider := d.Provider.String()
|
||||
@@ -1367,7 +1370,7 @@ func toRetrievalOutput(d api.RetrievalInfo, color bool, verbose bool) map[string
|
||||
"PayloadCID": payloadCID,
|
||||
"DealId": d.ID,
|
||||
"Provider": provider,
|
||||
"Status": retrievalStatusString(color, d.Status),
|
||||
"Status": retrievalStatusString(d.Status),
|
||||
"PricePerByte": types.FIL(d.PricePerByte),
|
||||
"Received": units.BytesSize(float64(d.BytesReceived)),
|
||||
"TotalPaid": types.FIL(d.TotalPaid),
|
||||
@@ -1397,19 +1400,17 @@ func toRetrievalOutput(d api.RetrievalInfo, color bool, verbose bool) map[string
|
||||
return retrievalOutput
|
||||
}
|
||||
|
||||
func retrievalStatusString(c bool, status retrievalmarket.DealStatus) string {
|
||||
func retrievalStatusString(status retrievalmarket.DealStatus) string {
|
||||
s := retrievalmarket.DealStatuses[status]
|
||||
if !c {
|
||||
|
||||
switch {
|
||||
case isTerminalError(status):
|
||||
return color.RedString(s)
|
||||
case retrievalmarket.IsTerminalSuccess(status):
|
||||
return color.GreenString(s)
|
||||
default:
|
||||
return s
|
||||
}
|
||||
|
||||
if isTerminalError(status) {
|
||||
return color.RedString(s)
|
||||
}
|
||||
if retrievalmarket.IsTerminalSuccess(status) {
|
||||
return color.GreenString(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var clientInspectDealCmd = &cli.Command{
|
||||
@@ -1804,9 +1805,9 @@ var clientListDeals = &cli.Command{
|
||||
Usage: "print verbose deal details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-failed",
|
||||
@@ -1818,6 +1819,10 @@ var clientListDeals = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1826,7 +1831,6 @@ var clientListDeals = &cli.Command{
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
verbose := cctx.Bool("verbose")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
|
||||
@@ -1845,7 +1849,7 @@ var clientListDeals = &cli.Command{
|
||||
tm.Clear()
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, color, showFailed)
|
||||
err = outputStorageDeals(ctx, tm.Screen, api, localDeals, verbose, showFailed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1871,7 +1875,7 @@ var clientListDeals = &cli.Command{
|
||||
}
|
||||
}
|
||||
|
||||
return outputStorageDeals(ctx, cctx.App.Writer, api, localDeals, verbose, color, showFailed)
|
||||
return outputStorageDeals(ctx, cctx.App.Writer, api, localDeals, verbose, showFailed)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1894,7 +1898,7 @@ func dealFromDealInfo(ctx context.Context, full v0api.FullNode, head *types.TipS
|
||||
}
|
||||
}
|
||||
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full v0api.FullNode, localDeals []lapi.DealInfo, verbose bool, color bool, showFailed bool) error {
|
||||
func outputStorageDeals(ctx context.Context, out io.Writer, full v0api.FullNode, localDeals []lapi.DealInfo, verbose bool, showFailed bool) error {
|
||||
sort.Slice(localDeals, func(i, j int) bool {
|
||||
return localDeals[i].CreationTime.Before(localDeals[j].CreationTime)
|
||||
})
|
||||
@@ -1946,7 +1950,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full v0api.FullNode,
|
||||
d.LocalDeal.ProposalCid,
|
||||
d.LocalDeal.DealID,
|
||||
d.LocalDeal.Provider,
|
||||
dealStateString(color, d.LocalDeal.State),
|
||||
dealStateString(d.LocalDeal.State),
|
||||
onChain,
|
||||
slashed,
|
||||
d.LocalDeal.PieceCID,
|
||||
@@ -1995,7 +1999,7 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full v0api.FullNode,
|
||||
"DealCid": propcid,
|
||||
"DealId": d.LocalDeal.DealID,
|
||||
"Provider": d.LocalDeal.Provider,
|
||||
"State": dealStateString(color, d.LocalDeal.State),
|
||||
"State": dealStateString(d.LocalDeal.State),
|
||||
"On Chain?": onChain,
|
||||
"Slashed?": slashed,
|
||||
"PieceCID": piece,
|
||||
@@ -2010,12 +2014,8 @@ func outputStorageDeals(ctx context.Context, out io.Writer, full v0api.FullNode,
|
||||
return w.Flush(out)
|
||||
}
|
||||
|
||||
func dealStateString(c bool, state storagemarket.StorageDealStatus) string {
|
||||
func dealStateString(state storagemarket.StorageDealStatus) string {
|
||||
s := storagemarket.DealStates[state]
|
||||
if !c {
|
||||
return s
|
||||
}
|
||||
|
||||
switch state {
|
||||
case storagemarket.StorageDealError, storagemarket.StorageDealExpired:
|
||||
return color.RedString(s)
|
||||
@@ -2334,9 +2334,9 @@ var clientListTransfers = &cli.Command{
|
||||
Usage: "print verbose transfer details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "completed",
|
||||
@@ -2352,6 +2352,10 @@ var clientListTransfers = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2366,7 +2370,6 @@ var clientListTransfers = &cli.Command{
|
||||
|
||||
verbose := cctx.Bool("verbose")
|
||||
completed := cctx.Bool("completed")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
if watch {
|
||||
@@ -2380,7 +2383,7 @@ var clientListTransfers = &cli.Command{
|
||||
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
OutputDataTransferChannels(tm.Screen, channels, verbose, completed, color, showFailed)
|
||||
OutputDataTransferChannels(tm.Screen, channels, verbose, completed, showFailed)
|
||||
|
||||
tm.Flush()
|
||||
|
||||
@@ -2405,13 +2408,13 @@ var clientListTransfers = &cli.Command{
|
||||
}
|
||||
}
|
||||
}
|
||||
OutputDataTransferChannels(os.Stdout, channels, verbose, completed, color, showFailed)
|
||||
OutputDataTransferChannels(os.Stdout, channels, verbose, completed, showFailed)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// OutputDataTransferChannels generates table output for a list of channels
|
||||
func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChannel, verbose, completed, color, showFailed bool) {
|
||||
func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChannel, verbose, completed, showFailed bool) {
|
||||
sort.Slice(channels, func(i, j int) bool {
|
||||
return channels[i].TransferID < channels[j].TransferID
|
||||
})
|
||||
@@ -2441,7 +2444,7 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann
|
||||
tablewriter.Col("Voucher"),
|
||||
tablewriter.NewLineCol("Message"))
|
||||
for _, channel := range sendingChannels {
|
||||
w.Write(toChannelOutput(color, "Sending To", channel, verbose))
|
||||
w.Write(toChannelOutput("Sending To", channel, verbose))
|
||||
}
|
||||
w.Flush(out) //nolint:errcheck
|
||||
|
||||
@@ -2455,17 +2458,13 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann
|
||||
tablewriter.Col("Voucher"),
|
||||
tablewriter.NewLineCol("Message"))
|
||||
for _, channel := range receivingChannels {
|
||||
w.Write(toChannelOutput(color, "Receiving From", channel, verbose))
|
||||
w.Write(toChannelOutput("Receiving From", channel, verbose))
|
||||
}
|
||||
w.Flush(out) //nolint:errcheck
|
||||
}
|
||||
|
||||
func channelStatusString(useColor bool, status datatransfer.Status) string {
|
||||
func channelStatusString(status datatransfer.Status) string {
|
||||
s := datatransfer.Statuses[status]
|
||||
if !useColor {
|
||||
return s
|
||||
}
|
||||
|
||||
switch status {
|
||||
case datatransfer.Failed, datatransfer.Cancelled:
|
||||
return color.RedString(s)
|
||||
@@ -2476,7 +2475,7 @@ func channelStatusString(useColor bool, status datatransfer.Status) string {
|
||||
}
|
||||
}
|
||||
|
||||
func toChannelOutput(useColor bool, otherPartyColumn string, channel lapi.DataTransferChannel, verbose bool) map[string]interface{} {
|
||||
func toChannelOutput(otherPartyColumn string, channel lapi.DataTransferChannel, verbose bool) map[string]interface{} {
|
||||
rootCid := channel.BaseCID.String()
|
||||
otherParty := channel.OtherPeer.String()
|
||||
if !verbose {
|
||||
@@ -2496,7 +2495,7 @@ func toChannelOutput(useColor bool, otherPartyColumn string, channel lapi.DataTr
|
||||
|
||||
return map[string]interface{}{
|
||||
"ID": channel.TransferID,
|
||||
"Status": channelStatusString(useColor, channel.Status),
|
||||
"Status": channelStatusString(channel.Status),
|
||||
otherPartyColumn: otherParty,
|
||||
"Root Cid": rootCid,
|
||||
"Initiated?": initiated,
|
||||
|
||||
+1
-1
@@ -695,7 +695,7 @@ var StateListActorsCmd = &cli.Command{
|
||||
var StateGetActorCmd = &cli.Command{
|
||||
Name: "get-actor",
|
||||
Usage: "Print actor information",
|
||||
ArgsUsage: "[actorrAddress]",
|
||||
ArgsUsage: "[actorAddress]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
|
||||
+10
@@ -3,10 +3,13 @@ package cli
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/hako/durafmt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/mattn/go-isatty"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
@@ -15,6 +18,13 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// Set the global default, to be overridden by individual cli flags in order
|
||||
func init() {
|
||||
color.NoColor = os.Getenv("GOLOG_LOG_FMT") != "color" &&
|
||||
!isatty.IsTerminal(os.Stdout.Fd()) &&
|
||||
!isatty.IsCygwinTerminal(os.Stdout.Fd())
|
||||
}
|
||||
|
||||
func parseTipSet(ctx context.Context, api v0api.FullNode, vals []string) (*types.TipSet, error) {
|
||||
var headers []*types.BlockHeader
|
||||
for _, c := range vals {
|
||||
|
||||
@@ -572,7 +572,7 @@ var genesisCarCmd = &cli.Command{
|
||||
}
|
||||
ofile := c.String("out")
|
||||
jrnl := journal.NilJournal()
|
||||
bstor := blockstore.NewMemorySync()
|
||||
bstor := blockstore.WrapIDStore(blockstore.NewMemorySync())
|
||||
sbldr := vm.Syscalls(ffiwrapper.ProofVerifier)
|
||||
_, err := testing.MakeGenesis(ofile, c.Args().First())(bstor, sbldr, jrnl)()
|
||||
return err
|
||||
|
||||
@@ -265,12 +265,15 @@ var actorControlList = &cli.Command{
|
||||
Name: "verbose",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
var maddr address.Address
|
||||
if act := cctx.String("actor"); act != "" {
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
@@ -18,6 +24,7 @@ var electionCmd = &cli.Command{
|
||||
Subcommands: []*cli.Command{
|
||||
electionRunDummy,
|
||||
electionEstimate,
|
||||
electionBacktest,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -124,3 +131,97 @@ var electionEstimate = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var electionBacktest = &cli.Command{
|
||||
Name: "backtest",
|
||||
Usage: "Backtest elections with given miner",
|
||||
ArgsUsage: "[minerAddress]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.Uint64Flag{
|
||||
Name: "height",
|
||||
Usage: "blockchain head height",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "count",
|
||||
Usage: "number of won elections to look for",
|
||||
Value: 120,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("GetFullNodeAPI: %w", err)
|
||||
}
|
||||
|
||||
defer closer()
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
|
||||
var head *types.TipSet
|
||||
if cctx.IsSet("height") {
|
||||
head, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("height")), types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("ChainGetTipSetByHeight: %w", err)
|
||||
}
|
||||
} else {
|
||||
head, err = api.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("ChainHead: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
miner, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("miner address: %w", err)
|
||||
}
|
||||
|
||||
count := cctx.Int("count")
|
||||
if count < 1 {
|
||||
return xerrors.Errorf("count: %d", count)
|
||||
}
|
||||
|
||||
fmt.Println("height, winCount")
|
||||
roundEnd := head.Height() + abi.ChainEpoch(1)
|
||||
for i := 0; i < count; {
|
||||
for round := head.Height() + abi.ChainEpoch(1); round <= roundEnd; round++ {
|
||||
i++
|
||||
win, err := backTestWinner(ctx, miner, round, head, api)
|
||||
if err == nil && win != nil {
|
||||
fmt.Printf("%d, %d\n", round, win.WinCount)
|
||||
}
|
||||
}
|
||||
|
||||
roundEnd = head.Height()
|
||||
head, err = api.ChainGetTipSet(ctx, head.Parents())
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func backTestWinner(ctx context.Context, miner address.Address, round abi.ChainEpoch, ts *types.TipSet, api v0api.FullNode) (*types.ElectionProof, error) {
|
||||
mbi, err := api.MinerGetBaseInfo(ctx, miner, round, ts.Key())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get mining base info: %w", err)
|
||||
}
|
||||
if mbi == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if !mbi.EligibleForMining {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
brand := mbi.PrevBeaconEntry
|
||||
bvals := mbi.BeaconEntries
|
||||
if len(bvals) > 0 {
|
||||
brand = bvals[len(bvals)-1]
|
||||
}
|
||||
|
||||
winner, err := gen.IsRoundWinner(ctx, ts, round, miner, brand, mbi, api)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
|
||||
}
|
||||
|
||||
return winner, nil
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner"
|
||||
)
|
||||
|
||||
var mathCmd = &cli.Command{
|
||||
@@ -17,6 +19,7 @@ var mathCmd = &cli.Command{
|
||||
Usage: "utility commands around doing math on a list of numbers",
|
||||
Subcommands: []*cli.Command{
|
||||
mathSumCmd,
|
||||
mathAggFeesCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -101,3 +104,30 @@ var mathSumCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var mathAggFeesCmd = &cli.Command{
|
||||
Name: "agg-fees",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "size",
|
||||
Required: true,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "base-fee",
|
||||
Usage: "baseFee aFIL",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
as := cctx.Int("size")
|
||||
|
||||
bf, err := types.BigFromString(cctx.String("base-fee"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing basefee: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println(types.FIL(miner5.AggregateNetworkFee(as, bf)))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
corebig "math/big"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
filbig "github.com/filecoin-project/go-state-types/big"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -21,13 +23,16 @@ type networkTotalsOutput struct {
|
||||
}
|
||||
|
||||
type networkTotals struct {
|
||||
UniqueCids int `json:"total_unique_cids"`
|
||||
UniqueProviders int `json:"total_unique_providers"`
|
||||
UniqueClients int `json:"total_unique_clients"`
|
||||
TotalDeals int `json:"total_num_deals"`
|
||||
TotalBytes int64 `json:"total_stored_data_size"`
|
||||
FilplusTotalDeals int `json:"filplus_total_num_deals"`
|
||||
FilplusTotalBytes int64 `json:"filplus_total_stored_data_size"`
|
||||
QaNetworkPower filbig.Int `json:"total_qa_power"`
|
||||
RawNetworkPower filbig.Int `json:"total_raw_capacity"`
|
||||
CapacityCarryingData float64 `json:"capacity_fraction_carrying_data"`
|
||||
UniqueCids int `json:"total_unique_cids"`
|
||||
UniqueProviders int `json:"total_unique_providers"`
|
||||
UniqueClients int `json:"total_unique_clients"`
|
||||
TotalDeals int `json:"total_num_deals"`
|
||||
TotalBytes int64 `json:"total_stored_data_size"`
|
||||
FilplusTotalDeals int `json:"filplus_total_num_deals"`
|
||||
FilplusTotalBytes int64 `json:"filplus_total_stored_data_size"`
|
||||
|
||||
seenClient map[address.Address]bool
|
||||
seenProvider map[address.Address]bool
|
||||
@@ -66,10 +71,17 @@ var storageStatsCmd = &cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
power, err := api.StateMinerPower(ctx, address.Address{}, head.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
netTotals := networkTotals{
|
||||
seenClient: make(map[address.Address]bool),
|
||||
seenProvider: make(map[address.Address]bool),
|
||||
seenPieceCid: make(map[cid.Cid]bool),
|
||||
QaNetworkPower: power.TotalPower.QualityAdjPower,
|
||||
RawNetworkPower: power.TotalPower.RawBytePower,
|
||||
seenClient: make(map[address.Address]bool),
|
||||
seenProvider: make(map[address.Address]bool),
|
||||
seenPieceCid: make(map[cid.Cid]bool),
|
||||
}
|
||||
|
||||
deals, err := api.StateMarketDeals(ctx, head.Key())
|
||||
@@ -103,6 +115,11 @@ var storageStatsCmd = &cli.Command{
|
||||
netTotals.UniqueClients = len(netTotals.seenClient)
|
||||
netTotals.UniqueProviders = len(netTotals.seenProvider)
|
||||
|
||||
netTotals.CapacityCarryingData, _ = new(corebig.Rat).SetFrac(
|
||||
corebig.NewInt(netTotals.TotalBytes),
|
||||
netTotals.RawNetworkPower.Int,
|
||||
).Float64()
|
||||
|
||||
return json.NewEncoder(os.Stdout).Encode(
|
||||
networkTotalsOutput{
|
||||
Epoch: int64(head.Height()),
|
||||
|
||||
@@ -388,12 +388,15 @@ var actorControlList = &cli.Command{
|
||||
Name: "verbose",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -435,6 +438,7 @@ var actorControlList = &cli.Command{
|
||||
commit := map[address.Address]struct{}{}
|
||||
precommit := map[address.Address]struct{}{}
|
||||
terminate := map[address.Address]struct{}{}
|
||||
dealPublish := map[address.Address]struct{}{}
|
||||
post := map[address.Address]struct{}{}
|
||||
|
||||
for _, ca := range mi.ControlAddresses {
|
||||
@@ -471,6 +475,16 @@ var actorControlList = &cli.Command{
|
||||
terminate[ca] = struct{}{}
|
||||
}
|
||||
|
||||
for _, ca := range ac.DealPublishControl {
|
||||
ca, err := api.StateLookupID(ctx, ca, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(post, ca)
|
||||
dealPublish[ca] = struct{}{}
|
||||
}
|
||||
|
||||
printKey := func(name string, a address.Address) {
|
||||
b, err := api.WalletBalance(ctx, a)
|
||||
if err != nil {
|
||||
@@ -515,6 +529,9 @@ var actorControlList = &cli.Command{
|
||||
if _, ok := terminate[a]; ok {
|
||||
uses = append(uses, color.YellowString("terminate"))
|
||||
}
|
||||
if _, ok := dealPublish[a]; ok {
|
||||
uses = append(uses, color.MagentaString("deals"))
|
||||
}
|
||||
|
||||
tw.Write(map[string]interface{}{
|
||||
"name": name,
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestMinerAllInfo(t *testing.T) {
|
||||
|
||||
t.Run("pre-info-all", run)
|
||||
|
||||
dh := kit.NewDealHarness(t, client, miner)
|
||||
dh := kit.NewDealHarness(t, client, miner, miner)
|
||||
deal, res, inPath := dh.MakeOnlineDeal(context.Background(), kit.MakeFullDealParams{Rseed: 6})
|
||||
outPath := dh.PerformRetrieval(context.Background(), deal, res.Root, false)
|
||||
kit.AssertFilesEqual(t, inPath, outPath)
|
||||
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
corebig "math/big"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
@@ -14,6 +17,7 @@ import (
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
@@ -45,8 +49,6 @@ var infoCmd = &cli.Command{
|
||||
}
|
||||
|
||||
func infoCmdAct(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -222,29 +224,89 @@ func infoCmdAct(cctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var nactiveDeals, nVerifDeals, ndeals uint64
|
||||
var activeDealBytes, activeVerifDealBytes, dealBytes abi.PaddedPieceSize
|
||||
for _, deal := range deals {
|
||||
if deal.State == storagemarket.StorageDealError {
|
||||
continue
|
||||
}
|
||||
|
||||
ndeals++
|
||||
dealBytes += deal.Proposal.PieceSize
|
||||
|
||||
if deal.State == storagemarket.StorageDealActive {
|
||||
nactiveDeals++
|
||||
activeDealBytes += deal.Proposal.PieceSize
|
||||
|
||||
if deal.Proposal.VerifiedDeal {
|
||||
nVerifDeals++
|
||||
activeVerifDealBytes += deal.Proposal.PieceSize
|
||||
}
|
||||
type dealStat struct {
|
||||
count, verifCount int
|
||||
bytes, verifBytes uint64
|
||||
}
|
||||
dsAdd := func(ds *dealStat, deal storagemarket.MinerDeal) {
|
||||
ds.count++
|
||||
ds.bytes += uint64(deal.Proposal.PieceSize)
|
||||
if deal.Proposal.VerifiedDeal {
|
||||
ds.verifCount++
|
||||
ds.verifBytes += uint64(deal.Proposal.PieceSize)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Deals: %d, %s\n", ndeals, types.SizeStr(types.NewInt(uint64(dealBytes))))
|
||||
fmt.Printf("\tActive: %d, %s (Verified: %d, %s)\n", nactiveDeals, types.SizeStr(types.NewInt(uint64(activeDealBytes))), nVerifDeals, types.SizeStr(types.NewInt(uint64(activeVerifDealBytes))))
|
||||
showDealStates := map[storagemarket.StorageDealStatus]struct{}{
|
||||
storagemarket.StorageDealActive: {},
|
||||
storagemarket.StorageDealTransferring: {},
|
||||
storagemarket.StorageDealStaged: {},
|
||||
storagemarket.StorageDealAwaitingPreCommit: {},
|
||||
storagemarket.StorageDealSealing: {},
|
||||
storagemarket.StorageDealPublish: {},
|
||||
storagemarket.StorageDealCheckForAcceptance: {},
|
||||
storagemarket.StorageDealPublishing: {},
|
||||
}
|
||||
|
||||
var total dealStat
|
||||
perState := map[storagemarket.StorageDealStatus]*dealStat{}
|
||||
for _, deal := range deals {
|
||||
if _, ok := showDealStates[deal.State]; !ok {
|
||||
continue
|
||||
}
|
||||
if perState[deal.State] == nil {
|
||||
perState[deal.State] = new(dealStat)
|
||||
}
|
||||
|
||||
dsAdd(&total, deal)
|
||||
dsAdd(perState[deal.State], deal)
|
||||
}
|
||||
|
||||
type wstr struct {
|
||||
str string
|
||||
status storagemarket.StorageDealStatus
|
||||
}
|
||||
sorted := make([]wstr, 0, len(perState))
|
||||
for status, stat := range perState {
|
||||
st := strings.TrimPrefix(storagemarket.DealStates[status], "StorageDeal")
|
||||
sorted = append(sorted, wstr{
|
||||
str: fmt.Sprintf(" %s:\t%d\t\t%s\t(Verified: %d\t%s)\n", st, stat.count, types.SizeStr(types.NewInt(stat.bytes)), stat.verifCount, types.SizeStr(types.NewInt(stat.verifBytes))),
|
||||
status: status,
|
||||
},
|
||||
)
|
||||
}
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
if sorted[i].status == storagemarket.StorageDealActive || sorted[j].status == storagemarket.StorageDealActive {
|
||||
return sorted[i].status == storagemarket.StorageDealActive
|
||||
}
|
||||
return sorted[i].status > sorted[j].status
|
||||
})
|
||||
|
||||
fmt.Printf("Storage Deals: %d, %s\n", total.count, types.SizeStr(types.NewInt(total.bytes)))
|
||||
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
|
||||
for _, e := range sorted {
|
||||
_, _ = tw.Write([]byte(e.str))
|
||||
}
|
||||
|
||||
_ = tw.Flush()
|
||||
fmt.Println()
|
||||
|
||||
retrievals, err := nodeApi.MarketListRetrievalDeals(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting retrieval deal list: %w", err)
|
||||
}
|
||||
|
||||
var retrComplete dealStat
|
||||
for _, retrieval := range retrievals {
|
||||
if retrieval.Status == retrievalmarket.DealStatusCompleted {
|
||||
retrComplete.count++
|
||||
retrComplete.bytes += retrieval.TotalSent
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Retrieval Deals (complete): %d, %s\n", retrComplete.count, types.SizeStr(types.NewInt(retrComplete.bytes)))
|
||||
|
||||
fmt.Println()
|
||||
|
||||
spendable := big.Zero()
|
||||
|
||||
@@ -121,7 +121,8 @@ var initCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
initRestoreCmd,
|
||||
restoreCmd,
|
||||
serviceCmd,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
log.Info("Initializing lotus miner")
|
||||
@@ -317,10 +318,10 @@ func migratePreSealMeta(ctx context.Context, api v1api.FullNode, metadata string
|
||||
Size: abi.PaddedPieceSize(meta.SectorSize),
|
||||
PieceCID: commD,
|
||||
},
|
||||
DealInfo: &sealing.DealInfo{
|
||||
DealInfo: &lapi.PieceDealInfo{
|
||||
DealID: dealID,
|
||||
DealProposal: §or.Deal,
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
DealSchedule: lapi.DealSchedule{
|
||||
StartEpoch: sector.Deal.StartEpoch,
|
||||
EndEpoch: sector.Deal.EndEpoch,
|
||||
},
|
||||
@@ -470,7 +471,6 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api v1api.FullNode
|
||||
AllowCommit: true,
|
||||
AllowUnseal: true,
|
||||
}, wsts, smsts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -734,6 +734,8 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, peerid peer.ID,
|
||||
return retval.IDAddress, nil
|
||||
}
|
||||
|
||||
// checkV1ApiSupport uses v0 api version to signal support for v1 API
|
||||
// trying to query the v1 api on older lotus versions would get a 404, which can happen for any number of other reasons
|
||||
func checkV1ApiSupport(ctx context.Context, cctx *cli.Context) error {
|
||||
// check v0 api version to make sure it supports v1 api
|
||||
api0, closer, err := lcli.GetFullNodeAPI(cctx)
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
@@ -30,7 +31,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
|
||||
var initRestoreCmd = &cli.Command{
|
||||
var restoreCmd = &cli.Command{
|
||||
Name: "restore",
|
||||
Usage: "Initialize a lotus miner repo from a backup",
|
||||
Flags: []cli.Flag{
|
||||
@@ -49,129 +50,11 @@ var initRestoreCmd = &cli.Command{
|
||||
},
|
||||
ArgsUsage: "[backupFile]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
log.Info("Initializing lotus miner using a backup")
|
||||
if cctx.Args().Len() != 1 {
|
||||
return xerrors.Errorf("expected 1 argument")
|
||||
}
|
||||
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
log.Info("Initializing lotus miner using a backup")
|
||||
|
||||
log.Info("Trying to connect to full node RPC")
|
||||
|
||||
if err := checkV1ApiSupport(ctx, cctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
api, closer, err := lcli.GetFullNodeAPIV1(cctx) // TODO: consider storing full node address in config
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
log.Info("Checking full node version")
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !v.APIVersion.EqMajorMinor(lapi.FullAPIVersion1) {
|
||||
return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", lapi.FullAPIVersion1, v.APIVersion)
|
||||
}
|
||||
|
||||
if !cctx.Bool("nosync") {
|
||||
if err := lcli.SyncWait(ctx, &v0api.WrapperV1Full{FullNode: api}, false); err != nil {
|
||||
return xerrors.Errorf("sync wait: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
bf, err := homedir.Expand(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expand backup file path: %w", err)
|
||||
}
|
||||
|
||||
st, err := os.Stat(bf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("stat backup file (%s): %w", bf, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(bf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening backup file: %w", err)
|
||||
}
|
||||
defer f.Close() // nolint:errcheck
|
||||
|
||||
log.Info("Checking if repo exists")
|
||||
|
||||
repoPath := cctx.String(FlagMinerRepo)
|
||||
r, err := repo.NewFS(repoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return xerrors.Errorf("repo at '%s' is already initialized", cctx.String(FlagMinerRepo))
|
||||
}
|
||||
|
||||
log.Info("Initializing repo")
|
||||
|
||||
if err := r.Init(repo.StorageMiner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.StorageMiner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
if cctx.IsSet("config") {
|
||||
log.Info("Restoring config")
|
||||
|
||||
cf, err := homedir.Expand(cctx.String("config"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expanding config path: %w", err)
|
||||
}
|
||||
|
||||
_, err = os.Stat(cf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("stat config file (%s): %w", cf, err)
|
||||
}
|
||||
|
||||
var cerr error
|
||||
err = lr.SetConfig(func(raw interface{}) {
|
||||
rcfg, ok := raw.(*config.StorageMiner)
|
||||
if !ok {
|
||||
cerr = xerrors.New("expected miner config")
|
||||
return
|
||||
}
|
||||
|
||||
ff, err := config.FromFile(cf, rcfg)
|
||||
if err != nil {
|
||||
cerr = xerrors.Errorf("loading config: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
*rcfg = *ff.(*config.StorageMiner)
|
||||
})
|
||||
if cerr != nil {
|
||||
return cerr
|
||||
}
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting config: %w", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Warn("--config NOT SET, WILL USE DEFAULT VALUES")
|
||||
}
|
||||
|
||||
var storageCfg *stores.StorageConfig
|
||||
if cctx.IsSet("storage-config") {
|
||||
log.Info("Restoring storage path config")
|
||||
|
||||
cf, err := homedir.Expand(cctx.String("storage-config"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expanding storage config path: %w", err)
|
||||
@@ -182,101 +65,233 @@ var initRestoreCmd = &cli.Command{
|
||||
return xerrors.Errorf("reading storage config: %w", err)
|
||||
}
|
||||
|
||||
var cerr error
|
||||
err = lr.SetStorage(func(scfg *stores.StorageConfig) {
|
||||
cerr = json.Unmarshal(cfb, scfg)
|
||||
})
|
||||
if cerr != nil {
|
||||
return xerrors.Errorf("unmarshalling storage config: %w", cerr)
|
||||
}
|
||||
storageCfg = &stores.StorageConfig{}
|
||||
err = json.Unmarshal(cfb, storageCfg)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting storage config: %w", err)
|
||||
return xerrors.Errorf("cannot unmarshal json for storage config: %w", err)
|
||||
}
|
||||
} else {
|
||||
log.Warn("--storage-config NOT SET. NO SECTOR PATHS WILL BE CONFIGURED")
|
||||
}
|
||||
|
||||
log.Info("Restoring metadata backup")
|
||||
if err := restore(ctx, cctx, storageCfg, nil, func(api lapi.FullNode, maddr address.Address, peerid peer.ID, mi miner.MinerInfo) error {
|
||||
log.Info("Checking proof parameters")
|
||||
|
||||
mds, err := lr.Datastore(context.TODO(), "/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := paramfetch.GetParams(ctx, build.ParametersJSON(), build.SrsJSON(), uint64(mi.SectorSize)); err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
bar := pb.New64(st.Size())
|
||||
br := bar.NewProxyReader(f)
|
||||
bar.ShowTimeLeft = true
|
||||
bar.ShowPercent = true
|
||||
bar.ShowSpeed = true
|
||||
bar.Units = pb.U_BYTES
|
||||
log.Info("Configuring miner actor")
|
||||
|
||||
bar.Start()
|
||||
err = backupds.RestoreInto(br, mds)
|
||||
bar.Finish()
|
||||
if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("restoring metadata: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Checking actor metadata")
|
||||
|
||||
abytes, err := mds.Get(datastore.NewKey("miner-address"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor address from metadata datastore: %w", err)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromBytes(abytes)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing actor address: %w", err)
|
||||
}
|
||||
|
||||
log.Info("ACTOR ADDRESS: ", maddr.String())
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
log.Info("SECTOR SIZE: ", units.BytesSize(float64(mi.SectorSize)))
|
||||
|
||||
wk, err := api.StateAccountKey(ctx, mi.Worker, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("resolving worker key: %w", err)
|
||||
}
|
||||
|
||||
has, err := api.WalletHas(ctx, wk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking worker address: %w", err)
|
||||
}
|
||||
|
||||
if !has {
|
||||
return xerrors.Errorf("worker address %s for miner actor %s not present in full node wallet", mi.Worker, maddr)
|
||||
}
|
||||
|
||||
log.Info("Checking proof parameters")
|
||||
|
||||
if err := paramfetch.GetParams(ctx, build.ParametersJSON(), build.SrsJSON(), uint64(mi.SectorSize)); err != nil {
|
||||
return xerrors.Errorf("fetching proof parameters: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Initializing libp2p identity")
|
||||
|
||||
p2pSk, err := makeHostKey(lr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("make host key: %w", err)
|
||||
}
|
||||
|
||||
peerid, err := peer.IDFromPrivateKey(p2pSk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("peer ID from private key: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Configuring miner actor")
|
||||
|
||||
if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero()); err != nil {
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func restore(ctx context.Context, cctx *cli.Context, strConfig *stores.StorageConfig, manageConfig func(*config.StorageMiner) error, after func(api lapi.FullNode, addr address.Address, peerid peer.ID, mi miner.MinerInfo) error) error {
|
||||
if cctx.Args().Len() != 1 {
|
||||
return xerrors.Errorf("expected 1 argument")
|
||||
}
|
||||
|
||||
log.Info("Trying to connect to full node RPC")
|
||||
|
||||
api, closer, err := lcli.GetFullNodeAPIV1(cctx) // TODO: consider storing full node address in config
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
log.Info("Checking full node version")
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !v.APIVersion.EqMajorMinor(lapi.FullAPIVersion1) {
|
||||
return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", lapi.FullAPIVersion1, v.APIVersion)
|
||||
}
|
||||
|
||||
if !cctx.Bool("nosync") {
|
||||
if err := lcli.SyncWait(ctx, &v0api.WrapperV1Full{FullNode: api}, false); err != nil {
|
||||
return xerrors.Errorf("sync wait: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
bf, err := homedir.Expand(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expand backup file path: %w", err)
|
||||
}
|
||||
|
||||
st, err := os.Stat(bf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("stat backup file (%s): %w", bf, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(bf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("opening backup file: %w", err)
|
||||
}
|
||||
defer f.Close() // nolint:errcheck
|
||||
|
||||
log.Info("Checking if repo exists")
|
||||
|
||||
repoPath := cctx.String(FlagMinerRepo)
|
||||
r, err := repo.NewFS(repoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok, err := r.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return xerrors.Errorf("repo at '%s' is already initialized", cctx.String(FlagMinerRepo))
|
||||
}
|
||||
|
||||
log.Info("Initializing repo")
|
||||
|
||||
if err := r.Init(repo.StorageMiner); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.StorageMiner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lr.Close() //nolint:errcheck
|
||||
|
||||
if cctx.IsSet("config") {
|
||||
log.Info("Restoring config")
|
||||
|
||||
cf, err := homedir.Expand(cctx.String("config"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("expanding config path: %w", err)
|
||||
}
|
||||
|
||||
_, err = os.Stat(cf)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("stat config file (%s): %w", cf, err)
|
||||
}
|
||||
|
||||
var cerr error
|
||||
err = lr.SetConfig(func(raw interface{}) {
|
||||
rcfg, ok := raw.(*config.StorageMiner)
|
||||
if !ok {
|
||||
cerr = xerrors.New("expected miner config")
|
||||
return
|
||||
}
|
||||
|
||||
ff, err := config.FromFile(cf, rcfg)
|
||||
if err != nil {
|
||||
cerr = xerrors.Errorf("loading config: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
*rcfg = *ff.(*config.StorageMiner)
|
||||
if manageConfig != nil {
|
||||
cerr = manageConfig(rcfg)
|
||||
}
|
||||
})
|
||||
if cerr != nil {
|
||||
return cerr
|
||||
}
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting config: %w", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Warn("--config NOT SET, WILL USE DEFAULT VALUES")
|
||||
}
|
||||
|
||||
if strConfig != nil {
|
||||
log.Info("Restoring storage path config")
|
||||
|
||||
err = lr.SetStorage(func(scfg *stores.StorageConfig) {
|
||||
*scfg = *strConfig
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting storage config: %w", err)
|
||||
}
|
||||
} else {
|
||||
log.Warn("--storage-config NOT SET. NO SECTOR PATHS WILL BE CONFIGURED")
|
||||
}
|
||||
|
||||
log.Info("Restoring metadata backup")
|
||||
|
||||
mds, err := lr.Datastore(context.TODO(), "/metadata")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bar := pb.New64(st.Size())
|
||||
br := bar.NewProxyReader(f)
|
||||
bar.ShowTimeLeft = true
|
||||
bar.ShowPercent = true
|
||||
bar.ShowSpeed = true
|
||||
bar.Units = pb.U_BYTES
|
||||
|
||||
bar.Start()
|
||||
err = backupds.RestoreInto(br, mds)
|
||||
bar.Finish()
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("restoring metadata: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Checking actor metadata")
|
||||
|
||||
abytes, err := mds.Get(datastore.NewKey("miner-address"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor address from metadata datastore: %w", err)
|
||||
}
|
||||
|
||||
maddr, err := address.NewFromBytes(abytes)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing actor address: %w", err)
|
||||
}
|
||||
|
||||
log.Info("ACTOR ADDRESS: ", maddr.String())
|
||||
|
||||
mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
log.Info("SECTOR SIZE: ", units.BytesSize(float64(mi.SectorSize)))
|
||||
|
||||
wk, err := api.StateAccountKey(ctx, mi.Worker, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("resolving worker key: %w", err)
|
||||
}
|
||||
|
||||
has, err := api.WalletHas(ctx, wk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking worker address: %w", err)
|
||||
}
|
||||
|
||||
if !has {
|
||||
return xerrors.Errorf("worker address %s for miner actor %s not present in full node wallet", mi.Worker, maddr)
|
||||
}
|
||||
|
||||
log.Info("Initializing libp2p identity")
|
||||
|
||||
p2pSk, err := makeHostKey(lr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("make host key: %w", err)
|
||||
}
|
||||
|
||||
peerid, err := peer.IDFromPrivateKey(p2pSk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("peer ID from private key: %w", err)
|
||||
}
|
||||
|
||||
return after(api, maddr, peerid, mi)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/client"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
MarketsService = "markets"
|
||||
)
|
||||
|
||||
var serviceCmd = &cli.Command{
|
||||
Name: "service",
|
||||
Usage: "Initialize a lotus miner sub-service",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "config file (config.toml)",
|
||||
Required: true,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "nosync",
|
||||
Usage: "don't check full-node sync status",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "type",
|
||||
Usage: "type of service to be enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "api-sealer",
|
||||
Usage: "sealer API info (lotus-miner auth api-info --perm=admin)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "api-sector-index",
|
||||
Usage: "sector Index API info (lotus-miner auth api-info --perm=admin)",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[backupFile]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := lcli.ReqContext(cctx)
|
||||
log.Info("Initializing lotus miner service")
|
||||
|
||||
es := EnabledServices(cctx.StringSlice("type"))
|
||||
|
||||
if len(es) == 0 {
|
||||
return xerrors.Errorf("at least one module must be enabled")
|
||||
}
|
||||
|
||||
// we should remove this as soon as we have more service types and not just `markets`
|
||||
if !es.Contains(MarketsService) {
|
||||
return xerrors.Errorf("markets module must be enabled")
|
||||
}
|
||||
|
||||
if !cctx.IsSet("api-sealer") {
|
||||
return xerrors.Errorf("--api-sealer is required without the sealer module enabled")
|
||||
}
|
||||
if !cctx.IsSet("api-sector-index") {
|
||||
return xerrors.Errorf("--api-sector-index is required without the sector storage module enabled")
|
||||
}
|
||||
|
||||
if err := restore(ctx, cctx, &stores.StorageConfig{}, func(cfg *config.StorageMiner) error {
|
||||
cfg.Subsystems.EnableMarkets = es.Contains(MarketsService)
|
||||
cfg.Subsystems.EnableMining = false
|
||||
cfg.Subsystems.EnableSealing = false
|
||||
cfg.Subsystems.EnableSectorStorage = false
|
||||
|
||||
if !cfg.Subsystems.EnableSealing {
|
||||
ai, err := checkApiInfo(ctx, cctx.String("api-sealer"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking sealer API: %w", err)
|
||||
}
|
||||
cfg.Subsystems.SealerApiInfo = ai
|
||||
}
|
||||
|
||||
if !cfg.Subsystems.EnableSectorStorage {
|
||||
ai, err := checkApiInfo(ctx, cctx.String("api-sector-index"))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking sector index API: %w", err)
|
||||
}
|
||||
cfg.Subsystems.SectorIndexApiInfo = ai
|
||||
}
|
||||
|
||||
return nil
|
||||
}, func(api lapi.FullNode, maddr address.Address, peerid peer.ID, mi miner.MinerInfo) error {
|
||||
if es.Contains(MarketsService) {
|
||||
log.Info("Configuring miner actor")
|
||||
|
||||
if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type EnabledServices []string
|
||||
|
||||
func (es EnabledServices) Contains(name string) bool {
|
||||
for _, s := range es {
|
||||
if s == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func checkApiInfo(ctx context.Context, ai string) (string, error) {
|
||||
ai = strings.TrimPrefix(strings.TrimSpace(ai), "MINER_API_INFO=")
|
||||
info := cliutil.ParseApiInfo(ai)
|
||||
addr, err := info.DialArgs("v0")
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("could not get DialArgs: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Checking api version of %s", addr)
|
||||
|
||||
api, closer, err := client.NewStorageMinerRPCV0(ctx, addr, info.AuthHeader())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
if err != nil {
|
||||
return "", xerrors.Errorf("checking version: %w", err)
|
||||
}
|
||||
|
||||
if !v.APIVersion.EqMajorMinor(lapi.MinerAPIVersion0) {
|
||||
return "", xerrors.Errorf("remote service API version didn't match (expected %s, remote %s)", lapi.MinerAPIVersion0, v.APIVersion)
|
||||
}
|
||||
|
||||
return ai, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fatih/color"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -61,9 +62,14 @@ func main() {
|
||||
trace.UnregisterExporter(jaeger)
|
||||
jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name)
|
||||
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
if originBefore != nil {
|
||||
return originBefore(cctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -81,7 +87,10 @@ func main() {
|
||||
Aliases: []string{"a"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
// examined in the Before above
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/fatih/color"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cidutil/cidenc"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -752,9 +753,9 @@ var transfersListCmd = &cli.Command{
|
||||
Usage: "print verbose transfer details",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "completed",
|
||||
@@ -770,6 +771,10 @@ var transfersListCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -784,7 +789,6 @@ var transfersListCmd = &cli.Command{
|
||||
|
||||
verbose := cctx.Bool("verbose")
|
||||
completed := cctx.Bool("completed")
|
||||
color := cctx.Bool("color")
|
||||
watch := cctx.Bool("watch")
|
||||
showFailed := cctx.Bool("show-failed")
|
||||
if watch {
|
||||
@@ -798,7 +802,7 @@ var transfersListCmd = &cli.Command{
|
||||
|
||||
tm.MoveCursor(1, 1)
|
||||
|
||||
lcli.OutputDataTransferChannels(tm.Screen, channels, verbose, completed, color, showFailed)
|
||||
lcli.OutputDataTransferChannels(tm.Screen, channels, verbose, completed, showFailed)
|
||||
|
||||
tm.Flush()
|
||||
|
||||
@@ -823,7 +827,7 @@ var transfersListCmd = &cli.Command{
|
||||
}
|
||||
}
|
||||
}
|
||||
lcli.OutputDataTransferChannels(os.Stdout, channels, verbose, completed, color, showFailed)
|
||||
lcli.OutputDataTransferChannels(os.Stdout, channels, verbose, completed, showFailed)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ var provingFaultsCmd = &cli.Command{
|
||||
Name: "faults",
|
||||
Usage: "View the currently known proving faulty sectors information",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,8 +88,6 @@ var provingInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "View current state information",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -197,8 +193,6 @@ var provingDeadlinesCmd = &cli.Command{
|
||||
Name: "deadlines",
|
||||
Usage: "View the current proving period deadlines information",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
|
||||
api, acloser, err := lcli.GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/lib/ulimit"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
)
|
||||
@@ -118,13 +119,33 @@ var runCmd = &cli.Command{
|
||||
return xerrors.Errorf("repo at '%s' is not initialized, run 'lotus-miner init' to set it up", minerRepoPath)
|
||||
}
|
||||
|
||||
lr, err := r.Lock(repo.StorageMiner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := lr.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, ok := c.(*config.StorageMiner)
|
||||
if !ok {
|
||||
return xerrors.Errorf("invalid config for repo, got: %T", c)
|
||||
}
|
||||
|
||||
bootstrapLibP2P := cfg.Subsystems.EnableMarkets
|
||||
|
||||
err = lr.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
shutdownChan := make(chan struct{})
|
||||
|
||||
var minerapi api.StorageMiner
|
||||
stop, err := node.New(ctx,
|
||||
node.StorageMiner(&minerapi),
|
||||
node.StorageMiner(&minerapi, cfg.Subsystems),
|
||||
node.Override(new(dtypes.ShutdownChan), shutdownChan),
|
||||
node.Online(),
|
||||
node.Base(),
|
||||
node.Repo(r),
|
||||
|
||||
node.ApplyIf(func(s *node.Settings) bool { return cctx.IsSet("miner-api") },
|
||||
@@ -142,14 +163,18 @@ var runCmd = &cli.Command{
|
||||
return xerrors.Errorf("getting API endpoint: %w", err)
|
||||
}
|
||||
|
||||
// Bootstrap with full node
|
||||
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting full node libp2p address: %w", err)
|
||||
}
|
||||
if bootstrapLibP2P {
|
||||
log.Infof("Bootstrapping libp2p network with full node")
|
||||
|
||||
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
|
||||
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
|
||||
// Bootstrap with full node
|
||||
remoteAddrs, err := nodeApi.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting full node libp2p address: %w", err)
|
||||
}
|
||||
|
||||
if err := minerapi.NetConnect(ctx, remoteAddrs); err != nil {
|
||||
return xerrors.Errorf("connecting to full node (libp2p): %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Remote version %s", v)
|
||||
|
||||
@@ -36,10 +36,16 @@ var sealingWorkersCmd = &cli.Command{
|
||||
Name: "workers",
|
||||
Usage: "list workers",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "color"},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -127,14 +133,20 @@ var sealingJobsCmd = &cli.Command{
|
||||
Name: "jobs",
|
||||
Usage: "list running jobs",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "color"},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-ret-done",
|
||||
Usage: "show returned but not consumed calls",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -161,9 +161,10 @@ var sectorsListCmd = &cli.Command{
|
||||
Usage: "show removed sectors",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Aliases: []string{"c"},
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
Aliases: []string{"c"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "fast",
|
||||
@@ -183,7 +184,9 @@ var sectorsListCmd = &cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -436,6 +439,12 @@ var sectorsExtendCmd = &cli.Command{
|
||||
Usage: "when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs",
|
||||
Required: false,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "expiration-ignore",
|
||||
Value: 120,
|
||||
Usage: "when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now",
|
||||
Required: false,
|
||||
},
|
||||
&cli.Int64Flag{
|
||||
Name: "expiration-cutoff",
|
||||
Usage: "when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified)",
|
||||
@@ -494,6 +503,10 @@ var sectorsExtendCmd = &cli.Command{
|
||||
continue
|
||||
}
|
||||
|
||||
if si.Expiration < (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-ignore"))) {
|
||||
continue
|
||||
}
|
||||
|
||||
if cctx.IsSet("expiration-cutoff") {
|
||||
if si.Expiration > (head.Height() + abi.ChainEpoch(cctx.Int64("expiration-cutoff"))) {
|
||||
continue
|
||||
@@ -508,6 +521,10 @@ var sectorsExtendCmd = &cli.Command{
|
||||
|
||||
// Set the new expiration to 48 hours less than the theoretical maximum lifetime
|
||||
newExp := ml - (miner3.WPoStProvingPeriod * 2) + si.Activation
|
||||
if withinTolerance(si.Expiration, newExp) || si.Expiration >= newExp {
|
||||
continue
|
||||
}
|
||||
|
||||
p, err := api.StateSectorPartition(ctx, maddr, si.SectorNumber, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting sector location for sector %d: %w", si.SectorNumber, err)
|
||||
@@ -525,7 +542,7 @@ var sectorsExtendCmd = &cli.Command{
|
||||
} else {
|
||||
added := false
|
||||
for exp := range es {
|
||||
if withinTolerance(exp, newExp) {
|
||||
if withinTolerance(exp, newExp) && newExp >= exp && exp > si.Expiration {
|
||||
es[exp] = append(es[exp], uint64(si.SectorNumber))
|
||||
added = true
|
||||
break
|
||||
|
||||
@@ -166,13 +166,19 @@ var storageListCmd = &cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list local storage paths",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "color"},
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Subcommands: []*cli.Command{
|
||||
storageListSectorsCmd,
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@@ -478,12 +484,15 @@ var storageListSectorsCmd = &cli.Command{
|
||||
Usage: "get list of all sector files",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "color",
|
||||
Value: true,
|
||||
Name: "color",
|
||||
Usage: "use color in display output",
|
||||
DefaultText: "depends on output being a TTY",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
if cctx.IsSet("color") {
|
||||
color.NoColor = !cctx.Bool("color")
|
||||
}
|
||||
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -314,7 +314,7 @@ var DaemonCmd = &cli.Command{
|
||||
stop, err := node.New(ctx,
|
||||
node.FullAPI(&api, node.Lite(isLite)),
|
||||
|
||||
node.Online(),
|
||||
node.Base(),
|
||||
node.Repo(r),
|
||||
|
||||
node.Override(new(dtypes.Bootstrapper), isBootstrapper),
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
* [SealingAbort](#SealingAbort)
|
||||
* [SealingSchedDiag](#SealingSchedDiag)
|
||||
* [Sector](#Sector)
|
||||
* [SectorAddPieceToAny](#SectorAddPieceToAny)
|
||||
* [SectorCommitFlush](#SectorCommitFlush)
|
||||
* [SectorCommitPending](#SectorCommitPending)
|
||||
* [SectorGetExpectedSealDuration](#SectorGetExpectedSealDuration)
|
||||
@@ -118,6 +119,7 @@
|
||||
* [SectorsRefs](#SectorsRefs)
|
||||
* [SectorsStatus](#SectorsStatus)
|
||||
* [SectorsSummary](#SectorsSummary)
|
||||
* [SectorsUnsealPiece](#SectorsUnsealPiece)
|
||||
* [SectorsUpdate](#SectorsUpdate)
|
||||
* [Storage](#Storage)
|
||||
* [StorageAddLocal](#StorageAddLocal)
|
||||
@@ -227,6 +229,7 @@ Response:
|
||||
"PreCommitControl": null,
|
||||
"CommitControl": null,
|
||||
"TerminateControl": null,
|
||||
"DealPublishControl": null,
|
||||
"DisableOwnerFallback": true,
|
||||
"DisableWorkerFallback": true
|
||||
}
|
||||
@@ -685,7 +688,6 @@ Response:
|
||||
"SlashEpoch": 10101,
|
||||
"FastRetrieval": true,
|
||||
"Message": "string value",
|
||||
"StoreID": 12,
|
||||
"FundsReserved": "0",
|
||||
"Ref": {
|
||||
"TransferType": "string value",
|
||||
@@ -704,7 +706,8 @@ Response:
|
||||
"Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"ID": 3
|
||||
},
|
||||
"SectorNumber": 9
|
||||
"SectorNumber": 9,
|
||||
"CARv2FilePath": "string value"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1560,6 +1563,54 @@ Response: `{}`
|
||||
## Sector
|
||||
|
||||
|
||||
### SectorAddPieceToAny
|
||||
Add piece to an open sector. If no sectors with enough space are open,
|
||||
either a new sector will be created, or this call will block until more
|
||||
sectors can be created.
|
||||
|
||||
|
||||
Perms: admin
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
1024,
|
||||
{},
|
||||
{
|
||||
"PublishCid": null,
|
||||
"DealID": 5432,
|
||||
"DealProposal": {
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1032,
|
||||
"VerifiedDeal": true,
|
||||
"Client": "f01234",
|
||||
"Provider": "f01234",
|
||||
"Label": "string value",
|
||||
"StartEpoch": 10101,
|
||||
"EndEpoch": 10101,
|
||||
"StoragePricePerEpoch": "0",
|
||||
"ProviderCollateral": "0",
|
||||
"ClientCollateral": "0"
|
||||
},
|
||||
"DealSchedule": {
|
||||
"StartEpoch": 10101,
|
||||
"EndEpoch": 10101
|
||||
},
|
||||
"KeepUnsealed": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"Sector": 9,
|
||||
"Offset": 1032
|
||||
}
|
||||
```
|
||||
|
||||
### SectorCommitFlush
|
||||
SectorCommitFlush immediately sends a Commit message with sectors aggregated for Commit.
|
||||
Returns null if message wasn't sent
|
||||
@@ -1860,6 +1911,30 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### SectorsUnsealPiece
|
||||
|
||||
|
||||
Perms: admin
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ID": {
|
||||
"Miner": 1000,
|
||||
"Number": 9
|
||||
},
|
||||
"ProofType": 8
|
||||
},
|
||||
1040384,
|
||||
1024,
|
||||
null,
|
||||
null
|
||||
]
|
||||
```
|
||||
|
||||
Response: `{}`
|
||||
|
||||
### SectorsUpdate
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* [ChainGetBlockMessages](#ChainGetBlockMessages)
|
||||
* [ChainGetGenesis](#ChainGetGenesis)
|
||||
* [ChainGetMessage](#ChainGetMessage)
|
||||
* [ChainGetMessagesInTipset](#ChainGetMessagesInTipset)
|
||||
* [ChainGetNode](#ChainGetNode)
|
||||
* [ChainGetParentMessages](#ChainGetParentMessages)
|
||||
* [ChainGetParentReceipts](#ChainGetParentReceipts)
|
||||
@@ -533,6 +534,28 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### ChainGetMessagesInTipset
|
||||
ChainGetMessagesInTipset returns message stores in current tipset
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Response: `null`
|
||||
|
||||
### ChainGetNode
|
||||
|
||||
|
||||
@@ -1444,7 +1467,7 @@ Inputs:
|
||||
},
|
||||
"Piece": null,
|
||||
"Size": 42,
|
||||
"LocalStore": 12,
|
||||
"LocalCARV2FilePath": "string value",
|
||||
"Total": "0",
|
||||
"UnsealPrice": "0",
|
||||
"PaymentInterval": 42,
|
||||
@@ -1498,7 +1521,7 @@ Inputs:
|
||||
},
|
||||
"Piece": null,
|
||||
"Size": 42,
|
||||
"LocalStore": 12,
|
||||
"LocalCARV2FilePath": "string value",
|
||||
"Total": "0",
|
||||
"UnsealPrice": "0",
|
||||
"PaymentInterval": 42,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* [ChainGetBlockMessages](#ChainGetBlockMessages)
|
||||
* [ChainGetGenesis](#ChainGetGenesis)
|
||||
* [ChainGetMessage](#ChainGetMessage)
|
||||
* [ChainGetMessagesInTipset](#ChainGetMessagesInTipset)
|
||||
* [ChainGetNode](#ChainGetNode)
|
||||
* [ChainGetParentMessages](#ChainGetParentMessages)
|
||||
* [ChainGetParentReceipts](#ChainGetParentReceipts)
|
||||
@@ -535,6 +536,28 @@ Response:
|
||||
}
|
||||
```
|
||||
|
||||
### ChainGetMessagesInTipset
|
||||
ChainGetMessagesInTipset returns message stores in current tipset
|
||||
|
||||
|
||||
Perms: read
|
||||
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
[
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
{
|
||||
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
|
||||
}
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
Response: `null`
|
||||
|
||||
### ChainGetNode
|
||||
|
||||
|
||||
@@ -1446,7 +1469,7 @@ Inputs:
|
||||
},
|
||||
"Piece": null,
|
||||
"Size": 42,
|
||||
"LocalStore": 12,
|
||||
"LocalCARV2FilePath": "string value",
|
||||
"Total": "0",
|
||||
"UnsealPrice": "0",
|
||||
"PaymentInterval": 42,
|
||||
@@ -1500,7 +1523,7 @@ Inputs:
|
||||
},
|
||||
"Piece": null,
|
||||
"Size": 42,
|
||||
"LocalStore": 12,
|
||||
"LocalCARV2FilePath": "string value",
|
||||
"Total": "0",
|
||||
"UnsealPrice": "0",
|
||||
"PaymentInterval": 42,
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE:
|
||||
lotus-miner [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.11.0
|
||||
1.11.1-dev
|
||||
|
||||
COMMANDS:
|
||||
init Initialize a lotus miner repo
|
||||
@@ -41,8 +41,8 @@ COMMANDS:
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--actor value, -a value specify other actor to check state for (read only)
|
||||
--color (default: false)
|
||||
--miner-repo value, --storagerepo value Specify miner repo path. flag(storagerepo) and env(LOTUS_STORAGE_PATH) are DEPRECATION, will REMOVE SOON (default: "/Users/jennijuju/.lotusminer") [$LOTUS_MINER_PATH, $LOTUS_STORAGE_PATH]
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--miner-repo value, --storagerepo value Specify miner repo path. flag(storagerepo) and env(LOTUS_STORAGE_PATH) are DEPRECATION, will REMOVE SOON (default: "~/.lotusminer") [$LOTUS_MINER_PATH, $LOTUS_STORAGE_PATH]
|
||||
--help, -h show help (default: false)
|
||||
--version, -v print the version (default: false)
|
||||
```
|
||||
@@ -57,6 +57,7 @@ USAGE:
|
||||
|
||||
COMMANDS:
|
||||
restore Initialize a lotus miner repo from a backup
|
||||
service Initialize a lotus miner sub-service
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
OPTIONS:
|
||||
@@ -93,6 +94,24 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
### lotus-miner init service
|
||||
```
|
||||
NAME:
|
||||
lotus-miner init service - Initialize a lotus miner sub-service
|
||||
|
||||
USAGE:
|
||||
lotus-miner init service [command options] [backupFile]
|
||||
|
||||
OPTIONS:
|
||||
--config value config file (config.toml)
|
||||
--nosync don't check full-node sync status (default: false)
|
||||
--type value type of service to be enabled
|
||||
--api-sealer value sealer API info (lotus-miner auth api-info --perm=admin)
|
||||
--api-sector-index value sector Index API info (lotus-miner auth api-info --perm=admin)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
## lotus-miner run
|
||||
```
|
||||
NAME:
|
||||
@@ -295,7 +314,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
--verbose (default: false)
|
||||
--color (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
@@ -888,7 +907,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
--verbose, -v print verbose transfer details (default: false)
|
||||
--color use color in display output (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--completed show completed data transfers (default: false)
|
||||
--watch watch deal updates in real-time, rather than a one time list (default: false)
|
||||
--show-failed show failed/cancelled transfers (default: false)
|
||||
@@ -1344,7 +1363,7 @@ USAGE:
|
||||
|
||||
OPTIONS:
|
||||
--show-removed show removed sectors (default: false)
|
||||
--color, -c (default: true)
|
||||
--color, -c use color in display output (default: depends on output being a TTY)
|
||||
--fast don't show on-chain info for better performance (default: false)
|
||||
--events display number of events the sector has received (default: false)
|
||||
--seal-time display how long it took for the sector to be sealed (default: false)
|
||||
@@ -1405,6 +1424,7 @@ OPTIONS:
|
||||
--new-expiration value new expiration epoch (default: 0)
|
||||
--v1-sectors renews all v1 sectors up to the maximum possible lifetime (default: false)
|
||||
--tolerance value when extending v1 sectors, don't try to extend sectors by fewer than this number of epochs (default: 20160)
|
||||
--expiration-ignore value when extending v1 sectors, skip sectors whose current expiration is less than <ignore> epochs from now (default: 120)
|
||||
--expiration-cutoff value when extending v1 sectors, skip sectors whose current expiration is more than <cutoff> epochs from now (infinity if unspecified) (default: 0)
|
||||
|
||||
--help, -h show help (default: false)
|
||||
@@ -1739,7 +1759,7 @@ COMMANDS:
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
OPTIONS:
|
||||
--color (default: false)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
--version, -v print the version (default: false)
|
||||
|
||||
@@ -1754,7 +1774,7 @@ USAGE:
|
||||
lotus-miner storage list sectors [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
@@ -1816,7 +1836,7 @@ USAGE:
|
||||
lotus-miner sealing jobs [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color (default: false)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--show-ret-done show returned but not consumed calls (default: false)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
@@ -1831,7 +1851,7 @@ USAGE:
|
||||
lotus-miner sealing workers [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--color (default: false)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE:
|
||||
lotus-worker [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.11.0
|
||||
1.11.1-dev
|
||||
|
||||
COMMANDS:
|
||||
run Start lotus worker
|
||||
@@ -20,7 +20,7 @@ COMMANDS:
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--worker-repo value, --workerrepo value Specify worker repo path. flag workerrepo and env WORKER_PATH are DEPRECATION, will REMOVE SOON (default: "~/.lotusworker") [$LOTUS_WORKER_PATH, $WORKER_PATH]
|
||||
--miner-repo value, --storagerepo value Specify miner repo path. flag storagerepo and env LOTUS_STORAGE_PATH are DEPRECATION, will REMOVE SOON (default: "/Users/jennijuju/.lotusminer") [$LOTUS_MINER_PATH, $LOTUS_STORAGE_PATH]
|
||||
--miner-repo value, --storagerepo value Specify miner repo path. flag storagerepo and env LOTUS_STORAGE_PATH are DEPRECATION, will REMOVE SOON (default: "~/.lotusminer") [$LOTUS_MINER_PATH, $LOTUS_STORAGE_PATH]
|
||||
--enable-gpu-proving enable use of GPU for mining operations (default: true)
|
||||
--help, -h show help (default: false)
|
||||
--version, -v print the version (default: false)
|
||||
|
||||
@@ -7,7 +7,7 @@ USAGE:
|
||||
lotus [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
1.11.0
|
||||
1.11.1-dev
|
||||
|
||||
COMMANDS:
|
||||
daemon Start a lotus daemon process
|
||||
@@ -535,7 +535,7 @@ CATEGORY:
|
||||
|
||||
OPTIONS:
|
||||
--verbose, -v print verbose deal details (default: false)
|
||||
--color use color in display output (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--show-failed show failed/failing deals (default: true)
|
||||
--completed show completed retrievals (default: false)
|
||||
--watch watch deal updates in real-time, rather than a one time list (default: false)
|
||||
@@ -609,7 +609,7 @@ CATEGORY:
|
||||
|
||||
OPTIONS:
|
||||
--verbose, -v print verbose deal details (default: false)
|
||||
--color use color in display output (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--show-failed show failed/failing deals (default: false)
|
||||
--watch watch deal updates in real-time, rather than a one time list (default: false)
|
||||
--help, -h show help (default: false)
|
||||
@@ -747,7 +747,7 @@ CATEGORY:
|
||||
|
||||
OPTIONS:
|
||||
--verbose, -v print verbose transfer details (default: false)
|
||||
--color use color in display output (default: true)
|
||||
--color use color in display output (default: depends on output being a TTY)
|
||||
--completed show completed data transfers (default: false)
|
||||
--watch watch deal updates in real-time, rather than a one time list (default: false)
|
||||
--show-failed show failed/cancelled transfers (default: false)
|
||||
@@ -1673,7 +1673,7 @@ NAME:
|
||||
lotus state get-actor - Print actor information
|
||||
|
||||
USAGE:
|
||||
lotus state get-actor [command options] [actorrAddress]
|
||||
lotus state get-actor [command options] [actorAddress]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
@@ -2140,7 +2140,7 @@ USAGE:
|
||||
lotus chain export [command options] [outputPath]
|
||||
|
||||
OPTIONS:
|
||||
--tipset value
|
||||
--tipset value specify tipset to start the export from (default: "@head")
|
||||
--recent-stateroots value specify the number of recent state roots to include in the export (default: 0)
|
||||
--skip-old-msgs (default: false)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
@@ -43,13 +43,8 @@ Testing an RC:
|
||||
- [ ] **Stage 1 - Internal Testing**
|
||||
- Binaries
|
||||
- [ ] Ensure the RC release has downloadable binaries
|
||||
- [ ] Validate the binary is able to run on at least one platform
|
||||
- Upgrade our testnet infra
|
||||
- [ ] 1 bootstrap node
|
||||
- [ ] 1 miner
|
||||
- [ ] Scratch nodes
|
||||
- [ ] Wait 24 hours, confirm nodes stay in sync
|
||||
- [ ] Remaining testnet infra
|
||||
- Upgrade our mainnet infra
|
||||
- [ ] Subset of development full archival nodes
|
||||
- [ ] Subset of bootstrappers (1 per region)
|
||||
|
||||
+1
-1
@@ -11,7 +11,6 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -24,6 +23,7 @@ import (
|
||||
commpffi "github.com/filecoin-project/go-commp-utils/ffiwrapper"
|
||||
"github.com/filecoin-project/go-commp-utils/zerocomm"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fr32"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -1,13 +1,13 @@
|
||||
package ffiwrapper
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
)
|
||||
|
||||
|
||||
Vendored
-2
@@ -29,8 +29,6 @@ var log = logging.Logger("advmgr")
|
||||
|
||||
var ErrNoWorkers = errors.New("no suitable workers found")
|
||||
|
||||
type URLs []string
|
||||
|
||||
type Worker interface {
|
||||
storiface.WorkerCalls
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -75,6 +75,10 @@ func (mgr *SectorMgr) NewSector(ctx context.Context, sector storage.SectorRef) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgr *SectorMgr) SectorsUnsealPiece(ctx context.Context, sector storage.SectorRef, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, commd *cid.Cid) error {
|
||||
panic("SectorMgr: unsealing piece: implement me")
|
||||
}
|
||||
|
||||
func (mgr *SectorMgr) AddPiece(ctx context.Context, sectorID storage.SectorRef, existingPieces []abi.UnpaddedPieceSize, size abi.UnpaddedPieceSize, r io.Reader) (abi.PieceInfo, error) {
|
||||
log.Warn("Add piece: ", sectorID, size, sectorID.ProofType)
|
||||
|
||||
@@ -496,10 +500,6 @@ func (mgr *SectorMgr) ReturnFetch(ctx context.Context, callID storiface.CallID,
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
func (mgr *SectorMgr) SectorsUnsealPiece(ctx context.Context, sector storage.SectorRef, offset storiface.UnpaddedByteIndex, size abi.UnpaddedPieceSize, randomness abi.SealRandomness, commd *cid.Cid) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m mockVerifProver) VerifySeal(svi proof5.SealVerifyInfo) (bool, error) {
|
||||
plen, err := svi.SealProof.ProofSize()
|
||||
if err != nil {
|
||||
|
||||
+2
-1
@@ -7,7 +7,6 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/detailyang/go-fallocate"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
|
||||
@@ -15,6 +14,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
|
||||
var log = logging.Logger("partialfile")
|
||||
|
||||
+3
-4
@@ -7,12 +7,12 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/gorilla/mux"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/partialfile"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/tarutil"
|
||||
|
||||
@@ -53,11 +53,10 @@ func (handler *FetchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
mux := mux.NewRouter()
|
||||
|
||||
mux.HandleFunc("/remote/stat/{id}", handler.remoteStatFs).Methods("GET")
|
||||
mux.HandleFunc("/remote/{type}/{id}/{spt}/allocated/{offset}/{size}", handler.remoteGetAllocated).Methods("GET")
|
||||
mux.HandleFunc("/remote/{type}/{id}", handler.remoteGetSector).Methods("GET")
|
||||
mux.HandleFunc("/remote/{type}/{id}", handler.remoteDeleteSector).Methods("DELETE")
|
||||
|
||||
mux.HandleFunc("/remote/{type}/{id}/{spt}/allocated/{offset}/{size}", handler.remoteGetAllocated).Methods("GET")
|
||||
|
||||
mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -66,6 +66,8 @@ type SectorIndex interface { // part of storage-miner api
|
||||
// atomically acquire locks on all sector file types. close ctx to unlock
|
||||
StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error
|
||||
StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error)
|
||||
|
||||
StorageList(ctx context.Context) (map[ID][]Decl, error)
|
||||
}
|
||||
|
||||
type Decl struct {
|
||||
|
||||
+2
@@ -158,6 +158,8 @@ func (p *path) sectorPath(sid abi.SectorID, fileType storiface.SectorFileType) s
|
||||
return filepath.Join(p.local, fileType.String(), storiface.SectorName(sid))
|
||||
}
|
||||
|
||||
type URLs []string
|
||||
|
||||
func NewLocal(ctx context.Context, ls LocalStorage, index SectorIndex, urls []string) (*Local, error) {
|
||||
l := &Local{
|
||||
localStorage: ls,
|
||||
|
||||
+16
-1
@@ -1,7 +1,7 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: index.go
|
||||
|
||||
// Package mock_stores is a generated GoMock package.
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
@@ -125,6 +125,21 @@ func (mr *MockSectorIndexMockRecorder) StorageInfo(arg0, arg1 interface{}) *gomo
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageInfo", reflect.TypeOf((*MockSectorIndex)(nil).StorageInfo), arg0, arg1)
|
||||
}
|
||||
|
||||
// StorageList mocks base method.
|
||||
func (m *MockSectorIndex) StorageList(ctx context.Context) (map[stores.ID][]stores.Decl, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StorageList", ctx)
|
||||
ret0, _ := ret[0].(map[stores.ID][]stores.Decl)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// StorageList indicates an expected call of StorageList.
|
||||
func (mr *MockSectorIndexMockRecorder) StorageList(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageList", reflect.TypeOf((*MockSectorIndex)(nil).StorageList), ctx)
|
||||
}
|
||||
|
||||
// StorageLock mocks base method.
|
||||
func (m *MockSectorIndex) StorageLock(ctx context.Context, sector abi.SectorID, read, write storiface.SectorFileType) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: interface.go
|
||||
|
||||
// Package mock_stores is a generated GoMock package.
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
|
||||
+26
-25
@@ -297,6 +297,32 @@ func (r *Remote) fetch(ctx context.Context, url, outname string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Remote) checkAllocated(ctx context.Context, url string, spt abi.RegisteredSealProof, offset, size abi.PaddedPieceSize) (bool, error) {
|
||||
url = fmt.Sprintf("%s/%d/allocated/%d/%d", url, spt, offset.Unpadded(), size.Unpadded())
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("request: %w", err)
|
||||
}
|
||||
req.Header = r.auth.Clone()
|
||||
fmt.Printf("req using header: %#v \n", r.auth)
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("do request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close() // nolint
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
return true, nil
|
||||
case http.StatusRequestedRangeNotSatisfiable:
|
||||
return false, nil
|
||||
default:
|
||||
return false, xerrors.Errorf("unexpected http response: %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Remote) MoveStorage(ctx context.Context, s storage.SectorRef, types storiface.SectorFileType) error {
|
||||
// Make sure we have the data local
|
||||
_, _, err := r.AcquireSector(ctx, s, types, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove)
|
||||
@@ -419,31 +445,6 @@ func (r *Remote) FsStat(ctx context.Context, id ID) (fsutil.FsStat, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r *Remote) checkAllocated(ctx context.Context, url string, spt abi.RegisteredSealProof, offset, size abi.PaddedPieceSize) (bool, error) {
|
||||
url = fmt.Sprintf("%s/%d/allocated/%d/%d", url, spt, offset.Unpadded(), size.Unpadded())
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("request: %w", err)
|
||||
}
|
||||
req.Header = r.auth.Clone()
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("do request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close() // nolint
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
return true, nil
|
||||
case http.StatusRequestedRangeNotSatisfiable:
|
||||
return false, nil
|
||||
default:
|
||||
return false, xerrors.Errorf("unexpected http response: %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Remote) readRemote(ctx context.Context, url string, offset, size abi.PaddedPieceSize) (io.ReadCloser, error) {
|
||||
if len(r.limit) >= cap(r.limit) {
|
||||
log.Infof("Throttling remote read, %d already running", len(r.limit))
|
||||
|
||||
Vendored
+4
-382
@@ -8,7 +8,7 @@ import (
|
||||
"sort"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
market "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
api "github.com/filecoin-project/lotus/api"
|
||||
miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -46,7 +46,7 @@ func (t *Piece) MarshalCBOR(w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.DealInfo (sealing.DealInfo) (struct)
|
||||
// t.DealInfo (api.PieceDealInfo) (struct)
|
||||
if len("DealInfo") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealInfo\" was too long")
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func (t *Piece) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
|
||||
}
|
||||
// t.DealInfo (sealing.DealInfo) (struct)
|
||||
// t.DealInfo (api.PieceDealInfo) (struct)
|
||||
case "DealInfo":
|
||||
|
||||
{
|
||||
@@ -120,7 +120,7 @@ func (t *Piece) UnmarshalCBOR(r io.Reader) error {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.DealInfo = new(DealInfo)
|
||||
t.DealInfo = new(api.PieceDealInfo)
|
||||
if err := t.DealInfo.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealInfo pointer: %w", err)
|
||||
}
|
||||
@@ -136,384 +136,6 @@ func (t *Piece) UnmarshalCBOR(r io.Reader) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
func (t *DealInfo) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{165}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.PublishCid (cid.Cid) (struct)
|
||||
if len("PublishCid") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"PublishCid\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("PublishCid"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("PublishCid")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.PublishCid == nil {
|
||||
if _, err := w.Write(cbg.CborNull); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteCidBuf(scratch, w, *t.PublishCid); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.PublishCid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// t.DealID (abi.DealID) (uint64)
|
||||
if len("DealID") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealID\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealID"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealID")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.DealID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.DealProposal (market.DealProposal) (struct)
|
||||
if len("DealProposal") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealProposal\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealProposal"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealProposal")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.DealProposal.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.DealSchedule (sealing.DealSchedule) (struct)
|
||||
if len("DealSchedule") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"DealSchedule\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("DealSchedule"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("DealSchedule")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.DealSchedule.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.KeepUnsealed (bool) (bool)
|
||||
if len("KeepUnsealed") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"KeepUnsealed\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("KeepUnsealed"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("KeepUnsealed")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cbg.WriteBool(w, t.KeepUnsealed); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DealInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = DealInfo{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajMap {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("DealInfo: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// t.PublishCid (cid.Cid) (struct)
|
||||
case "PublishCid":
|
||||
|
||||
{
|
||||
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.PublishCid: %w", err)
|
||||
}
|
||||
|
||||
t.PublishCid = &c
|
||||
}
|
||||
|
||||
}
|
||||
// t.DealID (abi.DealID) (uint64)
|
||||
case "DealID":
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.DealID = abi.DealID(extra)
|
||||
|
||||
}
|
||||
// t.DealProposal (market.DealProposal) (struct)
|
||||
case "DealProposal":
|
||||
|
||||
{
|
||||
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := br.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.DealProposal = new(market.DealProposal)
|
||||
if err := t.DealProposal.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealProposal pointer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// t.DealSchedule (sealing.DealSchedule) (struct)
|
||||
case "DealSchedule":
|
||||
|
||||
{
|
||||
|
||||
if err := t.DealSchedule.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealSchedule: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.KeepUnsealed (bool) (bool)
|
||||
case "KeepUnsealed":
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajOther {
|
||||
return fmt.Errorf("booleans must be major type 7")
|
||||
}
|
||||
switch extra {
|
||||
case 20:
|
||||
t.KeepUnsealed = false
|
||||
case 21:
|
||||
t.KeepUnsealed = true
|
||||
default:
|
||||
return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra)
|
||||
}
|
||||
|
||||
default:
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
cbg.ScanForLinks(r, func(cid.Cid) {})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (t *DealSchedule) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{162}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.StartEpoch (abi.ChainEpoch) (int64)
|
||||
if len("StartEpoch") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"StartEpoch\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("StartEpoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("StartEpoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.StartEpoch >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.StartEpoch)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.StartEpoch-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.EndEpoch (abi.ChainEpoch) (int64)
|
||||
if len("EndEpoch") > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field \"EndEpoch\" was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len("EndEpoch"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string("EndEpoch")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.EndEpoch >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.EndEpoch)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.EndEpoch-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DealSchedule) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = DealSchedule{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajMap {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("DealSchedule: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
var name string
|
||||
n := extra
|
||||
|
||||
for i := uint64(0); i < n; i++ {
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name = string(sval)
|
||||
}
|
||||
|
||||
switch name {
|
||||
// t.StartEpoch (abi.ChainEpoch) (int64)
|
||||
case "StartEpoch":
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.StartEpoch = abi.ChainEpoch(extraI)
|
||||
}
|
||||
// t.EndEpoch (abi.ChainEpoch) (int64)
|
||||
case "EndEpoch":
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.EndEpoch = abi.ChainEpoch(extraI)
|
||||
}
|
||||
|
||||
default:
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
cbg.ScanForLinks(r, func(cid.Cid) {})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (t *SectorInfo) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
|
||||
Vendored
+1
-1
@@ -62,7 +62,7 @@ func checkPieces(ctx context.Context, maddr address.Address, si SectorInfo, api
|
||||
}
|
||||
|
||||
if proposal.PieceCID != p.Piece.PieceCID {
|
||||
return &ErrInvalidDeals{xerrors.Errorf("piece %d (of %d) of sector %d refers deal %d with wrong PieceCID: %x != %x", i, len(si.Pieces), si.SectorNumber, p.DealInfo.DealID, p.Piece.PieceCID, proposal.PieceCID)}
|
||||
return &ErrInvalidDeals{xerrors.Errorf("piece %d (of %d) of sector %d refers deal %d with wrong PieceCID: %s != %s", i, len(si.Pieces), si.SectorNumber, p.DealInfo.DealID, p.Piece.PieceCID, proposal.PieceCID)}
|
||||
}
|
||||
|
||||
if p.Piece.Size != proposal.PieceSize {
|
||||
|
||||
+39
-8
@@ -7,10 +7,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -18,13 +14,16 @@ import (
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner"
|
||||
proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
@@ -46,6 +45,7 @@ type CommitBatcherApi interface {
|
||||
StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok TipSetToken) (*miner.SectorPreCommitOnChainInfo, error)
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, TipSetToken) (big.Int, error)
|
||||
StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error)
|
||||
StateMinerAvailableBalance(context.Context, address.Address, TipSetToken) (big.Int, error)
|
||||
}
|
||||
|
||||
type AggregateInput struct {
|
||||
@@ -225,7 +225,7 @@ func (b *CommitBatcher) maybeStartBatch(notif bool) ([]sealiface.CommitBatchRes,
|
||||
}
|
||||
|
||||
if individual {
|
||||
res, err = b.processIndividually()
|
||||
res, err = b.processIndividually(cfg)
|
||||
} else {
|
||||
res, err = b.processBatch(cfg)
|
||||
}
|
||||
@@ -341,6 +341,10 @@ func (b *CommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.CommitBa
|
||||
aggFee := big.Div(big.Mul(policy.AggregateNetworkFee(nv, len(infos), bf), aggFeeNum), aggFeeDen)
|
||||
|
||||
needFunds := big.Add(collateral, aggFee)
|
||||
needFunds, err = collateralSendAmount(b.mctx, b.api, b.maddr, cfg, needFunds)
|
||||
if err != nil {
|
||||
return []sealiface.CommitBatchRes{res}, err
|
||||
}
|
||||
|
||||
goodFunds := big.Add(maxFee, needFunds)
|
||||
|
||||
@@ -361,12 +365,26 @@ func (b *CommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.CommitBa
|
||||
return []sealiface.CommitBatchRes{res}, nil
|
||||
}
|
||||
|
||||
func (b *CommitBatcher) processIndividually() ([]sealiface.CommitBatchRes, error) {
|
||||
func (b *CommitBatcher) processIndividually(cfg sealiface.Config) ([]sealiface.CommitBatchRes, error) {
|
||||
mi, err := b.api.StateMinerInfo(b.mctx, b.maddr, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("couldn't get miner info: %w", err)
|
||||
}
|
||||
|
||||
avail := types.TotalFilecoinInt
|
||||
|
||||
if cfg.CollateralFromMinerBalance && !cfg.DisableCollateralFallback {
|
||||
avail, err = b.api.StateMinerAvailableBalance(b.mctx, b.maddr, nil)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting available miner balance: %w", err)
|
||||
}
|
||||
|
||||
avail = big.Sub(avail, cfg.AvailableBalanceBuffer)
|
||||
if avail.LessThan(big.Zero()) {
|
||||
avail = big.Zero()
|
||||
}
|
||||
}
|
||||
|
||||
tok, _, err := b.api.ChainHead(b.mctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -380,7 +398,7 @@ func (b *CommitBatcher) processIndividually() ([]sealiface.CommitBatchRes, error
|
||||
FailedSectors: map[abi.SectorNumber]string{},
|
||||
}
|
||||
|
||||
mcid, err := b.processSingle(mi, sn, info, tok)
|
||||
mcid, err := b.processSingle(cfg, mi, &avail, sn, info, tok)
|
||||
if err != nil {
|
||||
log.Errorf("process single error: %+v", err) // todo: return to user
|
||||
r.FailedSectors[sn] = err.Error()
|
||||
@@ -394,7 +412,7 @@ func (b *CommitBatcher) processIndividually() ([]sealiface.CommitBatchRes, error
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (b *CommitBatcher) processSingle(mi miner.MinerInfo, sn abi.SectorNumber, info AggregateInput, tok TipSetToken) (cid.Cid, error) {
|
||||
func (b *CommitBatcher) processSingle(cfg sealiface.Config, mi miner.MinerInfo, avail *abi.TokenAmount, sn abi.SectorNumber, info AggregateInput, tok TipSetToken) (cid.Cid, error) {
|
||||
enc := new(bytes.Buffer)
|
||||
params := &miner.ProveCommitSectorParams{
|
||||
SectorNumber: sn,
|
||||
@@ -410,6 +428,19 @@ func (b *CommitBatcher) processSingle(mi miner.MinerInfo, sn abi.SectorNumber, i
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
if cfg.CollateralFromMinerBalance {
|
||||
c := big.Sub(collateral, *avail)
|
||||
*avail = big.Sub(*avail, collateral)
|
||||
collateral = c
|
||||
|
||||
if collateral.LessThan(big.Zero()) {
|
||||
collateral = big.Zero()
|
||||
}
|
||||
if (*avail).LessThan(big.Zero()) {
|
||||
*avail = big.Zero()
|
||||
}
|
||||
}
|
||||
|
||||
goodFunds := big.Add(collateral, big.Int(b.feeCfg.MaxCommitGasFee))
|
||||
|
||||
from, _, err := b.addrSel(b.mctx, mi, api.CommitAddr, goodFunds, collateral)
|
||||
|
||||
Vendored
-2
@@ -12,8 +12,6 @@ import (
|
||||
func main() {
|
||||
err := gen.WriteMapEncodersToFile("./cbor_gen.go", "sealing",
|
||||
sealing.Piece{},
|
||||
sealing.DealInfo{},
|
||||
sealing.DealSchedule{},
|
||||
sealing.SectorInfo{},
|
||||
sealing.Log{},
|
||||
)
|
||||
|
||||
Vendored
+10
-9
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/filecoin-project/go-statemachine"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||
@@ -236,34 +237,34 @@ func (m *Sealing) handleAddPieceFailed(ctx statemachine.Context, sector SectorIn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Sealing) AddPieceToAnySector(ctx context.Context, size abi.UnpaddedPieceSize, data storage.Data, deal DealInfo) (abi.SectorNumber, abi.PaddedPieceSize, error) {
|
||||
func (m *Sealing) SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPieceSize, data storage.Data, deal api.PieceDealInfo) (api.SectorOffset, error) {
|
||||
log.Infof("Adding piece for deal %d (publish msg: %s)", deal.DealID, deal.PublishCid)
|
||||
if (padreader.PaddedSize(uint64(size))) != size {
|
||||
return 0, 0, xerrors.Errorf("cannot allocate unpadded piece")
|
||||
return api.SectorOffset{}, xerrors.Errorf("cannot allocate unpadded piece")
|
||||
}
|
||||
|
||||
sp, err := m.currentSealProof(ctx)
|
||||
if err != nil {
|
||||
return 0, 0, xerrors.Errorf("getting current seal proof type: %w", err)
|
||||
return api.SectorOffset{}, xerrors.Errorf("getting current seal proof type: %w", err)
|
||||
}
|
||||
|
||||
ssize, err := sp.SectorSize()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
return api.SectorOffset{}, err
|
||||
}
|
||||
|
||||
if size > abi.PaddedPieceSize(ssize).Unpadded() {
|
||||
return 0, 0, xerrors.Errorf("piece cannot fit into a sector")
|
||||
return api.SectorOffset{}, xerrors.Errorf("piece cannot fit into a sector")
|
||||
}
|
||||
|
||||
if _, err := deal.DealProposal.Cid(); err != nil {
|
||||
return 0, 0, xerrors.Errorf("getting proposal CID: %w", err)
|
||||
return api.SectorOffset{}, xerrors.Errorf("getting proposal CID: %w", err)
|
||||
}
|
||||
|
||||
m.inputLk.Lock()
|
||||
if _, exist := m.pendingPieces[proposalCID(deal)]; exist {
|
||||
m.inputLk.Unlock()
|
||||
return 0, 0, xerrors.Errorf("piece for deal %s already pending", proposalCID(deal))
|
||||
return api.SectorOffset{}, xerrors.Errorf("piece for deal %s already pending", proposalCID(deal))
|
||||
}
|
||||
|
||||
resCh := make(chan struct {
|
||||
@@ -295,7 +296,7 @@ func (m *Sealing) AddPieceToAnySector(ctx context.Context, size abi.UnpaddedPiec
|
||||
|
||||
res := <-resCh
|
||||
|
||||
return res.sn, res.offset.Padded(), res.err
|
||||
return api.SectorOffset{Sector: res.sn, Offset: res.offset.Padded()}, res.err
|
||||
}
|
||||
|
||||
// called with m.inputLk
|
||||
@@ -454,7 +455,7 @@ func (m *Sealing) StartPacking(sid abi.SectorNumber) error {
|
||||
return m.sectors.Send(uint64(sid), SectorStartPacking{})
|
||||
}
|
||||
|
||||
func proposalCID(deal DealInfo) cid.Cid {
|
||||
func proposalCID(deal api.PieceDealInfo) cid.Cid {
|
||||
pc, err := deal.DealProposal.Cid()
|
||||
if err != nil {
|
||||
log.Errorf("DealProposal.Cid error: %+v", err)
|
||||
|
||||
@@ -88,6 +88,21 @@ func (mr *MockCommitBatcherApiMockRecorder) SendMsg(arg0, arg1, arg2, arg3, arg4
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockCommitBatcherApi)(nil).SendMsg), arg0, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
}
|
||||
|
||||
// StateMinerAvailableBalance mocks base method.
|
||||
func (m *MockCommitBatcherApi) StateMinerAvailableBalance(arg0 context.Context, arg1 address.Address, arg2 sealing.TipSetToken) (big.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StateMinerAvailableBalance", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(big.Int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// StateMinerAvailableBalance indicates an expected call of StateMinerAvailableBalance.
|
||||
func (mr *MockCommitBatcherApiMockRecorder) StateMinerAvailableBalance(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateMinerAvailableBalance", reflect.TypeOf((*MockCommitBatcherApi)(nil).StateMinerAvailableBalance), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// StateMinerInfo mocks base method.
|
||||
func (m *MockCommitBatcherApi) StateMinerInfo(arg0 context.Context, arg1 address.Address, arg2 sealing.TipSetToken) (miner.MinerInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -71,6 +71,21 @@ func (mr *MockPreCommitBatcherApiMockRecorder) SendMsg(arg0, arg1, arg2, arg3, a
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockPreCommitBatcherApi)(nil).SendMsg), arg0, arg1, arg2, arg3, arg4, arg5, arg6)
|
||||
}
|
||||
|
||||
// StateMinerAvailableBalance mocks base method.
|
||||
func (m *MockPreCommitBatcherApi) StateMinerAvailableBalance(arg0 context.Context, arg1 address.Address, arg2 sealing.TipSetToken) (big.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StateMinerAvailableBalance", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(big.Int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// StateMinerAvailableBalance indicates an expected call of StateMinerAvailableBalance.
|
||||
func (mr *MockPreCommitBatcherApiMockRecorder) StateMinerAvailableBalance(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateMinerAvailableBalance", reflect.TypeOf((*MockPreCommitBatcherApi)(nil).StateMinerAvailableBalance), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// StateMinerInfo mocks base method.
|
||||
func (m *MockPreCommitBatcherApi) StateMinerInfo(arg0 context.Context, arg1 address.Address, arg2 sealing.TipSetToken) (miner.MinerInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
+8
-3
@@ -7,9 +7,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@@ -20,7 +17,9 @@ import (
|
||||
miner5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/extern/storage-sealing/sealiface"
|
||||
"github.com/filecoin-project/lotus/node/config"
|
||||
)
|
||||
@@ -30,6 +29,7 @@ import (
|
||||
type PreCommitBatcherApi interface {
|
||||
SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, maxFee abi.TokenAmount, params []byte) (cid.Cid, error)
|
||||
StateMinerInfo(context.Context, address.Address, TipSetToken) (miner.MinerInfo, error)
|
||||
StateMinerAvailableBalance(context.Context, address.Address, TipSetToken) (big.Int, error)
|
||||
ChainHead(ctx context.Context) (TipSetToken, abi.ChainEpoch, error)
|
||||
}
|
||||
|
||||
@@ -226,6 +226,11 @@ func (b *PreCommitBatcher) processBatch(cfg sealiface.Config) ([]sealiface.PreCo
|
||||
deposit = big.Add(deposit, p.deposit)
|
||||
}
|
||||
|
||||
deposit, err := collateralSendAmount(b.mctx, b.api, b.maddr, cfg, deposit)
|
||||
if err != nil {
|
||||
return []sealiface.PreCommitBatchRes{res}, err
|
||||
}
|
||||
|
||||
enc := new(bytes.Buffer)
|
||||
if err := params.MarshalCBOR(enc); err != nil {
|
||||
return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("couldn't serialize PreCommitSectorBatchParams: %w", err)
|
||||
|
||||
+9
-8
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
api "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -58,9 +59,9 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) {
|
||||
Size: abi.PaddedPieceSize(1024),
|
||||
PieceCID: fakePieceCid(t),
|
||||
},
|
||||
DealInfo: &sealing.DealInfo{
|
||||
DealInfo: &api.PieceDealInfo{
|
||||
DealID: abi.DealID(42),
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
DealSchedule: api.DealSchedule{
|
||||
StartEpoch: abi.ChainEpoch(70),
|
||||
EndEpoch: abi.ChainEpoch(75),
|
||||
},
|
||||
@@ -71,9 +72,9 @@ func TestBasicPolicyMostConstrictiveSchedule(t *testing.T) {
|
||||
Size: abi.PaddedPieceSize(1024),
|
||||
PieceCID: fakePieceCid(t),
|
||||
},
|
||||
DealInfo: &sealing.DealInfo{
|
||||
DealInfo: &api.PieceDealInfo{
|
||||
DealID: abi.DealID(43),
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
DealSchedule: api.DealSchedule{
|
||||
StartEpoch: abi.ChainEpoch(80),
|
||||
EndEpoch: abi.ChainEpoch(100),
|
||||
},
|
||||
@@ -98,9 +99,9 @@ func TestBasicPolicyIgnoresExistingScheduleIfExpired(t *testing.T) {
|
||||
Size: abi.PaddedPieceSize(1024),
|
||||
PieceCID: fakePieceCid(t),
|
||||
},
|
||||
DealInfo: &sealing.DealInfo{
|
||||
DealInfo: &api.PieceDealInfo{
|
||||
DealID: abi.DealID(44),
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
DealSchedule: api.DealSchedule{
|
||||
StartEpoch: abi.ChainEpoch(1),
|
||||
EndEpoch: abi.ChainEpoch(10),
|
||||
},
|
||||
@@ -125,9 +126,9 @@ func TestMissingDealIsIgnored(t *testing.T) {
|
||||
Size: abi.PaddedPieceSize(1024),
|
||||
PieceCID: fakePieceCid(t),
|
||||
},
|
||||
DealInfo: &sealing.DealInfo{
|
||||
DealInfo: &api.PieceDealInfo{
|
||||
DealID: abi.DealID(44),
|
||||
DealSchedule: sealing.DealSchedule{
|
||||
DealSchedule: api.DealSchedule{
|
||||
StartEpoch: abi.ChainEpoch(1),
|
||||
EndEpoch: abi.ChainEpoch(10),
|
||||
},
|
||||
|
||||
+4
@@ -24,6 +24,10 @@ type Config struct {
|
||||
|
||||
FinalizeEarly bool
|
||||
|
||||
CollateralFromMinerBalance bool
|
||||
AvailableBalanceBuffer abi.TokenAmount
|
||||
DisableCollateralFallback bool
|
||||
|
||||
BatchPreCommits bool
|
||||
MaxPreCommitBatch int
|
||||
PreCommitBatchWait time.Duration
|
||||
|
||||
Vendored
+2
-1
@@ -59,6 +59,7 @@ type SealingAPI interface {
|
||||
StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, TipSetToken) (big.Int, error)
|
||||
StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, TipSetToken) (big.Int, error)
|
||||
StateMinerInfo(context.Context, address.Address, TipSetToken) (miner.MinerInfo, error)
|
||||
StateMinerAvailableBalance(context.Context, address.Address, TipSetToken) (big.Int, error)
|
||||
StateMinerSectorAllocated(context.Context, address.Address, abi.SectorNumber, TipSetToken) (bool, error)
|
||||
StateMarketStorageDeal(context.Context, abi.DealID, TipSetToken) (*api.MarketDeal, error)
|
||||
StateMarketStorageDealProposal(context.Context, abi.DealID, TipSetToken) (market.DealProposal, error)
|
||||
@@ -124,7 +125,7 @@ type openSector struct {
|
||||
|
||||
type pendingPiece struct {
|
||||
size abi.UnpaddedPieceSize
|
||||
deal DealInfo
|
||||
deal api.PieceDealInfo
|
||||
|
||||
data storage.Data
|
||||
|
||||
|
||||
+2
-2
@@ -142,7 +142,7 @@ func (m *Sealing) handlePreCommitFailed(ctx statemachine.Context, sector SectorI
|
||||
}
|
||||
|
||||
if pci.Info.SealedCID != *sector.CommR {
|
||||
log.Warnf("sector %d is precommitted on chain, with different CommR: %x != %x", sector.SectorNumber, pci.Info.SealedCID, sector.CommR)
|
||||
log.Warnf("sector %d is precommitted on chain, with different CommR: %s != %s", sector.SectorNumber, pci.Info.SealedCID, sector.CommR)
|
||||
return nil // TODO: remove when the actor allows re-precommit
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func (m *Sealing) handleRecoverDealIDs(ctx statemachine.Context, sector SectorIn
|
||||
}
|
||||
|
||||
if proposal.PieceCID != p.Piece.PieceCID {
|
||||
log.Warnf("piece %d (of %d) of sector %d refers deal %d with wrong PieceCID: %x != %x", i, len(sector.Pieces), sector.SectorNumber, p.DealInfo.DealID, p.Piece.PieceCID, proposal.PieceCID)
|
||||
log.Warnf("piece %d (of %d) of sector %d refers deal %d with wrong PieceCID: %s != %s", i, len(sector.Pieces), sector.SectorNumber, p.DealInfo.DealID, p.Piece.PieceCID, proposal.PieceCID)
|
||||
toFix = append(toFix, i)
|
||||
continue
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user