Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
785a54692b | ||
|
|
41b8b6d416 | ||
|
|
aef4cc829b | ||
|
|
f7b90cb5c1 | ||
|
|
db34b828e4 | ||
|
|
0853b99fca | ||
|
|
a6ddd167c6 | ||
|
|
570edcbbb9 | ||
|
|
074eac16cc | ||
|
|
c298d8ca3e | ||
|
|
b4719c9daf | ||
|
|
f44ba40450 | ||
|
|
8385f1d2a1 | ||
|
|
37c9c397d3 | ||
|
|
c3e12a69cc | ||
|
|
371e90a40a | ||
|
|
80624845c4 | ||
|
|
151cd76f75 | ||
|
|
1858c0e290 | ||
|
|
a7ab55dc00 | ||
|
|
68269b23fb | ||
|
|
b096887b16 | ||
|
|
b3e73e4dad | ||
|
|
6c3acb8e21 | ||
|
|
36cb7d9451 | ||
|
|
de1c041900 | ||
|
|
b7cda68c1c | ||
|
|
abb0ea01a7 | ||
|
|
57337c1ae0 | ||
|
|
c7aac60c6f | ||
|
|
b026c70f79 | ||
|
|
1ac87279d7 | ||
|
|
3506b9e8f2 | ||
|
|
4510fa7dcb | ||
|
|
c05eb1251b | ||
|
|
e74c374783 | ||
|
|
12875a9664 | ||
|
|
ece154d73b | ||
|
|
69204eea04 | ||
|
|
5579001366 | ||
|
|
862a2ce695 | ||
|
|
94f7205943 | ||
|
|
5bdc1862d9 | ||
|
|
62769e3b11 | ||
|
|
fcc3103123 | ||
|
|
0beb48f11d | ||
|
|
28bf9688f1 | ||
|
|
da86f445c8 | ||
|
|
2d1494314e | ||
|
|
8c586d7f7c | ||
|
|
5ca128e8bb | ||
|
|
c143fa922e | ||
|
|
192fb159d2 | ||
|
|
47d9a69802 | ||
|
|
3350bd422f | ||
|
|
d494778435 | ||
|
|
88f5bcdb63 | ||
|
|
f0143e351d | ||
|
|
113ea6dc4b | ||
|
|
1e6cc6f836 | ||
|
|
e467b130c2 | ||
|
|
7ff5844aa2 | ||
|
|
518b6f1d41 | ||
|
|
d7076778e2 | ||
|
|
473a192b85 | ||
|
|
15d90c24ed | ||
|
|
52746911d8 | ||
|
|
ea242b5bad | ||
|
|
c37241c733 | ||
|
|
263ae6f99f | ||
|
|
11ff756b2e | ||
|
|
10615b53ad | ||
|
|
2e5b492edd | ||
|
|
0d7654d2c9 | ||
|
|
92402e9f23 | ||
|
|
adcb8f3b15 | ||
|
|
56c35ff1e9 | ||
|
|
e397a079c1 | ||
|
|
4bcf159381 | ||
|
|
b50b1e9ac4 | ||
|
|
c5f81d35f5 | ||
|
|
6812c293b1 | ||
|
|
34dc70ca2a | ||
|
|
81a5521845 | ||
|
|
f7cfb74a3f | ||
|
|
f34631facc | ||
|
|
35c8c5885b | ||
|
|
8c9321ce7b | ||
|
|
2e2b9009fc | ||
|
|
eaff65c00f | ||
|
|
931cf9342e | ||
|
|
e23c3b3e77 | ||
|
|
230f81661c | ||
|
|
d95fcd55bf | ||
|
|
3983dadf3a | ||
|
|
f312ba376c | ||
|
|
13e9d7c71c | ||
|
|
8c326d7bad | ||
|
|
04b358f340 | ||
|
|
23cd561f2e | ||
|
|
3733fa9cc2 | ||
|
|
a94ab050bf | ||
|
|
1527ed46bc | ||
|
|
43d48f37b6 | ||
|
|
2c9edb1d1a | ||
|
|
a1aed960a9 | ||
|
|
22461f30e9 | ||
|
|
7b1a82a3cc | ||
|
|
0d06527507 | ||
|
|
2b5bcfdb7f | ||
|
|
9133f819e0 | ||
|
|
73c161a295 | ||
|
|
b46b26f1ae | ||
|
|
18eadd338e | ||
|
|
21b1059ba5 | ||
|
|
c25ed49f0d | ||
|
|
2ecf8914a1 | ||
|
|
f9ea2e834c | ||
|
|
85a4f8325f | ||
|
|
60b612247d | ||
|
|
d92c6a2097 | ||
|
|
45166e760b | ||
|
|
e90e71456b | ||
|
|
ce58b119bf | ||
|
|
2d8c9bba99 | ||
|
|
c8720fef02 | ||
|
|
73a644f320 | ||
|
|
3960f719db | ||
|
|
2484fbc1f7 | ||
|
|
5f6166435c | ||
|
|
af9a71ac7c | ||
|
|
ee44312c00 | ||
|
|
4214ab12ef | ||
|
|
3bb5d4eb8f | ||
|
|
dcff06bd91 | ||
|
|
3235dbfaee | ||
|
|
9911ab1000 | ||
|
|
4bf8cb455b | ||
|
|
cbb7c191e6 | ||
|
|
b2714e19d5 | ||
|
|
498644acab | ||
|
|
e8a6ea1dc8 | ||
|
|
07c636bf86 | ||
|
|
a52352b13a | ||
|
|
14dcc477f1 | ||
|
|
bfda864c1b | ||
|
|
bf41240ee1 | ||
|
|
b914e95f34 | ||
|
|
d6562bccfc | ||
|
|
46a93bb78a | ||
|
|
130fc6fce1 | ||
|
|
65e3540d03 | ||
|
|
feb9d3c557 | ||
|
|
234030218c | ||
|
|
6da26dcefc | ||
|
|
c24d4e11d5 | ||
|
|
eb0a62e9e9 | ||
|
|
742c85bf81 | ||
|
|
79f348a01c | ||
|
|
a9403b42f0 | ||
|
|
1a59b73adc | ||
|
|
26a5832f92 | ||
|
|
380e16d465 | ||
|
|
b83b5405c6 | ||
|
|
57c984cea1 | ||
|
|
563fa1e31a | ||
|
|
cb3c53664d | ||
|
|
3c994d94aa | ||
|
|
32d94d4e85 | ||
|
|
49346f5679 | ||
|
|
1323d8fb20 | ||
|
|
6f22cffb6b | ||
|
|
e1e5af8661 | ||
|
|
18f39be3ba | ||
|
|
bfd69f5381 | ||
|
|
5e27023ba7 | ||
|
|
5a321f970e | ||
|
|
f7e288589b | ||
|
|
66bfadd7f0 | ||
|
|
cfc10e9b52 | ||
|
|
be2ecf6236 | ||
|
|
57bf5c2143 | ||
|
|
9dca65634d | ||
|
|
faf8a47684 | ||
|
|
c9124bd1a9 | ||
|
|
db6b7b91d8 | ||
|
|
eefdcb0454 | ||
|
|
94c5076710 | ||
|
|
66e8418125 | ||
|
|
677afbcb91 | ||
|
|
7f6c942b81 | ||
|
|
e09cdc45a7 | ||
|
|
9ee80fd1db | ||
|
|
77166f88ac | ||
|
|
e0777fed15 | ||
|
|
075bb3b314 | ||
|
|
a768dd84fa | ||
|
|
4a1655b225 | ||
|
|
40449f1ccb | ||
|
|
020cc5e64f | ||
|
|
52b76c9d5c | ||
|
|
5939623f26 | ||
|
|
9e707e18e1 | ||
|
|
783fa6b7c0 | ||
|
|
fa7e52dbda | ||
|
|
1ce5c3bf9c | ||
|
|
8d51c5a971 | ||
|
|
d06f38757d | ||
|
|
b885d69aaa | ||
|
|
8426a62d15 | ||
|
|
555c402ba3 | ||
|
|
0c809d3a5f | ||
|
|
ca697c9aa2 | ||
|
|
73b2b5f384 | ||
|
|
0340189baa | ||
|
|
823bd54484 | ||
|
|
756e5ac0b8 | ||
|
|
7c99169fb4 | ||
|
|
2380d252e1 | ||
|
|
f2f6c209ea | ||
|
|
ff734ed080 | ||
|
|
c4ca3660de | ||
|
|
b584f44661 | ||
|
|
f63d1b114a | ||
|
|
e5fb4a6c04 | ||
|
|
1d50dadc18 | ||
|
|
1f7d584517 | ||
|
|
08e046066d | ||
|
|
c17a0c4fed | ||
|
|
28e3c8bd3f | ||
|
|
00fb675452 | ||
|
|
83a4d7dc1c | ||
|
|
8433aae1af | ||
|
|
9549087ba9 | ||
|
|
b17fcfc4d1 | ||
|
|
3144da86f3 | ||
|
|
90427bc3af | ||
|
|
8fae68a5ae | ||
|
|
3b2c3a3f6b | ||
|
|
d9c6a32b8e | ||
|
|
00e32d1ede | ||
|
|
7d6eb250ea | ||
|
|
22c0884f5f | ||
|
|
e00cb29804 | ||
|
|
973476930e | ||
|
|
4e19d8d562 | ||
|
|
595695a459 | ||
|
|
7f41d30ce8 | ||
|
|
18652bc388 | ||
|
|
4f2722e7cf | ||
|
|
57d87ef24b | ||
|
|
4273fb067c | ||
|
|
ef6620ad8e | ||
|
|
ee20d30480 | ||
|
|
2fd12daf9f | ||
|
|
351f615ce6 | ||
|
|
5e8b2c7860 | ||
|
|
8be8f043bd | ||
|
|
8d6bff36f2 | ||
|
|
ee59479e25 | ||
|
|
11394aa4aa | ||
|
|
8ccee51887 | ||
|
|
5c823e9b42 | ||
|
|
ca76822fde | ||
|
|
fe74311209 | ||
|
|
742321dd08 | ||
|
|
69f0bdd486 | ||
|
|
6ffcf611a6 | ||
|
|
256d12773b | ||
|
|
5be5f255d1 | ||
|
|
b812d3ec26 | ||
|
|
640407aae7 | ||
|
|
d3742048f9 | ||
|
|
a61ba7b09c | ||
|
|
b1fb707a3a | ||
|
|
e09a25ca68 | ||
|
|
a968784908 | ||
|
|
0202192fc0 | ||
|
|
dbe4891a39 | ||
|
|
5a3b4ab34c | ||
|
|
acf6b07794 | ||
|
|
b397955f24 | ||
|
|
4a90c0f13b | ||
|
|
21244704fc | ||
|
|
80aedcd276 | ||
|
|
07f40b9488 | ||
|
|
a1a23d8be5 | ||
|
|
ef94509eac | ||
|
|
3b617f4528 | ||
|
|
25052fe48f | ||
|
|
389f71251c | ||
|
|
5867e34ec9 | ||
|
|
f8afb699cd | ||
|
|
6969202a03 | ||
|
|
54c6a3a454 | ||
|
|
b75ff37448 | ||
|
|
4cf5c8f656 | ||
|
|
c65d72fbca | ||
|
|
fff1c0ae57 | ||
|
|
de4a847078 | ||
|
|
66e793531d | ||
|
|
297c9e2f7a | ||
|
|
0740274b7c | ||
|
|
950ded454d | ||
|
|
9d0cc2c9d7 | ||
|
|
0bc7456b7f | ||
|
|
b8bb673b75 | ||
|
|
2e7ba05173 | ||
|
|
f9595b58ee | ||
|
|
e49c77e29c | ||
|
|
01c786c141 | ||
|
|
c0b07286aa | ||
|
|
9afb63d2e4 | ||
|
|
c31e5596e8 | ||
|
|
29b2d27f00 | ||
|
|
d45b4a7a1f | ||
|
|
dfac7c5f29 | ||
|
|
e163d556fb | ||
|
|
c57c20c6e4 | ||
|
|
05a3710288 | ||
|
|
ae63a4b33b | ||
|
|
ce82f2827b | ||
|
|
e7d73cbe56 | ||
|
|
9bd312881d | ||
|
|
ca1cd741c3 | ||
|
|
50b217817e | ||
|
|
6ba42e3e6b | ||
|
|
ac8937245c | ||
|
|
e68c59f984 | ||
|
|
64d2b7a122 | ||
|
|
41bce7925a | ||
|
|
3829d6bd9a | ||
|
|
123a976f62 | ||
|
|
7ee46ad4e0 | ||
|
|
adb62a3fff | ||
|
|
9e34cce1f2 |
+57
-19
@@ -1,19 +1,57 @@
|
||||
comment: off
|
||||
ignore:
|
||||
- "**/cbor_gen.go"
|
||||
- "api/test/**/*"
|
||||
- "api/test/*"
|
||||
- "gen/**/*"
|
||||
- "gen/*"
|
||||
- "cmd/lotus-shed/*"
|
||||
- "cmd/tvx/*"
|
||||
- "cmd/lotus-pcr/*"
|
||||
- "cmd/tvx/*"
|
||||
- "cmd/lotus-chainwatch/*"
|
||||
- "cmd/lotus-health/*"
|
||||
- "cmd/lotus-fountain/*"
|
||||
- "cmd/lotus-townhall/*"
|
||||
- "cmd/lotus-stats/*"
|
||||
- "cmd/lotus-pcr/*"
|
||||
github_checks:
|
||||
annotations: false
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
tools-and-tests:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: true
|
||||
paths:
|
||||
- "testplans"
|
||||
- "tools"
|
||||
- "system"
|
||||
- "snap"
|
||||
- "lotuspond"
|
||||
- "conformance"
|
||||
- "scripts"
|
||||
- "gen"
|
||||
- "build"
|
||||
markets:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: false
|
||||
paths:
|
||||
- "markets"
|
||||
- "paychmgr"
|
||||
miner:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: false
|
||||
paths:
|
||||
- "miner"
|
||||
- "storage"
|
||||
chain:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: false
|
||||
paths:
|
||||
- "chain"
|
||||
node:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: false
|
||||
paths:
|
||||
- "node"
|
||||
- "blockstore"
|
||||
- "metrics"
|
||||
- "lib"
|
||||
- "genesis"
|
||||
- "gateway"
|
||||
- "api"
|
||||
- "journal"
|
||||
cli:
|
||||
target: auto
|
||||
threshold: 0.5%
|
||||
informational: true
|
||||
paths:
|
||||
- "cli"
|
||||
- "cmd"
|
||||
@@ -21,35 +21,45 @@ body:
|
||||
required: true
|
||||
- label: I did not make any code changes to lotus.
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: component-and-area
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Lotus component
|
||||
description: Please select the lotus component you are filing a bug for
|
||||
options:
|
||||
- lotus daemon - chain sync
|
||||
- lotus miner - mining and block production
|
||||
- lotus miner/worker - sealing
|
||||
- lotus miner - proving(WindowPoSt)
|
||||
- lotus miner/market - storage deal
|
||||
- lotus miner/market - retrieval deal
|
||||
- lotus client
|
||||
- lotus JSON-RPC API
|
||||
- lotus message management (mpool)
|
||||
- Other
|
||||
- label: lotus daemon - chain sync
|
||||
required: false
|
||||
- label: lotus miner - mining and block production
|
||||
required: false
|
||||
- label: lotus miner/worker - sealing
|
||||
required: false
|
||||
- label: lotus miner - proving(WindowPoSt)
|
||||
required: false
|
||||
- label: lotus miner/market - storage deal
|
||||
required: false
|
||||
- label: lotus miner/market - retrieval deal
|
||||
required: false
|
||||
- label: lotus miner/market - data transfer
|
||||
required: false
|
||||
- label: lotus client
|
||||
required: false
|
||||
- label: lotus JSON-RPC API
|
||||
required: false
|
||||
- label: lotus message management (mpool)
|
||||
required: false
|
||||
- label: Other
|
||||
required: false
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Lotus Version
|
||||
render: text
|
||||
description: Enter the output of `lotus version` and `lotus-miner version` if applicable.
|
||||
placeholder: |
|
||||
e.g.
|
||||
Daemon:1.11.0-rc2+debug+git.0519cd371.dirty+api1.3.0
|
||||
Local: lotus version 1.11.0-rc2+debug+git.0519cd371.dirty
|
||||
validations:
|
||||
reuiqred: true
|
||||
required: true
|
||||
- type: textarea
|
||||
id: Description
|
||||
attributes:
|
||||
@@ -62,19 +72,18 @@ body:
|
||||
* For sealing issues, include the output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
* For proving issues, include the output of `lotus-miner proving` info.
|
||||
* For deal making issues, include the output of `lotus client list-deals -v` and/or `lotus-miner storage-deals|retrieval-deals|data-transfers list [-v]` commands for the deal(s) in question.
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extraInfo
|
||||
attributes:
|
||||
label: Logging Information
|
||||
render: text
|
||||
description: |
|
||||
Please provide debug logs of the problem, remember you can get set log level control for:
|
||||
* lotus: use `lotus log list` to get all log systems available and set level by `lotus log set-level`. An example can be found [here](https://docs.filecoin.io/get-started/lotus/configuration-and-advanced-usage/#log-level-control).
|
||||
* lotus-miner:`lotus-miner log list` to get all log systems available and set level by `lotus-miner log set-level
|
||||
If you don't provide detailed logs when you raise the issue it will almost certainly be the first request I make before furthur diagnosing the problem.
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
@@ -87,6 +96,5 @@ body:
|
||||
2. Do '...'
|
||||
3. See error '...'
|
||||
...
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
required: false
|
||||
|
||||
@@ -15,24 +15,33 @@ body:
|
||||
required: true
|
||||
- label: I **have** a specific, actionable, and well motivated improvement to propose.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: component
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Lotus component
|
||||
description: Please select the lotus component you are propoing improvement for
|
||||
description: Please select the lotus component you are filing an improvement request for
|
||||
options:
|
||||
- lotus daemon - chain sync
|
||||
- lotus miner - mining and block production
|
||||
- lotus miner/worker - sealing
|
||||
- lotus miner - proving(WindowPoSt)
|
||||
- lotus miner/market - storage deal
|
||||
- lotus miner/market - retrieval deal
|
||||
- lotus client
|
||||
- lotus JSON-RPC API
|
||||
- lotus message management (mpool)
|
||||
- Other
|
||||
- label: lotus daemon - chain sync
|
||||
required: false
|
||||
- label: lotus miner - mining and block production
|
||||
required: false
|
||||
- label: lotus miner/worker - sealing
|
||||
required: false
|
||||
- label: lotus miner - proving(WindowPoSt)
|
||||
required: false
|
||||
- label: lotus miner/market - storage deal
|
||||
required: false
|
||||
- label: lotus miner/market - retrieval deal
|
||||
required: false
|
||||
- label: lotus miner/market - data transfer
|
||||
required: false
|
||||
- label: lotus client
|
||||
required: false
|
||||
- label: lotus JSON-RPC API
|
||||
required: false
|
||||
- label: lotus message management (mpool)
|
||||
required: false
|
||||
- label: Other
|
||||
required: false
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
|
||||
@@ -13,24 +13,33 @@ body:
|
||||
required: true
|
||||
- label: I **have** a specific, actionable, and well motivated feature request to propose.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: component
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Lotus component
|
||||
description: Please select the lotus component you are requesting a new feature for
|
||||
description: Please select the lotus component you are filing a new feature request for
|
||||
options:
|
||||
- lotus daemon - chain sync
|
||||
- lotus miner - mining and block production
|
||||
- lotus miner/worker - sealing
|
||||
- lotus miner - proving(WindowPoSt)
|
||||
- lotus miner/market - storage deal
|
||||
- lotus miner/market - retrieval deal
|
||||
- lotus client
|
||||
- lotus JSON-RPC API
|
||||
- lotus message management (mpool)
|
||||
- Other
|
||||
- label: lotus daemon - chain sync
|
||||
required: false
|
||||
- label: lotus miner - mining and block production
|
||||
required: false
|
||||
- label: lotus miner/worker - sealing
|
||||
required: false
|
||||
- label: lotus miner - proving(WindowPoSt)
|
||||
required: false
|
||||
- label: lotus miner/market - storage deal
|
||||
required: false
|
||||
- label: lotus miner/market - retrieval deal
|
||||
required: false
|
||||
- label: lotus miner/market - data transfer
|
||||
required: false
|
||||
- label: lotus client
|
||||
required: false
|
||||
- label: lotus JSON-RPC API
|
||||
required: false
|
||||
- label: lotus message management (mpool)
|
||||
required: false
|
||||
- label: Other
|
||||
required: false
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
name: "M1 Bug Report For Deal Making"
|
||||
description: "File a bug report around deal making for the M1 releases"
|
||||
labels: [need/triage, kind/bug, M1-release]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please check off the following boxes before continuing to file a bug report!
|
||||
options:
|
||||
- label: This is **not** a question or a support request. If you have any lotus related questions, please ask in the [lotus forum](https://github.com/filecoin-project/lotus/discussions).
|
||||
required: true
|
||||
- label: I **am** reporting a bug w.r.t one of the [M1 tags](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043951). If not, choose another issue option [here](https://github.com/filecoin-project/lotus/issues/new/choose).
|
||||
required: true
|
||||
- label: I **am** reporting a bug around deal making. If not, create a [M1 Bug Report For Non Deal Making Issue](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Fbug%2CM1-release&template=m1_bug_report_non_deal.yml).
|
||||
required: true
|
||||
- label: I have my log level set as instructed [here](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043678) and have logs available for troubleshooting.
|
||||
required: true
|
||||
- label: The deal is coming from one of the M1 clients(communitcated in the coordination slack channel).
|
||||
required: true
|
||||
- label: I **have** searched on the [issue tracker](https://github.com/filecoin-project/lotus/issues) and the [lotus forum](https://github.com/filecoin-project/lotus/discussions), and there is no existing related issue or discussion.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: lotus-componets
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Lotus Component
|
||||
description: Please select the lotus component you are filing a bug for
|
||||
options:
|
||||
- lotus miner market subsystem - storage deal
|
||||
- lotus miner market subsystem - retrieval deal
|
||||
- lotus miner - storage deal
|
||||
- lotus miner - retrieval deal
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Lotus Tag and Version
|
||||
description: Enter the lotus tag, output of `lotus version` and `lotus-miner version`.
|
||||
validations:
|
||||
reuiqred: true
|
||||
- type: textarea
|
||||
id: Description
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
description: |
|
||||
This is where you get to tell us what went wrong, when doing so, please try to provide a clear and concise description of the bug with all related information:
|
||||
* What you were doding when you experienced the bug?
|
||||
* Any *error* messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
|
||||
* What is the expected behaviour?
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: deal-status
|
||||
attributes:
|
||||
label: Deal Status
|
||||
description: What's the status of the deal?
|
||||
placeholder: |
|
||||
Please share the output of `lotus-miner storage-deals|retrieval-deals list [-v]` commands for the deal(s) in question.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: data-transfer-status
|
||||
attributes:
|
||||
label: Data Transfer Status
|
||||
description: What's the status of the data transfer?
|
||||
placeholder: |
|
||||
Please share the output of `lotus-miner data-transfers list -v` commands for the deal(s) in question.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logging
|
||||
attributes:
|
||||
label: Logging Information
|
||||
description: Please link to the whole of the miner logs on your side of the transaction. You can upload the logs to a [gist](https://gist.github.com).
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: RepoSteps
|
||||
attributes:
|
||||
label: Repo Steps (optional)
|
||||
description: "Steps to reproduce the behavior"
|
||||
value: |
|
||||
1. Run '...'
|
||||
2. Do '...'
|
||||
3. See error '...'
|
||||
...
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
@@ -1,81 +0,0 @@
|
||||
name: "M1 Bug Report For Non Deal Making Issue"
|
||||
description: "File a bug report around non deal making issue for the M1 releases"
|
||||
labels: [need/triage, kind/bug, M1-release]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please check off the following boxes before continuing to file a bug report!
|
||||
options:
|
||||
- label: This is **not** a question or a support request. If you have any lotus related questions, please ask in the [lotus forum](https://github.com/filecoin-project/lotus/discussions).
|
||||
required: true
|
||||
- label: I **am** reporting a bug w.r.t one of the [M1 tags](https://github.com/filecoin-project/lotus/discussions/6852#discussioncomment-1043951). If not, choose another issue option [here](https://github.com/filecoin-project/lotus/issues/new/choose).
|
||||
required: true
|
||||
- label: I am **not** reporting a bug around deal making. If yes, create a [M1 Bug Report For Deal Making](https://github.com/filecoin-project/lotus/issues/new?assignees=&labels=need%2Ftriage%2Ckind%2Fbug%2CM1-release&template=m1_bug_report_deal.yml).
|
||||
required: true
|
||||
- label: I **have** searched on the [issue tracker](https://github.com/filecoin-project/lotus/issues) and the [lotus forum](https://github.com/filecoin-project/lotus/discussions), and there is no existing related issue or discussion.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: component-and-area
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Lotus component
|
||||
description: Please select the lotus component you are filing a bug for
|
||||
options:
|
||||
- lotus daemon - chain sync **with** splitstore enabled
|
||||
- lotus daemon - chain sync **without** splitstore enabled
|
||||
- lotus miner - mining and block production
|
||||
- lotus miner/worker - sealing
|
||||
- lotus miner - proving(WindowPoSt)
|
||||
- lotus client
|
||||
- lotus JSON-RPC API
|
||||
- lotus message management (mpool)
|
||||
- Other
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Lotus Tag and Version
|
||||
description: Enter the lotus tag, output of `lotus version` and `lotus-miner version`.
|
||||
validations:
|
||||
reuiqred: true
|
||||
- type: textarea
|
||||
id: Description
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
description: |
|
||||
This is where you get to tell us what went wrong, when doing so, please try to provide a clear and concise description of the bug with all related information:
|
||||
* What you were doding when you experienced the bug?
|
||||
* Any *error* messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
|
||||
* What is the expected behaviour?
|
||||
* For sealing issues, include the output of `lotus-miner sectors status --log <sectorId>` for the failed sector(s).
|
||||
* For proving issues, include the output of `lotus-miner proving` info.
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extraInfo
|
||||
attributes:
|
||||
label: Logging Information
|
||||
description: |
|
||||
Please provide debug logs of the problem, remember you can get set log level control for:
|
||||
* lotus: use `lotus log list` to get all log systems available and set level by `lotus log set-level`. An example can be found [here](https://docs.filecoin.io/get-started/lotus/configuration-and-advanced-usage/#log-level-control).
|
||||
* lotus-miner:`lotus-miner log list` to get all log systems available and set level by `lotus-miner log set-level
|
||||
If you don't provide detailed logs when you raise the issue it will almost certainly be the first request I make before furthur diagnosing the problem.
|
||||
render: bash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: RepoSteps
|
||||
attributes:
|
||||
label: Repo Steps
|
||||
description: "Steps to reproduce the behavior"
|
||||
value: |
|
||||
1. Run '...'
|
||||
2. Do '...'
|
||||
3. See error '...'
|
||||
...
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
@@ -29,5 +29,5 @@ jobs:
|
||||
days-before-pr-close: 2
|
||||
remove-stale-when-updated: true
|
||||
enable-statistics: true
|
||||
|
||||
|
||||
|
||||
|
||||
+307
-169
@@ -1,184 +1,329 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 1.11.1-rc1 / 2021-07-27
|
||||
# v1.11.2 / 2021-09-06
|
||||
|
||||
This is the first release candidate for the **highly-recommended** but optional Lotus v1.11.1 release that introduces many deal making and datastore improvements and new features along with other bug fixes. A more organized and detailed release note will be shared in the next few days with future RCs, highlights are:
|
||||
- [lotus-miner market subsystem](https://docs.filecoin.io/mine/lotus/split-markets-miners/#frontmatter-title)
|
||||
- [splistore](https://github.com/filecoin-project/lotus/blob/master/blockstore/splitstore/README.md)
|
||||
lotus v1.11.2 is a feature release that's **highly recommended ALL lotus users to upgrade**, including node operators,
|
||||
storage providers and clients.
|
||||
|
||||
## Highlights
|
||||
- 🌟🌟🌟 Introduce Dagstore and CARv2 for deal-making (#6671) ([filecoin-project/lotus#6671](https://github.com/filecoin-project/lotus/pull/6671))
|
||||
- **[lotus miner markets' Dagstore](https://docs.filecoin.io/mine/lotus/dagstore/#conceptual-overview)** is a
|
||||
component of the `markets` subsystem in lotus-miner. It is a sharded store to hold large IPLD graphs efficiently,
|
||||
packaged as location-transparent attachable CAR files and it replaces the former Badger staging blockstore. It
|
||||
is designed to provide high efficiency and throughput, and minimize resource utilization during deal-making operations.
|
||||
The dagstore also leverages the indexing features of [CARv2](https://github.com/ipld/ipld/blob/master/specs/transport/car/carv2/index.md) to enable plan CAR files to act as read and write
|
||||
blockstores, which are served as the direct medium for data exchanges in markets for both storage and retrieval
|
||||
deal making without requiring intermediate buffers.
|
||||
- In the future, lotus will leverage and interact with Dagstore a lot for new features and improvements for deal
|
||||
making, therefore, it's highly recommended to lotus users to go through [Lotus Miner: About the markets dagstore](https://docs.filecoin.io/mine/lotus/dagstore/#conceptual-overview) thoroughly to learn more about Dagstore's
|
||||
conceptual overview, terminology, directory structure, configuration and so on.
|
||||
- **Note**:
|
||||
- When you first start your lotus-miner or market subsystem with this release, a one-time/first-time **dagstore migration** will be triggered which replaces the former Badger staging blockstore with dagstore. We highly
|
||||
recommend storage providers to read this [section](https://docs.filecoin.io/mine/lotus/dagstore/#first-time-migration) to learn more about
|
||||
what the process does, what to expect and how monitor it.
|
||||
- It is highly recommended to **wait all ongoing data transfer to finish or cancel inbound storage deals that
|
||||
are still transferring**, using the `lotus-miner data-transfers cancel` command before upgrade your market nodes. Reason being that the new dagstore changes attributes in the internal deal state objects, and the paths to the staging CARs where the deal data was being placed will be lost.
|
||||
- ‼️Having your dags initialized will become important in the near feature for you to provide a better storage
|
||||
and retrieval service. We'd suggest you to start [forced bulk initialization] soon if possible as this process
|
||||
places relatively high IP workload on your storage system and is better to be carried out gradually and over a
|
||||
longer timeframe. Read how to do properly perform a force bulk initialization [here](https://docs.filecoin.io/mine/lotus/dagstore/#forcing-bulk-initialization).
|
||||
- ⏮ Rollback Alert(from v1.11.2-rcX to any version lower): If a storages deal is initiated with M1/v1.11.2(-rcX)
|
||||
release, it needs to get to the `StorageDealAwaitingPrecommit` state before you can do a version rollback or the markets process may panic.
|
||||
- 💙 **Special thanks to [MinerX fellows for testing and providing valuable feedbacks](https://github.com/filecoin-project/lotus/discussions/6852) for Dagstore in the past month!**
|
||||
- 🌟🌟 rpcenc: Support reader redirect ([filecoin-project/lotus#6952](https://github.com/filecoin-project/lotus/pull/6952))
|
||||
- This allows market processes to send piece bytes directly to workers involved on `AddPiece`.
|
||||
- Extending sectors: more practical and flexible tools ([filecoin-project/lotus#6097](https://github.com/filecoin-project/lotus/pull/6097))
|
||||
- `lotus-miner sectors check-expire` to inspect expiring sectors.
|
||||
- `lotus-miner sectors renew` for renewing expiring sectors, see the command help menu for customizable option
|
||||
like `extension`, `new-expiration` and so on.
|
||||
- ‼️ MpoolReplaceCmd ( lotus mpool replace`) now takes FIL for fee-limit ([filecoin-project/lotus#6927](https://github.com/filecoin-project/lotus/pull/6927))
|
||||
- Drop townhall/chainwatch ([filecoin-project/lotus#6912](https://github.com/filecoin-project/lotus/pull/6912))
|
||||
- ChainWatch is no longer supported by lotus.
|
||||
- Configurable CC Sector Expiration ([filecoin-project/lotus#6803](https://github.com/filecoin-project/lotus/pull/6803))
|
||||
- Set `CommittedCapacitySectorLifetime` in lotus-miner/config.toml to specify the default expiration for a new CC
|
||||
sector, value must be between 180-540 days inclusive.
|
||||
|
||||
## New Features
|
||||
- api/command for encoding actor params ([filecoin-project/lotus#7150](https://github.com/filecoin-project/lotus/pull/7150))
|
||||
- shed: Support raw encoding in cid id ([filecoin-project/lotus#7149](https://github.com/filecoin-project/lotus/pull/7149))
|
||||
- feat(miner deals): create subdir to miner repo for staged deals ([filecoin-project/lotus#6853](https://github.com/filecoin-project/lotus/pull/6853))
|
||||
- Support --actor in miner actor control list ([filecoin-project/lotus#7027](https://github.com/filecoin-project/lotus/pull/7027))
|
||||
- Shed: Include network name in genesis-verify ([filecoin-project/lotus#7019](https://github.com/filecoin-project/lotus/pull/7019))
|
||||
- feat: add ChainGetTipSetAfterHeight ([filecoin-project/lotus#6990](https://github.com/filecoin-project/lotus/pull/6990))
|
||||
- lotus-shed splitstore clear command ([filecoin-project/lotus#6967](https://github.com/filecoin-project/lotus/pull/6967))
|
||||
|
||||
## Improvements
|
||||
- improve get api error messages ([filecoin-project/lotus#7088](https://github.com/filecoin-project/lotus/pull/7088))
|
||||
- Strict major minor version checking on v0 and v1 apis ([filecoin-project/lotus#7038](https://github.com/filecoin-project/lotus/pull/7038))
|
||||
- make lotus-miner net commands hit markets subsystem. ([filecoin-project/lotus#7042](https://github.com/filecoin-project/lotus/pull/7042))
|
||||
- Test with latest actors version ([filecoin-project/lotus#6998](https://github.com/filecoin-project/lotus/pull/6998))
|
||||
- Reduce splitstore memory usage during chain walks ([filecoin-project/lotus#6949](https://github.com/filecoin-project/lotus/pull/6949))
|
||||
- Remove forgotten non-functioning config from the pre-mainnet days ([filecoin-project/lotus#6970](https://github.com/filecoin-project/lotus/pull/6970))
|
||||
- add explicit error msg if repo dir does not exist ([filecoin-project/lotus#6909](https://github.com/filecoin-project/lotus/pull/6909))
|
||||
- Test/pledge batching msg prop ([filecoin-project/lotus#6537](https://github.com/filecoin-project/lotus/pull/6537))
|
||||
- reasonable max value for initial sector expiration ([filecoin-project/lotus#6099](https://github.com/filecoin-project/lotus/pull/6099))
|
||||
- support MARKETS_API_INFO env var, and markets-repo, markets-api-url CLI flags. ([filecoin-project/lotus#6936](https://github.com/filecoin-project/lotus/pull/6936))
|
||||
- Improve formatting of workers CLI ([filecoin-project/lotus#6942](https://github.com/filecoin-project/lotus/pull/6942))
|
||||
- make: set default GOCC earlier ([filecoin-project/lotus#6932](https://github.com/filecoin-project/lotus/pull/6932))
|
||||
- Moving GC Followup ([filecoin-project/lotus#6905](https://github.com/filecoin-project/lotus/pull/6905))
|
||||
- Log more call context during errors ([filecoin-project/lotus#6918](https://github.com/filecoin-project/lotus/pull/6918))
|
||||
- polish(errors): better state tree errors ([filecoin-project/lotus#6923](https://github.com/filecoin-project/lotus/pull/6923))
|
||||
- adding an RuntimeSubsystems API to storage miner; fix `lotus-miner info` ([filecoin-project/lotus#6906](https://github.com/filecoin-project/lotus/pull/6906))
|
||||
- Reduce entropy in the chain package ([filecoin-project/lotus#6889](https://github.com/filecoin-project/lotus/pull/6889))
|
||||
- make: Allow setting Go compiler with GOCC ([filecoin-project/lotus#6911](https://github.com/filecoin-project/lotus/pull/6911))
|
||||
|
||||
## Bug Fixes
|
||||
- sealing: Fix RecoverDealIDs loop with changed PieceCID ([filecoin-project/lotus#7117](https://github.com/filecoin-project/lotus/pull/7117))
|
||||
- Fix error handling in SectorAddPieceToAny api impl ([filecoin-project/lotus#7135](https://github.com/filecoin-project/lotus/pull/7135))
|
||||
- add rice box to required binaries ([filecoin-project/lotus#7125](https://github.com/filecoin-project/lotus/pull/7125))
|
||||
- fix(miner): always create miner deal staging directory (#7098) ([filecoin-project/lotus#7098](https://github.com/filecoin-project/lotus/pull/7098))
|
||||
- fix build after merging #6097. (#7096) ([filecoin-project/lotus#7096](https://github.com/filecoin-project/lotus/pull/7096))
|
||||
- fix: don't check for t_aux when proving ([filecoin-project/lotus#7011](https://github.com/filecoin-project/lotus/pull/7011))
|
||||
- fix: vet actors shims ([filecoin-project/lotus#6999](https://github.com/filecoin-project/lotus/pull/6999))
|
||||
- fix: more logging in maybeStartBatch error ([filecoin-project/lotus#6996](https://github.com/filecoin-project/lotus/pull/6996))
|
||||
- fix flaky TestDealPublisher and re-enable ([filecoin-project/lotus#6991](https://github.com/filecoin-project/lotus/pull/6991))
|
||||
- fix skipCount ([filecoin-project/lotus#6940](https://github.com/filecoin-project/lotus/pull/6940))
|
||||
- fix bug in MpoolPending message exclusion ([filecoin-project/lotus#6945](https://github.com/filecoin-project/lotus/pull/6945))
|
||||
- PreCommitPolicy: Don't try to align expirations on proving period boundaries ([filecoin-project/lotus#7018](https://github.com/filecoin-project/lotus/pull/7018))
|
||||
- make: fix version check when using gotip ([filecoin-project/lotus#6916](https://github.com/filecoin-project/lotus/pull/6916))
|
||||
- fix ticket check ([filecoin-project/lotus#6882](https://github.com/filecoin-project/lotus/pull/6882))
|
||||
|
||||
## Dependency Updates
|
||||
- github.com/filecoin-project/go-data-transfer (v1.7.2 -> v1.7.8):
|
||||
- github.com/filecoin-project/go-fil-markets (v1.6.2 -> v1.8.1):
|
||||
- update go-libp2p-pubsub to v0.5.4 ([filecoin-project/lotus#6958](https://github.com/filecoin-project/lotus/pull/6958))
|
||||
- integrate the proof patch: tag proofs-v9-revert-deps-hotfix
|
||||
- Update markets, dt and graphsync ([filecoin-project/lotus#7160](https://github.com/filecoin-project/lotus/pull/7160))
|
||||
- Remove replace directive for multihash dep (#7113) ([filecoin-project/lotus#7113](https://github.com/filecoin-project/lotus/pull/7113))
|
||||
- upgrade upstream dependencies. ([filecoin-project/lotus#7115](https://github.com/filecoin-project/lotus/pull/7115))
|
||||
- Update to latest FFI ([filecoin-project/lotus#7110](https://github.com/filecoin-project/lotus/pull/7110))
|
||||
- Update state machine deps for logging ([filecoin-project/lotus#6941](https://github.com/filecoin-project/lotus/pull/6941))
|
||||
- Update deps for more logging in data transfer and markets ([filecoin-project/lotus#6937](https://github.com/filecoin-project/lotus/pull/6937))
|
||||
- Update to branches with improved logging ([filecoin-project/lotus#6919](https://github.com/filecoin-project/lotus/pull/6919))
|
||||
- update go-libp2p-pubsub to v0.5.3 ([filecoin-project/lotus#6907](https://github.com/filecoin-project/lotus/pull/6907))
|
||||
|
||||
## Others
|
||||
- Fix nits and see if codecov works now with auto ([filecoin-project/lotus#7151](https://github.com/filecoin-project/lotus/pull/7151))
|
||||
- Codecov Projects ([filecoin-project/lotus#7147](https://github.com/filecoin-project/lotus/pull/7147))
|
||||
- remove m1 templates and make area selection multi-optionable ([filecoin-project/lotus#7121](https://github.com/filecoin-project/lotus/pull/7121))
|
||||
- release -> master ([filecoin-project/lotus#7105](https://github.com/filecoin-project/lotus/pull/7105))
|
||||
- Lotus release process - how we make releases ([filecoin-project/lotus#6944](https://github.com/filecoin-project/lotus/pull/6944))
|
||||
- codecov: fix mock name ([filecoin-project/lotus#7039](https://github.com/filecoin-project/lotus/pull/7039))
|
||||
- codecov: fix regexes ([filecoin-project/lotus#7037](https://github.com/filecoin-project/lotus/pull/7037))
|
||||
- chore: disable flaky test ([filecoin-project/lotus#6957](https://github.com/filecoin-project/lotus/pull/6957))
|
||||
- set buildtype in nerpa and butterfly ([filecoin-project/lotus#6085](https://github.com/filecoin-project/lotus/pull/6085))
|
||||
- release v1.11.1 backport -> master ([filecoin-project/lotus#6929](https://github.com/filecoin-project/lotus/pull/6929))
|
||||
- chore: fixup issue templates ([filecoin-project/lotus#6899](https://github.com/filecoin-project/lotus/pull/6899))
|
||||
- bump master version to v1.11.2-dev ([filecoin-project/lotus#6903](https://github.com/filecoin-project/lotus/pull/6903))
|
||||
- releases -> master for v1.11.0 ([filecoin-project/lotus#6894](https://github.com/filecoin-project/lotus/pull/6894))
|
||||
|
||||
- github.com/filecoin-project/lotus:
|
||||
- Merge branch 'releases' into release/v1.11.1
|
||||
- Update to proof v8.0.3 ([filecoin-project/lotus#6890](https://github.com/filecoin-project/lotus/pull/6890))
|
||||
- lotus-shed: initial export cmd for markets related metadata ([filecoin-project/lotus#6840](https://github.com/filecoin-project/lotus/pull/6840))
|
||||
- add a very verbose -vv flag to lotus and lotus-miner. ([filecoin-project/lotus#6888](https://github.com/filecoin-project/lotus/pull/6888))
|
||||
- Update RELEASE_ISSUE_TEMPLATE.md ([filecoin-project/lotus#6880](https://github.com/filecoin-project/lotus/pull/6880))
|
||||
- Moving GC for badger ([filecoin-project/lotus#6854](https://github.com/filecoin-project/lotus/pull/6854))
|
||||
- Add github actions for staled pr ([filecoin-project/lotus#6879](https://github.com/filecoin-project/lotus/pull/6879))
|
||||
- Add allocated sectorid vis ([filecoin-project/lotus#4638](https://github.com/filecoin-project/lotus/pull/4638))
|
||||
- rename `cmd/lotus{-storage=>}-miner` to match binary. ([filecoin-project/lotus#6886](https://github.com/filecoin-project/lotus/pull/6886))
|
||||
- update to go-fil-market v1.6.0 ([filecoin-project/lotus#6885](https://github.com/filecoin-project/lotus/pull/6885))
|
||||
- Bump go-multihash, adjust test for supported version ([filecoin-project/lotus#6674](https://github.com/filecoin-project/lotus/pull/6674))
|
||||
- Fix padding of deals, which only partially shipped in #5988 ([filecoin-project/lotus#6683](https://github.com/filecoin-project/lotus/pull/6683))
|
||||
- fix racy TestSimultanenousTransferLimit. ([filecoin-project/lotus#6862](https://github.com/filecoin-project/lotus/pull/6862))
|
||||
- Improve splitstore warmup ([filecoin-project/lotus#6867](https://github.com/filecoin-project/lotus/pull/6867))
|
||||
- ValidateBlock: Assert that block header height's are greater than parents ([filecoin-project/lotus#6872](https://github.com/filecoin-project/lotus/pull/6872))
|
||||
- feat: Don't panic when api impl is nil ([filecoin-project/lotus#6857](https://github.com/filecoin-project/lotus/pull/6857))
|
||||
- splitstore shed utils ([filecoin-project/lotus#6811](https://github.com/filecoin-project/lotus/pull/6811))
|
||||
- Fix links in issue templates
|
||||
- Update issue templates and add templates for M1 ([filecoin-project/lotus#6856](https://github.com/filecoin-project/lotus/pull/6856))
|
||||
- Splitstore: support on-disk marksets using badger ([filecoin-project/lotus#6833](https://github.com/filecoin-project/lotus/pull/6833))
|
||||
- Config UX improvements ([filecoin-project/lotus#6848](https://github.com/filecoin-project/lotus/pull/6848))
|
||||
- fix deal concurrency test failures by upgrading graphsync and others ([filecoin-project/lotus#6724](https://github.com/filecoin-project/lotus/pull/6724))
|
||||
- Update issue templates to forms ([filecoin-project/lotus#6798](https://github.com/filecoin-project/lotus/pull/6798))
|
||||
- Nerpa v13 upgrade ([filecoin-project/lotus#6837](https://github.com/filecoin-project/lotus/pull/6837))
|
||||
- add docker-compose file ([filecoin-project/lotus#6544](https://github.com/filecoin-project/lotus/pull/6544))
|
||||
- fix warmup by decoupling state from message receipt walk ([filecoin-project/lotus#6841](https://github.com/filecoin-project/lotus/pull/6841))
|
||||
- add a command for compacting sector numbers bitfield ([filecoin-project/lotus#4640](https://github.com/filecoin-project/lotus/pull/4640))
|
||||
- PriceListByVersion ([filecoin-project/lotus#6766](https://github.com/filecoin-project/lotus/pull/6766))
|
||||
- easy way to make install app ([filecoin-project/lotus#5183](https://github.com/filecoin-project/lotus/pull/5183))
|
||||
- api: Separate the Net interface from Common ([filecoin-project/lotus#6627](https://github.com/filecoin-project/lotus/pull/6627))
|
||||
- cache loaded block messages ([filecoin-project/lotus#6760](https://github.com/filecoin-project/lotus/pull/6760))
|
||||
- fix: on randomness change, use new rand ([filecoin-project/lotus#6805](https://github.com/filecoin-project/lotus/pull/6805))
|
||||
- Splitstore: add retention policy option for keeping messages in the hotstore ([filecoin-project/lotus#6775](https://github.com/filecoin-project/lotus/pull/6775))
|
||||
- Introduce the LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC envvar ([filecoin-project/lotus#6817](https://github.com/filecoin-project/lotus/pull/6817))
|
||||
- add StateReadState to gateway api ([filecoin-project/lotus#6818](https://github.com/filecoin-project/lotus/pull/6818))
|
||||
- add SealProof in SectorBuilder ([filecoin-project/lotus#6815](https://github.com/filecoin-project/lotus/pull/6815))
|
||||
- release -> master ([filecoin-project/lotus#6828](https://github.com/filecoin-project/lotus/pull/6828))
|
||||
- sealing: Handle preCommitParams errors more correctly ([filecoin-project/lotus#6763](https://github.com/filecoin-project/lotus/pull/6763))
|
||||
- fix: always check if StateSearchMessage returns nil ([filecoin-project/lotus#6802](https://github.com/filecoin-project/lotus/pull/6802))
|
||||
- ClientFindData: always fetch peer id from chain ([filecoin-project/lotus#6807](https://github.com/filecoin-project/lotus/pull/6807))
|
||||
- test: fix flaky window post tests ([filecoin-project/lotus#6804](https://github.com/filecoin-project/lotus/pull/6804))
|
||||
- ([filecoin-project/lotus#6800](https://github.com/filecoin-project/lotus/pull/6800))
|
||||
- fixes #6786 segfault ([filecoin-project/lotus#6787](https://github.com/filecoin-project/lotus/pull/6787))
|
||||
- Splitstore: add support for protecting out of chain references in the blockstore ([filecoin-project/lotus#6777](https://github.com/filecoin-project/lotus/pull/6777))
|
||||
- Resurrect CODEOWNERS, but for maintainers group ([filecoin-project/lotus#6773](https://github.com/filecoin-project/lotus/pull/6773))
|
||||
- update go-libp2p-pubsub to v0.5.0 ([filecoin-project/lotus#6764](https://github.com/filecoin-project/lotus/pull/6764))
|
||||
- Implement exposed splitstore ([filecoin-project/lotus#6762](https://github.com/filecoin-project/lotus/pull/6762))
|
||||
- Add ChainGetMessagesInTipset API ([filecoin-project/lotus#6642](https://github.com/filecoin-project/lotus/pull/6642))
|
||||
- test: handle null blocks in TestForkRefuseCall ([filecoin-project/lotus#6758](https://github.com/filecoin-project/lotus/pull/6758))
|
||||
- Master disclaimer ([filecoin-project/lotus#6757](https://github.com/filecoin-project/lotus/pull/6757))
|
||||
- Splitstore code reorg ([filecoin-project/lotus#6756](https://github.com/filecoin-project/lotus/pull/6756))
|
||||
- Create stale.yml ([filecoin-project/lotus#6747](https://github.com/filecoin-project/lotus/pull/6747))
|
||||
- Splitstore: Some small fixes ([filecoin-project/lotus#6754](https://github.com/filecoin-project/lotus/pull/6754))
|
||||
- ([filecoin-project/lotus#6746](https://github.com/filecoin-project/lotus/pull/6746))
|
||||
- Handle the --color flag via proper global state ([filecoin-project/lotus#6743](https://github.com/filecoin-project/lotus/pull/6743))
|
||||
- Config for collateral from miner available balance ([filecoin-project/lotus#6629](https://github.com/filecoin-project/lotus/pull/6629))
|
||||
- Support standalone miner-market process ([filecoin-project/lotus#6356](https://github.com/filecoin-project/lotus/pull/6356))
|
||||
- Splitstore Enhanchements ([filecoin-project/lotus#6474](https://github.com/filecoin-project/lotus/pull/6474))
|
||||
- ([filecoin-project/lotus#6739](https://github.com/filecoin-project/lotus/pull/6739))
|
||||
- Add more deal details to lotus-miner info ([filecoin-project/lotus#6708](https://github.com/filecoin-project/lotus/pull/6708))
|
||||
- Release template: Update all testnet infra at once ([filecoin-project/lotus#6710](https://github.com/filecoin-project/lotus/pull/6710))
|
||||
- Fix Lotus shed
|
||||
- Fix bugs in sectors extend --v1-sectors ([filecoin-project/lotus#6066](https://github.com/filecoin-project/lotus/pull/6066))
|
||||
- add election backtest ([filecoin-project/lotus#5950](https://github.com/filecoin-project/lotus/pull/5950))
|
||||
- Envvar to disable slash filter ([filecoin-project/lotus#6620](https://github.com/filecoin-project/lotus/pull/6620))
|
||||
- Release Template: remove binary validation step ([filecoin-project/lotus#6709](https://github.com/filecoin-project/lotus/pull/6709))
|
||||
- Config for deal publishing control addresses ([filecoin-project/lotus#6697](https://github.com/filecoin-project/lotus/pull/6697))
|
||||
- Reset of the interop network ([filecoin-project/lotus#6689](https://github.com/filecoin-project/lotus/pull/6689))
|
||||
- Enable color by default only if os.Stdout is a TTY ([filecoin-project/lotus#6696](https://github.com/filecoin-project/lotus/pull/6696))
|
||||
- Stop outputing ANSI color on non-TTY ([filecoin-project/lotus#6694](https://github.com/filecoin-project/lotus/pull/6694))
|
||||
- add dollar sign ([filecoin-project/lotus#6690](https://github.com/filecoin-project/lotus/pull/6690))
|
||||
- get-actor cli spelling fix ([filecoin-project/lotus#6681](https://github.com/filecoin-project/lotus/pull/6681))
|
||||
- fix "lotus-seed genesis car" error "merkledag: not found" ([filecoin-project/lotus#6688](https://github.com/filecoin-project/lotus/pull/6688))
|
||||
- polish(statetree): accept a context in statetree diff for timeouts ([filecoin-project/lotus#6639](https://github.com/filecoin-project/lotus/pull/6639))
|
||||
- Add helptext to lotus chain export ([filecoin-project/lotus#6672](https://github.com/filecoin-project/lotus/pull/6672))
|
||||
- Get retrieval pricing input should not error out on a deal state fetch ([filecoin-project/lotus#6679](https://github.com/filecoin-project/lotus/pull/6679))
|
||||
- Fix more CID double-encoding as hex ([filecoin-project/lotus#6680](https://github.com/filecoin-project/lotus/pull/6680))
|
||||
- add an incremental nonce itest. ([filecoin-project/lotus#6663](https://github.com/filecoin-project/lotus/pull/6663))
|
||||
- storage: Fix FinalizeSector with sectors in stoage paths ([filecoin-project/lotus#6653](https://github.com/filecoin-project/lotus/pull/6653))
|
||||
- Fix tiny error in check-client-datacap ([filecoin-project/lotus#6664](https://github.com/filecoin-project/lotus/pull/6664))
|
||||
- Fix: precommit_batch method used the wrong cfg.CommitBatchWait ([filecoin-project/lotus#6658](https://github.com/filecoin-project/lotus/pull/6658))
|
||||
- fix ticket expiration check ([filecoin-project/lotus#6635](https://github.com/filecoin-project/lotus/pull/6635))
|
||||
- commit batch: AggregateAboveBaseFee config ([filecoin-project/lotus#6650](https://github.com/filecoin-project/lotus/pull/6650))
|
||||
- commit batch: Initialize the FailedSectors map ([filecoin-project/lotus#6647](https://github.com/filecoin-project/lotus/pull/6647))
|
||||
- Fast-path retry submitting commit aggregate if commit is still valid ([filecoin-project/lotus#6638](https://github.com/filecoin-project/lotus/pull/6638))
|
||||
- remove precommit check in handleCommitFailed ([filecoin-project/lotus#6634](https://github.com/filecoin-project/lotus/pull/6634))
|
||||
- Reuse timers in sealing batch logic ([filecoin-project/lotus#6636](https://github.com/filecoin-project/lotus/pull/6636))
|
||||
- shed tool to estimate aggregate network fees ([filecoin-project/lotus#6631](https://github.com/filecoin-project/lotus/pull/6631))
|
||||
- fix prove commit aggregate send token amount ([filecoin-project/lotus#6625](https://github.com/filecoin-project/lotus/pull/6625))
|
||||
- Update version.go to 1.11.1 ([filecoin-project/lotus#6621](https://github.com/filecoin-project/lotus/pull/6621))
|
||||
- github.com/filecoin-project/go-data-transfer (v1.6.0 -> v1.7.0):
|
||||
- release: v1.7.0
|
||||
- Fire a transfer queued event when a transfer is queued in Graphsync (#221) ([filecoin-project/go-data-transfer#221](https://github.com/filecoin-project/go-data-transfer/pull/221))
|
||||
- feat: pass ChannelID to ValidatePush & ValidatePull (#220) ([filecoin-project/go-data-transfer#220](https://github.com/filecoin-project/go-data-transfer/pull/220))
|
||||
- release: v1.6.1 ([filecoin-project/go-data-transfer#218](https://github.com/filecoin-project/go-data-transfer/pull/218))
|
||||
- Remove CID lists (#217) ([filecoin-project/go-data-transfer#217](https://github.com/filecoin-project/go-data-transfer/pull/217))
|
||||
- Merge v1.6.0 ([filecoin-project/go-data-transfer#214](https://github.com/filecoin-project/go-data-transfer/pull/214))
|
||||
- Remove restart ack timeout (#211) ([filecoin-project/go-data-transfer#211](https://github.com/filecoin-project/go-data-transfer/pull/211))
|
||||
- feat: use different extension names to fit multiple hooks data in same graphsync message (#204) ([filecoin-project/go-data-transfer#204](https://github.com/filecoin-project/go-data-transfer/pull/204))
|
||||
- fix: map race in GS transport (#208) ([filecoin-project/go-data-transfer#208](https://github.com/filecoin-project/go-data-transfer/pull/208))
|
||||
- refactor: simplify graphsync transport (#203) ([filecoin-project/go-data-transfer#203](https://github.com/filecoin-project/go-data-transfer/pull/203))
|
||||
- release: v1.5.0 (#200) ([filecoin-project/go-data-transfer#200](https://github.com/filecoin-project/go-data-transfer/pull/200))
|
||||
- github.com/filecoin-project/go-fil-markets (v1.5.0 -> v1.6.0):
|
||||
- release: v1.6.0
|
||||
- support padding out smaller files (#536) ([filecoin-project/go-fil-markets#536](https://github.com/filecoin-project/go-fil-markets/pull/536))
|
||||
- On overloaded CI 10 seconds just isn't enough (#587) ([filecoin-project/go-fil-markets#587](https://github.com/filecoin-project/go-fil-markets/pull/587))
|
||||
- Do not hex-encode CIDs in logs (#561) ([filecoin-project/go-fil-markets#561](https://github.com/filecoin-project/go-fil-markets/pull/561))
|
||||
- remove wrong peer check in push deal validation (#585) ([filecoin-project/go-fil-markets#585](https://github.com/filecoin-project/go-fil-markets/pull/585))
|
||||
- fix: circleci docs-gen task (#574) ([filecoin-project/go-fil-markets#574](https://github.com/filecoin-project/go-fil-markets/pull/574))
|
||||
- Storage market request queued event and validation interface changes (#555) ([filecoin-project/go-fil-markets#555](https://github.com/filecoin-project/go-fil-markets/pull/555))
|
||||
- build(deps): bump ws from 6.2.1 to 6.2.2 (#554) ([filecoin-project/go-fil-markets#554](https://github.com/filecoin-project/go-fil-markets/pull/554))
|
||||
- release: v1.5.0 ([filecoin-project/go-fil-markets#553](https://github.com/filecoin-project/go-fil-markets/pull/553))
|
||||
- github.com/filecoin-project/go-padreader (v0.0.0-20200903213702-ed5fae088b20 -> v0.0.0-20210723183308-812a16dc01b1):
|
||||
- New method to pad harder (#6) ([filecoin-project/go-padreader#6](https://github.com/filecoin-project/go-padreader/pull/6))
|
||||
- Create SECURITY.md (#5) ([filecoin-project/go-padreader#5](https://github.com/filecoin-project/go-padreader/pull/5))
|
||||
- github.com/filecoin-project/go-state-types (v0.1.1-0.20210506134452-99b279731c48 -> v0.1.1-0.20210722133031-ad9bfe54c124):
|
||||
- Add version 6.5 (#30) ([filecoin-project/go-state-types#30](https://github.com/filecoin-project/go-state-types/pull/30))
|
||||
- rename file
|
||||
- github.com/filecoin-project/specs-actors/v5 (v5.0.1 -> v5.0.3):
|
||||
- Adjust code for subtle change in go-multihash 0.0.15 (#1463) ([filecoin-project/specs-actors#1463](https://github.com/filecoin-project/specs-actors/pull/1463))
|
||||
- Bump go state types (#1464) ([filecoin-project/specs-actors#1464](https://github.com/filecoin-project/specs-actors/pull/1464))
|
||||
- Create CODEOWNERS (#1465) ([filecoin-project/specs-actors#1465](https://github.com/filecoin-project/specs-actors/pull/1465))
|
||||
- Test deterministic offset (#1462) ([filecoin-project/specs-actors#1462](https://github.com/filecoin-project/specs-actors/pull/1462))
|
||||
|
||||
Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| vyzo | 295 | +8700/-5936 | 397 |
|
||||
| Anton Evangelatov | 94 | +4680/-2965 | 277 |
|
||||
| Łukasz Magiera | 37 | +3851/-1611 | 146 |
|
||||
| Mike Greenberg | 1 | +2310/-578 | 8 |
|
||||
| dirkmc | 7 | +1154/-726 | 29 |
|
||||
| Jennifer Wang | 9 | +485/-341 | 26 |
|
||||
| Peter Rabbitson | 18 | +469/-273 | 64 |
|
||||
| Cory Schwartz | 5 | +576/-135 | 14 |
|
||||
| hunjixin | 7 | +404/-82 | 19 |
|
||||
| ZenGround0 | 17 | +284/-135 | 44 |
|
||||
| Dirk McCormick | 17 | +348/-47 | 17 |
|
||||
| Raúl Kripalani | 18 | +254/-97 | 62 |
|
||||
| tchardin | 1 | +261/-33 | 4 |
|
||||
| Jakub Sztandera | 4 | +254/-16 | 4 |
|
||||
| Aarsh Shah | 2 | +196/-40 | 28 |
|
||||
| whyrusleeping | 3 | +150/-9 | 8 |
|
||||
| Whyrusleeping | 2 | +87/-66 | 10 |
|
||||
| Aayush Rajasekaran | 10 | +81/-53 | 13 |
|
||||
| zgfzgf | 2 | +104/-4 | 2 |
|
||||
| aarshkshah1992 | 4 | +73/-7 | 6 |
|
||||
| llifezou | 4 | +59/-20 | 4 |
|
||||
| Steven Allen | 7 | +47/-17 | 9 |
|
||||
| johnli-helloworld | 3 | +46/-15 | 5 |
|
||||
| frrist | 1 | +28/-23 | 2 |
|
||||
| Jennifer | 4 | +31/-2 | 4 |
|
||||
| wangchao | 1 | +1/-27 | 1 |
|
||||
| Jiaying Wang | 2 | +7/-21 | 2 |
|
||||
| hannahhoward | 3 | +21/-2 | 3 |
|
||||
| chadwick2143 | 1 | +15/-1 | 1 |
|
||||
| Jerry | 2 | +9/-4 | 2 |
|
||||
| @magik6k | 23 | +5040/-8389 | 114 |
|
||||
| @aarshkshah1992 | 11 | +4859/-1078 | 101 |
|
||||
| @raulk | 5 | +4170/-1662 | 104 |
|
||||
| @vyzo | 30 | +1092/-702 | 49 |
|
||||
| @nonsense | 6 | +630/-472 | 19 |
|
||||
| @ZenGround0 | 31 | +556/-274 | 74 |
|
||||
| @He Weidong | 16 | +680/-128 | 16 |
|
||||
| @raulk | 16 | +444/-277 | 49 |
|
||||
| @Stebalien | 11 | +403/-259 | 48 |
|
||||
| @jennijuju| 17 | +276/-281 | 42 |
|
||||
| @dirkmc | 5 | +204/-138 | 20 |
|
||||
| @placer14 | 7 | +178/-77 | 17 |
|
||||
| @BlocksOnAChain | 1 | +138/-0 | 1 |
|
||||
| @Frrist | 1 | +63/-56 | 2 |
|
||||
| @arajasek | 7 | +74/-42 | 13 |
|
||||
| @frrist | 2 | +67/-6 | 6 |
|
||||
| @hannahhoward | 2 | +13/-11 | 3 |
|
||||
| @coryschwartz | 1 | +16/-6 | 3 |
|
||||
| @whyrusleeping | 1 | +7/-7 | 1 |
|
||||
| @hunjixin | 1 | +8/-6 | 1 |
|
||||
| @aarshkshah1992 | 1 | +6/-6 | 2 |
|
||||
| @dirkmc | 2 | +8/-0 | 2 |
|
||||
| @mx | 2 | +6/-1 | 2 |
|
||||
| @travisperson | 1 | +3/-2 | 1 |
|
||||
| @jennijuju | 2 | +2/-2 | 2 |
|
||||
| @ribasushi | 1 | +1/-2 | 2 |
|
||||
|
||||
# 1.11.1 / 2021-08-16
|
||||
|
||||
> Note: for discussion about this release, please comment [here](https://github.com/filecoin-project/lotus/discussions/6904)
|
||||
|
||||
This is a **highly recommended** but optional Lotus v1.11.1 release that introduces many deal making and datastore improvements and new features along with other bug fixes.
|
||||
|
||||
## Highlights
|
||||
- ⭐️⭐️⭐️[**lotus-miner market subsystem**](https://docs.filecoin.io/mine/lotus/split-markets-miners/#frontmatter-title) is introduced in this release! It is **highly recommended** for storage providers to run markets processes on a separate machine! Doing so, only this machine needs to exposes public ports for deal making. This also means that the other miner operations can now be completely isolated by from the deal making processes and storage providers can stop and restarts the markets process without affecting an ongoing Winning/Window PoSt!
|
||||
- More details on the concepts, architecture and how to split the market process can be found [here](https://docs.filecoin.io/mine/lotus/split-markets-miners/#concepts).
|
||||
- Base on your system setup(running on separate machines, same machine and so on), please see the suggested practice by community members [here](https://github.com/filecoin-project/lotus/discussions/7047#discussion-3515335).
|
||||
- Note: if you are running lotus-worker on a different machine, you will need to set `MARKETS_API_INFO` for certain CLI to work properly. This will be improved by #7072.
|
||||
- Huge thanks to MinerX fellows for [helping testing the implementation, reporting the issues so they were fixed by now and providing feedbacks](https://github.com/filecoin-project/lotus/discussions/6861) to user docs in the past three weeks!
|
||||
- Config for collateral from miner available balance ([filecoin-project/lotus#6629](https://github.com/filecoin-project/lotus/pull/6629))
|
||||
- Better control your sector collateral payment by setting `CollateralFromMinerBalance`, `AvailableBalanceBuffer` and `DisableCollateralFallback`.
|
||||
- `CollateralFromMinerBalance`: whether to use available miner balance for sector collateral instead of sending it with each message, default is `false`.
|
||||
- `AvailableBalanceBuffer`: minimum available balance to keep in the miner actor before sending it with messages, default is 0FIL.
|
||||
- `DisableCollateralFallback`: whether to send collateral with messages even if there is no available balance in the miner actor, default is `false`.
|
||||
- Config for deal publishing control addresses ([filecoin-project/lotus#6697](https://github.com/filecoin-project/lotus/pull/6697))
|
||||
- Set `DealPublishControl` to set the wallet used for sending `PublishStorageDeals` messages, instructions [here](https://docs.filecoin.io/mine/lotus/miner-addresses/#control-addresses).
|
||||
- Config UX improvements ([filecoin-project/lotus#6848](https://github.com/filecoin-project/lotus/pull/6848))
|
||||
- You can now preview the the default and updated node config by running `lotus/lotus-miner config default/updated`
|
||||
|
||||
## New Features
|
||||
- ⭐️⭐️⭐️ Support standalone miner-market process ([filecoin-project/lotus#6356](https://github.com/filecoin-project/lotus/pull/6356))
|
||||
- **⭐️⭐️ Experimental** [Splitstore]((https://github.com/filecoin-project/lotus/blob/master/blockstore/splitstore/README.md)) (more details coming in v1.11.2! Stay tuned! Join the discussion [here](https://github.com/filecoin-project/lotus/discussions/5788) if you have questions!) :
|
||||
- Improve splitstore warmup ([filecoin-project/lotus#6867](https://github.com/filecoin-project/lotus/pull/6867))
|
||||
- Moving GC for badger ([filecoin-project/lotus#6854](https://github.com/filecoin-project/lotus/pull/6854))
|
||||
- splitstore shed utils ([filecoin-project/lotus#6811](https://github.com/filecoin-project/lotus/pull/6811))
|
||||
- fix warmup by decoupling state from message receipt walk ([filecoin-project/lotus#6841](https://github.com/filecoin-project/lotus/pull/6841))
|
||||
- Splitstore: support on-disk marksets using badger ([filecoin-project/lotus#6833](https://github.com/filecoin-project/lotus/pull/6833))
|
||||
- cache loaded block messages ([filecoin-project/lotus#6760](https://github.com/filecoin-project/lotus/pull/6760))
|
||||
- Splitstore: add retention policy option for keeping messages in the hotstore ([filecoin-project/lotus#6775](https://github.com/filecoin-project/lotus/pull/6775))
|
||||
- Introduce the LOTUS_CHAIN_BADGERSTORE_DISABLE_FSYNC envvar ([filecoin-project/lotus#6817](https://github.com/filecoin-project/lotus/pull/6817))
|
||||
- Splitstore: add support for protecting out of chain references in the blockstore ([filecoin-project/lotus#6777](https://github.com/filecoin-project/lotus/pull/6777))
|
||||
- Implement exposed splitstore ([filecoin-project/lotus#6762](https://github.com/filecoin-project/lotus/pull/6762))
|
||||
- Splitstore code reorg ([filecoin-project/lotus#6756](https://github.com/filecoin-project/lotus/pull/6756))
|
||||
- Splitstore: Some small fixes ([filecoin-project/lotus#6754](https://github.com/filecoin-project/lotus/pull/6754))
|
||||
- Splitstore Enhanchements ([filecoin-project/lotus#6474](https://github.com/filecoin-project/lotus/pull/6474))
|
||||
- lotus-shed: initial export cmd for markets related metadata ([filecoin-project/lotus#6840](https://github.com/filecoin-project/lotus/pull/6840))
|
||||
- add a very verbose -vv flag to lotus and lotus-miner. ([filecoin-project/lotus#6888](https://github.com/filecoin-project/lotus/pull/6888))
|
||||
- Add allocated sectorid vis ([filecoin-project/lotus#4638](https://github.com/filecoin-project/lotus/pull/4638))
|
||||
- add a command for compacting sector numbers bitfield ([filecoin-project/lotus#4640](https://github.com/filecoin-project/lotus/pull/4640))
|
||||
- Run `lotus-miner actor compact-allocated` to compact sector number allocations to reduce the size of the allocated sector number bitfield.
|
||||
- Add ChainGetMessagesInTipset API ([filecoin-project/lotus#6642](https://github.com/filecoin-project/lotus/pull/6642))
|
||||
- Handle the --color flag via proper global state ([filecoin-project/lotus#6743](https://github.com/filecoin-project/lotus/pull/6743))
|
||||
- Enable color by default only if os.Stdout is a TTY ([filecoin-project/lotus#6696](https://github.com/filecoin-project/lotus/pull/6696))
|
||||
- Stop outputing ANSI color on non-TTY ([filecoin-project/lotus#6694](https://github.com/filecoin-project/lotus/pull/6694))
|
||||
- Envvar to disable slash filter ([filecoin-project/lotus#6620](https://github.com/filecoin-project/lotus/pull/6620))
|
||||
- commit batch: AggregateAboveBaseFee config ([filecoin-project/lotus#6650](https://github.com/filecoin-project/lotus/pull/6650))
|
||||
- shed tool to estimate aggregate network fees ([filecoin-project/lotus#6631](https://github.com/filecoin-project/lotus/pull/6631))
|
||||
|
||||
## Bug Fixes
|
||||
- Fix padding of deals, which only partially shipped in #5988 ([filecoin-project/lotus#6683](https://github.com/filecoin-project/lotus/pull/6683))
|
||||
- fix deal concurrency test failures by upgrading graphsync and others ([filecoin-project/lotus#6724](https://github.com/filecoin-project/lotus/pull/6724))
|
||||
- fix: on randomness change, use new rand ([filecoin-project/lotus#6805](https://github.com/filecoin-project/lotus/pull/6805)) - fix: always check if StateSearchMessage returns nil ([filecoin-project/lotus#6802](https://github.com/filecoin-project/lotus/pull/6802))
|
||||
- test: fix flaky window post tests ([filecoin-project/lotus#6804](https://github.com/filecoin-project/lotus/pull/6804))
|
||||
- wrap close(wait) with sync.Once to avoid panic ([filecoin-project/lotus#6800](https://github.com/filecoin-project/lotus/pull/6800))
|
||||
- fixes #6786 segfault ([filecoin-project/lotus#6787](https://github.com/filecoin-project/lotus/pull/6787))
|
||||
- ClientRetrieve stops on cancel([filecoin-project/lotus#6739](https://github.com/filecoin-project/lotus/pull/6739))
|
||||
- Fix bugs in sectors extend --v1-sectors ([filecoin-project/lotus#6066](https://github.com/filecoin-project/lotus/pull/6066))
|
||||
- fix "lotus-seed genesis car" error "merkledag: not found" ([filecoin-project/lotus#6688](https://github.com/filecoin-project/lotus/pull/6688))
|
||||
- Get retrieval pricing input should not error out on a deal state fetch ([filecoin-project/lotus#6679](https://github.com/filecoin-project/lotus/pull/6679))
|
||||
- Fix more CID double-encoding as hex ([filecoin-project/lotus#6680](https://github.com/filecoin-project/lotus/pull/6680))
|
||||
- storage: Fix FinalizeSector with sectors in stoage paths ([filecoin-project/lotus#6653](https://github.com/filecoin-project/lotus/pull/6653))
|
||||
- Fix tiny error in check-client-datacap ([filecoin-project/lotus#6664](https://github.com/filecoin-project/lotus/pull/6664))
|
||||
- Fix: precommit_batch method used the wrong cfg.CommitBatchWait ([filecoin-project/lotus#6658](https://github.com/filecoin-project/lotus/pull/6658))
|
||||
- fix ticket expiration check ([filecoin-project/lotus#6635](https://github.com/filecoin-project/lotus/pull/6635))
|
||||
- remove precommit check in handleCommitFailed ([filecoin-project/lotus#6634](https://github.com/filecoin-project/lotus/pull/6634))
|
||||
- fix prove commit aggregate send token amount ([filecoin-project/lotus#6625](https://github.com/filecoin-project/lotus/pull/6625))
|
||||
|
||||
## Improvements
|
||||
- Eliminate inefficiency in markets logging ([filecoin-project/lotus#6895](https://github.com/filecoin-project/lotus/pull/6895))
|
||||
- rename `cmd/lotus{-storage=>}-miner` to match binary. ([filecoin-project/lotus#6886](https://github.com/filecoin-project/lotus/pull/6886))
|
||||
- fix racy TestSimultanenousTransferLimit. ([filecoin-project/lotus#6862](https://github.com/filecoin-project/lotus/pull/6862))
|
||||
- ValidateBlock: Assert that block header height's are greater than parents ([filecoin-project/lotus#6872](https://github.com/filecoin-project/lotus/pull/6872))
|
||||
- feat: Don't panic when api impl is nil ([filecoin-project/lotus#6857](https://github.com/filecoin-project/lotus/pull/6857))
|
||||
- add docker-compose file ([filecoin-project/lotus#6544](https://github.com/filecoin-project/lotus/pull/6544))
|
||||
- easy way to make install app ([filecoin-project/lotus#5183](https://github.com/filecoin-project/lotus/pull/5183))
|
||||
- api: Separate the Net interface from Common ([filecoin-project/lotus#6627](https://github.com/filecoin-project/lotus/pull/6627)) - add StateReadState to gateway api ([filecoin-project/lotus#6818](https://github.com/filecoin-project/lotus/pull/6818))
|
||||
- add SealProof in SectorBuilder ([filecoin-project/lotus#6815](https://github.com/filecoin-project/lotus/pull/6815))
|
||||
- sealing: Handle preCommitParams errors more correctly ([filecoin-project/lotus#6763](https://github.com/filecoin-project/lotus/pull/6763))
|
||||
- ClientFindData: always fetch peer id from chain ([filecoin-project/lotus#6807](https://github.com/filecoin-project/lotus/pull/6807))
|
||||
- test: handle null blocks in TestForkRefuseCall ([filecoin-project/lotus#6758](https://github.com/filecoin-project/lotus/pull/6758))
|
||||
- Add more deal details to lotus-miner info ([filecoin-project/lotus#6708](https://github.com/filecoin-project/lotus/pull/6708))
|
||||
- add election backtest ([filecoin-project/lotus#5950](https://github.com/filecoin-project/lotus/pull/5950))
|
||||
- add dollar sign ([filecoin-project/lotus#6690](https://github.com/filecoin-project/lotus/pull/6690))
|
||||
- get-actor cli spelling fix ([filecoin-project/lotus#6681](https://github.com/filecoin-project/lotus/pull/6681))
|
||||
- polish(statetree): accept a context in statetree diff for timeouts ([filecoin-project/lotus#6639](https://github.com/filecoin-project/lotus/pull/6639))
|
||||
- Add helptext to lotus chain export ([filecoin-project/lotus#6672](https://github.com/filecoin-project/lotus/pull/6672))
|
||||
- add an incremental nonce itest. ([filecoin-project/lotus#6663](https://github.com/filecoin-project/lotus/pull/6663))
|
||||
- commit batch: Initialize the FailedSectors map ([filecoin-project/lotus#6647](https://github.com/filecoin-project/lotus/pull/6647))
|
||||
- Fast-path retry submitting commit aggregate if commit is still valid ([filecoin-project/lotus#6638](https://github.com/filecoin-project/lotus/pull/6638))
|
||||
- Reuse timers in sealing batch logic ([filecoin-project/lotus#6636](https://github.com/filecoin-project/lotus/pull/6636))
|
||||
|
||||
## Dependency Updates
|
||||
- Update to proof v8.0.3 ([filecoin-project/lotus#6890](https://github.com/filecoin-project/lotus/pull/6890))
|
||||
- update to go-fil-market v1.6.0 ([filecoin-project/lotus#6885](https://github.com/filecoin-project/lotus/pull/6885))
|
||||
- Bump go-multihash, adjust test for supported version ([filecoin-project/lotus#6674](https://github.com/filecoin-project/lotus/pull/6674))
|
||||
- github.com/filecoin-project/go-data-transfer (v1.6.0 -> v1.7.2):
|
||||
- github.com/filecoin-project/go-fil-markets (v1.5.0 -> v1.6.2):
|
||||
- github.com/filecoin-project/go-padreader (v0.0.0-20200903213702-ed5fae088b20 -> v0.0.0-20210723183308-812a16dc01b1)
|
||||
- github.com/filecoin-project/go-state-types (v0.1.1-0.20210506134452-99b279731c48 -> v0.1.1-0.20210810190654-139e0e79e69e)
|
||||
- github.com/filecoin-project/go-statemachine (v0.0.0-20200925024713-05bd7c71fbfe -> v1.0.1)
|
||||
- update go-libp2p-pubsub to v0.5.0 ([filecoin-project/lotus#6764](https://github.com/filecoin-project/lotus/pull/6764))
|
||||
|
||||
## Others
|
||||
- Master->v1.11.1 ([filecoin-project/lotus#7051](https://github.com/filecoin-project/lotus/pull/7051))
|
||||
- v1.11.1-rc2 ([filecoin-project/lotus#6966](https://github.com/filecoin-project/lotus/pull/6966))
|
||||
- Backport master -> v1.11.1 ([filecoin-project/lotus#6965](https://github.com/filecoin-project/lotus/pull/6965))
|
||||
- Fixes in master -> release ([filecoin-project/lotus#6933](https://github.com/filecoin-project/lotus/pull/6933))
|
||||
- Add changelog for v1.11.1-rc1 and bump the version ([filecoin-project/lotus#6900](https://github.com/filecoin-project/lotus/pull/6900))
|
||||
- Fix merge release -> v1.11.1 ([filecoin-project/lotus#6897](https://github.com/filecoin-project/lotus/pull/6897))
|
||||
- Update RELEASE_ISSUE_TEMPLATE.md ([filecoin-project/lotus#6880](https://github.com/filecoin-project/lotus/pull/6880))
|
||||
- Add github actions for staled pr ([filecoin-project/lotus#6879](https://github.com/filecoin-project/lotus/pull/6879))
|
||||
- Update issue templates and add templates for M1 ([filecoin-project/lotus#6856](https://github.com/filecoin-project/lotus/pull/6856))
|
||||
- Fix links in issue templates
|
||||
- Update issue templates to forms ([filecoin-project/lotus#6798](https://github.com/filecoin-project/lotus/pull/6798)
|
||||
- Nerpa v13 upgrade ([filecoin-project/lotus#6837](https://github.com/filecoin-project/lotus/pull/6837))
|
||||
- add docker-compose file ([filecoin-project/lotus#6544](https://github.com/filecoin-project/lotus/pull/6544))
|
||||
- release -> master ([filecoin-project/lotus#6828](https://github.com/filecoin-project/lotus/pull/6828))
|
||||
- Resurrect CODEOWNERS, but for maintainers group ([filecoin-project/lotus#6773](https://github.com/filecoin-project/lotus/pull/6773))
|
||||
- Master disclaimer ([filecoin-project/lotus#6757](https://github.com/filecoin-project/lotus/pull/6757))
|
||||
- Create stale.yml ([filecoin-project/lotus#6747](https://github.com/filecoin-project/lotus/pull/6747))
|
||||
- Release template: Update all testnet infra at once ([filecoin-project/lotus#6710](https://github.com/filecoin-project/lotus/pull/6710))
|
||||
- Release Template: remove binary validation step ([filecoin-project/lotus#6709](https://github.com/filecoin-project/lotus/pull/6709))
|
||||
- Reset of the interop network ([filecoin-project/lotus#6689](https://github.com/filecoin-project/lotus/pull/6689))
|
||||
- Update version.go to 1.11.1 ([filecoin-project/lotus#6621](https://github.com/filecoin-project/lotus/pull/6621))
|
||||
|
||||
## Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| @vyzo | 313 | +8928/-6010 | 415 |
|
||||
| @nonsense | 103 | +6041/-4041 | 304 |
|
||||
| @magik6k | 37 | +3851/-1611 | 146 |
|
||||
| @ZenGround0 | 24 | +1693/-1394 | 95 |
|
||||
| @placer14 | 1 | +2310/-578 | 8 |
|
||||
| @dirkmc | 7 | +1154/-726 | 29 |
|
||||
| @raulk | 44 | +969/-616 | 141 |
|
||||
| @jennijuju | 15 | +682/-354 | 47 |
|
||||
| @ribasushi | 18 | +469/-273 | 64 |
|
||||
| @coryschwartz | 5 | +576/-135 | 14 |
|
||||
| @hunjixin | 7 | +404/-82 | 19 |
|
||||
| @dirkmc | 17 | +348/-47 | 17 |
|
||||
| @tchardin | 2 | +262/-34 | 5 |
|
||||
| @aarshkshah1992 | 9 | +233/-63 | 44 |
|
||||
| @Kubuxu | 4 | +254/-16 | 4 |
|
||||
| @hannahhoward | 6 | +163/-75 | 8 |
|
||||
| @whyrusleeping | 4 | +157/-16 | 9 |
|
||||
| @Whyrusleeping | 2 | +87/-66 | 10 |
|
||||
| @arajasek | 10 | +81/-53 | 13 |
|
||||
| @zgfzgf | 2 | +104/-4 | 2 |
|
||||
| @aarshkshah1992 | 6 | +85/-19 | 10 |
|
||||
| @llifezou | 4 | +59/-20 | 4 |
|
||||
| @Stebalien | 7 | +47/-17 | 9 |
|
||||
| @johnli-helloworld | 3 | +46/-15 | 5 |
|
||||
| @frrist | 1 | +28/-23 | 2 |
|
||||
| @hannahhoward | 4 | +46/-5 | 11 |
|
||||
| @Jennifer | 4 | +31/-2 | 4 |
|
||||
| @wangchao | 1 | +1/-27 | 1 |
|
||||
| @jennijuju | 2 | +7/-21 | 2 |
|
||||
| @chadwick2143 | 1 | +15/-1 | 1 |
|
||||
| @Jerry | 2 | +9/-4 | 2 |
|
||||
| Steve Loeppky | 2 | +12/-0 | 2 |
|
||||
| David Dias | 1 | +9/-0 | 1 |
|
||||
| dependabot[bot] | 1 | +3/-3 | 1 |
|
||||
| zhoutian527 | 1 | +2/-2 | 1 |
|
||||
| xloem | 1 | +4/-0 | 1 |
|
||||
| Travis Person | 2 | +2/-2 | 3 |
|
||||
| @travisperson| 2 | +2/-2 | 3 |
|
||||
| Liviu Damian | 2 | +2/-2 | 2 |
|
||||
| Jim Pick | 2 | +2/-2 | 2 |
|
||||
| @jimpick | 2 | +2/-2 | 2 |
|
||||
| Frank | 1 | +3/-0 | 1 |
|
||||
| turuslan | 1 | +1/-1 | 1 |
|
||||
| Kirk Baird | 1 | +0/-0 | 1 |
|
||||
|
||||
|
||||
|
||||
# 1.11.0 / 2021-07-22
|
||||
|
||||
This is a **highly recommended** release of Lotus that have many bug fixes, improvements and new features.
|
||||
@@ -432,13 +577,6 @@ Contributors
|
||||
| @zhoutian527 | 1 | +2/-2 | 1 |
|
||||
| @ribasushi| 1 | +1/-1 | 1 |
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
||||||| merged common ancestors
|
||||
>>>>>>>>> Temporary merge branch 2
|
||||
=======
|
||||
>>>>>>> releases
|
||||
>>>>>>> releases
|
||||
# 1.10.0 / 2021-06-23
|
||||
|
||||
This is a mandatory release of Lotus that introduces Filecoin network v13, codenamed the HyperDrive upgrade. The
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
- [`lotus` Release Flow](#lotus-release-flow)
|
||||
- [Purpose](#purpose)
|
||||
- [High-level Summary](#high-level-summary)
|
||||
- [Motivation and Requirements](#motivation-and-requirements)
|
||||
- [Adopted Conventions](#adopted-conventions)
|
||||
- [Major Releases](#major-releases)
|
||||
- [Mandatory Releases](#mandatory-releases)
|
||||
- [Feature Releases](#feature-releases)
|
||||
- [Examples Scenarios](#examples-scenarios)
|
||||
- [Release Cycle](#release-cycle)
|
||||
- [Patch Releases](#patch-releases)
|
||||
- [Performing a Release](#performing-a-release)
|
||||
- [Security Fix Policy](#security-fix-policy)
|
||||
- [FAQ](#faq)
|
||||
- [Why aren't Go major versions used more?](#why-arent-go-major-versions-used-more)
|
||||
- [Related Items](#related-items)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
# `lotus` Release Flow
|
||||
|
||||
## Purpose
|
||||
|
||||
This document aims to describe how the Lotus team plans to ship releases of the Lotus implementation of Filecoin network. Interested parties can expect new releases to come out as described in this document.
|
||||
|
||||
## High-level Summary
|
||||
|
||||
- **Major releases** (1.0.0, 2.0.0, etc.) are reserved for significant changes to the Filecoin protocol that transform the network and its usecases. Such changes could include the addition of new Virtual Machines to the protocol, major upgrades to the Proofs of Replication used by Filecoin, etc.
|
||||
- Even minor releases (1.2.0, 1.4.0, etc.) of the Lotus software correspond to **mandatory releases** as they ship Filecoin network upgrades. Users **must** upgrade to these releases before a certain time in order to keep in sync with the Filecoin network. We aim to ensure there is at least one week before the upgrade deadline.
|
||||
- Patch versions of even minor releases (1.2.1, 1.4.2, etc.) correspond to **hotfix releases**. Such releases will only be shipped when a critical fix is needed to be applied on top of a mandatory release.
|
||||
- Odd minor releases (1.3.0, 1.5.0, etc.), as well as patch releases in these series (1.3.1, 1.5.2, etc.) correspond to **feature releases** with new development and bugfixes. These releases are not mandatory, but still highly recommended, **as they may contain critical security fixes**.
|
||||
- We aim to ship a new feature release of the Lotus software every 3 weeks, so users can expect a regular cadence of Lotus feature releases. Note that mandatory releases for network upgrades may disrupt this schedule.
|
||||
|
||||
## Motivation and Requirements
|
||||
|
||||
Our primary motivation is for users of the Lotus software (storage providers, storage clients, developers, etc.) to have a clear idea about when they can expect Lotus releases, and what they can expect in a release.
|
||||
|
||||
In order to achieve this, we need the following from our release process and conventions:
|
||||
|
||||
- Lotus version conventions make it immediately obvious whether a new Lotus release is mandatory or not. A release is mandatory if it ships a network upgrade to the Filecoin protocol.
|
||||
- The ability to ship critical fixes on top of mandatory releases, so as to avoid forcing users to consume larger unrelated changes.
|
||||
- A regular cadence of feature releases, so that users can know when a new Lotus release will be available for consumption.
|
||||
- The ability to ship any number of feature releases between two mandatory releases.
|
||||
- A clear description of the various stages of testing that a Lotus Release Candidate (RC) goes through.
|
||||
- Lotus Release issues will present a single source of truth for what may be contained in Lotus releases, including security fixes, and how they will be disclosed.
|
||||
|
||||
## Adopted Conventions
|
||||
|
||||
This section describes the conventions we have adopted. Users of Lotus are encouraged to review this in detail so as to be informed when new Lotus releases are shipped.
|
||||
|
||||
### Major Releases
|
||||
|
||||
Bumps to the Lotus major version number (1.0.0, 2.0.0, etc.) are reserved for significant changes to the Filecoin protocol that dramatically transform the network itself. Such changes could include the addition of new Virtual Machines to the protocol, major upgrades to the Proofs of Replication used by Filecoin, etc. These releases are expected to take lots of time to develop and will be rare. See also "Why aren't Go major versions used more?" below.
|
||||
|
||||
### Mandatory Releases
|
||||
|
||||
Even bumps to the Lotus minor version number (1.2.0, 1.4.0, etc.) are reserved for **mandatory releases** that ship Filecoin network upgrades. Users **must** upgrade to these releases before a certain time in order to keep in sync with the Filecoin network.
|
||||
|
||||
Depending on the scope of the upgrade, these releases may take up to several weeks to fully develop and test. We aim to ensure there are at least 2 weeks between the publication of the final Lotus release and the Filecoin network upgrade deadline.
|
||||
|
||||
These releases do not follow a regular cadence, as they are developed in lockstep with the other implementations of the Filecoin protocol. As of August 2021, the developers aim to ship 3-4 Filecoin network upgrades a year, though smaller security-critical upgrades may occur unpredictably.
|
||||
|
||||
Mandatory releases are somewhat sensitive since all Lotus users are forced to upgrade to them at the same time. As a result, they will be shipped on top of the most recent stable release of Lotus, which will generally be the latest Lotus release that has been in production for more than 2 weeks. (Note: given this rule, the basis of a mandatory release could be a mandatory release or a feature release depending on timing). Mandatory releases will not include any new feature development or bugfixes that haven't already baked in production for 2+ weeks, except for the changes needed for the network upgrade itself. Further, any critical fixes that are needed after the network upgrade will be shipped as patch version bumps to the mandatory release (1.2.1, 1.2.2, etc.) This prevents users from being forced to quickly digest unnecessary changes.
|
||||
|
||||
Users should generally aim to always upgrade to a new even minor version release since they either introduce a mandatory network upgrade or a critical fix.
|
||||
|
||||
### Feature Releases
|
||||
|
||||
All releases under an odd minor version number indicate **feature releases**. These could include releases such as 1.3.0, 1.3.1, 1.5.2, etc.
|
||||
|
||||
Feature releases include new development and bug fixes. They are not mandatory, but still highly recommended, **as they may contain critical security fixes**. Note that some of these releases may be very small patch releases that include critical hotfixes. There is no way to distinguish between a bug fix release and a feature release on the "feature" version. Both cases will use the "patch" version number.
|
||||
|
||||
We aim to ship a new feature release of the Lotus software from our development (master) branch every 3 weeks, so users can expect a regular cadence of Lotus feature releases. Note that mandatory releases for network upgrades may disrupt this schedule. For more, see the Release Cycle section (TODO: Link).
|
||||
|
||||
### Examples Scenarios
|
||||
|
||||
- **Scenario 1**: **Lotus 1.12.0 shipped a network upgrade, and no network upgrades are needed for a long while.**
|
||||
|
||||
In this case, the next feature release will be Lotus 1.13.0. In three-week intervals, we will ship Lotus 1.13.1, 1.13.2, and 1.13.3, all containing new features and bug fixes.
|
||||
|
||||
Let us assume that after the release of 1.13.3, a critical issue is discovered and a hotfix quickly developed. This hotfix will then be shipped in **both** 1.12.1 and 1.13.4. Users who have already upgrade to the 1.13 series can simply upgrade to 1.13.4. Users who have chosen to still be on 1.12.0, however, can use 1.12.1 to patch the critical issue without being forced to consume all the changes in the 1.13 series.
|
||||
|
||||
- **Scenario 2**: **Lotus 1.12.0 shipped a network upgrade, but the need for an unexpected network upgrade soon arises**
|
||||
|
||||
In this case, the Lotus 1.13 series will be dropped entirely, including any RCs that may have been undergoing testing. Instead, the network upgrade will be shipped as Lotus 1.14.0, built on top of Lotus 1.12.0. It will thus include no unnecessary changes, only the work needed to support the new network upgrade.
|
||||
|
||||
Any changes that were being worked on in the 1.13.0 series will then get applied on top of Lotus 1.14.0 and get shipped as Lotus 1.15.0.
|
||||
|
||||
## Release Cycle
|
||||
|
||||
A mandatory release process should take about 3-6 weeks, depending on the amount and the overall complexity of new features being introduced to the network protocol. It may also be shorter if there is a network incident that requires an emergency upgrade. A feature release process should take about 2-3 weeks.
|
||||
|
||||
The start time of the mandatory release process is subject to the network upgrade timeline. We will start a new feature release process every 3 weeks on Tuesdays, regardless of when the previous release landed unless it's still ongoing.
|
||||
|
||||
### Patch Releases
|
||||
|
||||
**Mandatory Release**
|
||||
|
||||
If we encounter a serious bug in a mandatory release post a network upgrade, we will create a patch release based on this release. Strictly only the fix to the bug will be included in the patch, and the bug fix will be backported to the master (dev) branch, and any ongoing feature release branch if applicable.
|
||||
|
||||
Patch release process for the mandatory releases will follow a compressed release cycle from hours to days depending on the severity and the impact to the network of the bug. In a patch release:
|
||||
|
||||
1. Automated and internal testing (stage 0 and 1) will be compressed into a few hours.
|
||||
2. Stage 2-3 will be skipped or shortened case by case.
|
||||
|
||||
Some patch releases, especially ones fixing one or more complex bugs that doesn't require a follow-up mandatory upgrade, may undergo the full release process.
|
||||
|
||||
**Feature Release**
|
||||
|
||||
Patch releases in odd minor releases (1.3.0, 1.5.0, etc.) like 1.3.1, 1.5.2 and etc are corresponding to another **feature releases** with new development and bugfixes. These releases are not mandatory, but still **highly** recommended, **as they may contain critical security fixes**.
|
||||
|
||||
---
|
||||
|
||||
### Performing a Release
|
||||
|
||||
At the beginning of each release cycle, we will generate our "Release tracking issue", which is populated with the content at [https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md](https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md)
|
||||
|
||||
This template will be used to track major goals we have, a planned shipping date, and a complete release checklist tied to a specific release.
|
||||
|
||||
### Security Fix Policy
|
||||
|
||||
Any release may contain security fixes. Unless the fix addresses a bug being exploited in the wild, the fix will *not* be called out in the release notes. Please make sure to update ASAP.
|
||||
|
||||
By policy, the team will usually wait until about 3 weeks after the final release to announce any fixed security issues. However, depending on the impact and ease of discovery of the issue, the team may wait more or less time.
|
||||
|
||||
It is important to always update to the latest version ASAP and file issues if you're unable to update for some reason.
|
||||
|
||||
Finally, unless a security issue is actively being exploited or a significant number of users are unable to update to the latest version (e.g., due to a difficult migration, breaking changes, etc.), security fixes will *not* be backported to previous releases.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why aren't Go major versions used more?
|
||||
|
||||
Golang tightly couples source code with versioning (major versions beyond v1 leak into import paths). This poses logistical difficulties to using major versions here. Concretely, if we were to pick a policy that bumped the major version on every network upgrade, we would disrupt every single downstream library/application that consumed the native Lotus API (e.g., libraries depending on the JSON-RPC client, testground tests). They would need to update their code every single time that we released a network breaking change, even if it brought on zero expectation of breakage for the Golang APIs that they depend on. In this scenario, we are signaling breakage on the wrong API surface! We're signaling breakage on the Go level, when what breaks is the network protocol.
|
||||
|
||||
## Related Items
|
||||
|
||||
1. [Release Issue template](https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md)
|
||||
2. [Lotus Release Flow Discussion](https://github.com/filecoin-project/lotus/discussions/7053): Leave a comment if you have any questions or feedbacks with regard to the lotus release flow.
|
||||
@@ -5,7 +5,9 @@ all: build
|
||||
|
||||
unexport GOFLAGS
|
||||
|
||||
GOVERSION:=$(shell go version | cut -d' ' -f 3 | sed 's/^go//' | awk -F. '{printf "%d%03d%03d", $$1, $$2, $$3}')
|
||||
GOCC?=go
|
||||
|
||||
GOVERSION:=$(shell $(GOCC) version | tr ' ' '\n' | grep go1 | sed 's/^go//' | awk -F. '{printf "%d%03d%03d", $$1, $$2, $$3}')
|
||||
ifeq ($(shell expr $(GOVERSION) \< 1016000), 1)
|
||||
$(warning Your Golang version is go$(shell expr $(GOVERSION) / 1000000).$(shell expr $(GOVERSION) % 1000000 / 1000).$(shell expr $(GOVERSION) % 1000))
|
||||
$(error Update Golang to version to at least 1.16.0)
|
||||
@@ -85,32 +87,32 @@ interopnet: build-devnets
|
||||
|
||||
lotus: $(BUILD_DEPS)
|
||||
rm -f lotus
|
||||
go build $(GOFLAGS) -o lotus ./cmd/lotus
|
||||
$(GOCC) build $(GOFLAGS) -o lotus ./cmd/lotus
|
||||
|
||||
.PHONY: lotus
|
||||
BINS+=lotus
|
||||
|
||||
lotus-miner: $(BUILD_DEPS)
|
||||
rm -f lotus-miner
|
||||
go build $(GOFLAGS) -o lotus-miner ./cmd/lotus-miner
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-miner ./cmd/lotus-miner
|
||||
.PHONY: lotus-miner
|
||||
BINS+=lotus-miner
|
||||
|
||||
lotus-worker: $(BUILD_DEPS)
|
||||
rm -f lotus-worker
|
||||
go build $(GOFLAGS) -o lotus-worker ./cmd/lotus-seal-worker
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-worker ./cmd/lotus-seal-worker
|
||||
.PHONY: lotus-worker
|
||||
BINS+=lotus-worker
|
||||
|
||||
lotus-shed: $(BUILD_DEPS)
|
||||
rm -f lotus-shed
|
||||
go build $(GOFLAGS) -o lotus-shed ./cmd/lotus-shed
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-shed ./cmd/lotus-shed
|
||||
.PHONY: lotus-shed
|
||||
BINS+=lotus-shed
|
||||
|
||||
lotus-gateway: $(BUILD_DEPS)
|
||||
rm -f lotus-gateway
|
||||
go build $(GOFLAGS) -o lotus-gateway ./cmd/lotus-gateway
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-gateway ./cmd/lotus-gateway
|
||||
.PHONY: lotus-gateway
|
||||
BINS+=lotus-gateway
|
||||
|
||||
@@ -138,19 +140,19 @@ install-app:
|
||||
|
||||
lotus-seed: $(BUILD_DEPS)
|
||||
rm -f lotus-seed
|
||||
go build $(GOFLAGS) -o lotus-seed ./cmd/lotus-seed
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-seed ./cmd/lotus-seed
|
||||
|
||||
.PHONY: lotus-seed
|
||||
BINS+=lotus-seed
|
||||
|
||||
benchmarks:
|
||||
go run github.com/whyrusleeping/bencher ./... > bench.json
|
||||
$(GOCC) run github.com/whyrusleeping/bencher ./... > bench.json
|
||||
@echo Submitting results
|
||||
@curl -X POST 'http://benchmark.kittyhawk.wtf/benchmark' -d '@bench.json' -u "${benchmark_http_cred}"
|
||||
.PHONY: benchmarks
|
||||
|
||||
lotus-pond: 2k
|
||||
go build -o lotus-pond ./lotuspond
|
||||
$(GOCC) build -o lotus-pond ./lotuspond
|
||||
.PHONY: lotus-pond
|
||||
BINS+=lotus-pond
|
||||
|
||||
@@ -161,85 +163,64 @@ lotus-pond-front:
|
||||
lotus-pond-app: lotus-pond-front lotus-pond
|
||||
.PHONY: lotus-pond-app
|
||||
|
||||
lotus-townhall:
|
||||
rm -f lotus-townhall
|
||||
go build -o lotus-townhall ./cmd/lotus-townhall
|
||||
.PHONY: lotus-townhall
|
||||
BINS+=lotus-townhall
|
||||
|
||||
lotus-townhall-front:
|
||||
(cd ./cmd/lotus-townhall/townhall && npm i && npm run build)
|
||||
.PHONY: lotus-townhall-front
|
||||
|
||||
lotus-townhall-app: lotus-touch lotus-townhall-front
|
||||
.PHONY: lotus-townhall-app
|
||||
|
||||
lotus-fountain:
|
||||
rm -f lotus-fountain
|
||||
go build -o lotus-fountain ./cmd/lotus-fountain
|
||||
go build $(GOFLAGS) -o lotus-fountain ./cmd/lotus-fountain
|
||||
go run github.com/GeertJohan/go.rice/rice append --exec lotus-fountain -i ./cmd/lotus-fountain -i ./build
|
||||
.PHONY: lotus-fountain
|
||||
BINS+=lotus-fountain
|
||||
|
||||
lotus-chainwatch:
|
||||
rm -f lotus-chainwatch
|
||||
go build $(GOFLAGS) -o lotus-chainwatch ./cmd/lotus-chainwatch
|
||||
.PHONY: lotus-chainwatch
|
||||
BINS+=lotus-chainwatch
|
||||
|
||||
lotus-bench:
|
||||
rm -f lotus-bench
|
||||
go build -o lotus-bench ./cmd/lotus-bench
|
||||
$(GOCC) build -o lotus-bench ./cmd/lotus-bench
|
||||
.PHONY: lotus-bench
|
||||
BINS+=lotus-bench
|
||||
|
||||
lotus-stats:
|
||||
rm -f lotus-stats
|
||||
go build $(GOFLAGS) -o lotus-stats ./cmd/lotus-stats
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-stats ./cmd/lotus-stats
|
||||
.PHONY: lotus-stats
|
||||
BINS+=lotus-stats
|
||||
|
||||
lotus-pcr:
|
||||
rm -f lotus-pcr
|
||||
go build $(GOFLAGS) -o lotus-pcr ./cmd/lotus-pcr
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-pcr ./cmd/lotus-pcr
|
||||
.PHONY: lotus-pcr
|
||||
BINS+=lotus-pcr
|
||||
|
||||
lotus-health:
|
||||
rm -f lotus-health
|
||||
go build -o lotus-health ./cmd/lotus-health
|
||||
$(GOCC) build -o lotus-health ./cmd/lotus-health
|
||||
.PHONY: lotus-health
|
||||
BINS+=lotus-health
|
||||
|
||||
lotus-wallet:
|
||||
rm -f lotus-wallet
|
||||
go build -o lotus-wallet ./cmd/lotus-wallet
|
||||
$(GOCC) build -o lotus-wallet ./cmd/lotus-wallet
|
||||
.PHONY: lotus-wallet
|
||||
BINS+=lotus-wallet
|
||||
|
||||
lotus-keygen:
|
||||
rm -f lotus-keygen
|
||||
go build -o lotus-keygen ./cmd/lotus-keygen
|
||||
$(GOCC) build -o lotus-keygen ./cmd/lotus-keygen
|
||||
.PHONY: lotus-keygen
|
||||
BINS+=lotus-keygen
|
||||
|
||||
testground:
|
||||
go build -tags testground -o /dev/null ./cmd/lotus
|
||||
$(GOCC) build -tags testground -o /dev/null ./cmd/lotus
|
||||
.PHONY: testground
|
||||
BINS+=testground
|
||||
|
||||
|
||||
tvx:
|
||||
rm -f tvx
|
||||
go build -o tvx ./cmd/tvx
|
||||
$(GOCC) build -o tvx ./cmd/tvx
|
||||
.PHONY: tvx
|
||||
BINS+=tvx
|
||||
|
||||
install-chainwatch: lotus-chainwatch
|
||||
install -C ./lotus-chainwatch /usr/local/bin/lotus-chainwatch
|
||||
|
||||
lotus-sim: $(BUILD_DEPS)
|
||||
rm -f lotus-sim
|
||||
go build $(GOFLAGS) -o lotus-sim ./cmd/lotus-sim
|
||||
$(GOCC) build $(GOFLAGS) -o lotus-sim ./cmd/lotus-sim
|
||||
.PHONY: lotus-sim
|
||||
BINS+=lotus-sim
|
||||
|
||||
@@ -261,21 +242,13 @@ install-miner-service: install-miner install-daemon-service
|
||||
@echo
|
||||
@echo "lotus-miner service installed. Don't forget to run 'sudo systemctl start lotus-miner' to start it and 'sudo systemctl enable lotus-miner' for it to be enabled on startup."
|
||||
|
||||
install-chainwatch-service: install-chainwatch install-daemon-service
|
||||
mkdir -p /etc/systemd/system
|
||||
mkdir -p /var/log/lotus
|
||||
install -C -m 0644 ./scripts/lotus-chainwatch.service /etc/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
@echo
|
||||
@echo "chainwatch service installed. Don't forget to run 'sudo systemctl start lotus-chainwatch' to start it and 'sudo systemctl enable lotus-chainwatch' for it to be enabled on startup."
|
||||
|
||||
install-main-services: install-miner-service
|
||||
|
||||
install-all-services: install-main-services install-chainwatch-service
|
||||
install-all-services: install-main-services
|
||||
|
||||
install-services: install-main-services
|
||||
|
||||
clean-daemon-service: clean-miner-service clean-chainwatch-service
|
||||
clean-daemon-service: clean-miner-service
|
||||
-systemctl stop lotus-daemon
|
||||
-systemctl disable lotus-daemon
|
||||
rm -f /etc/systemd/system/lotus-daemon.service
|
||||
@@ -287,12 +260,6 @@ clean-miner-service:
|
||||
rm -f /etc/systemd/system/lotus-miner.service
|
||||
systemctl daemon-reload
|
||||
|
||||
clean-chainwatch-service:
|
||||
-systemctl stop lotus-chainwatch
|
||||
-systemctl disable lotus-chainwatch
|
||||
rm -f /etc/systemd/system/lotus-chainwatch.service
|
||||
systemctl daemon-reload
|
||||
|
||||
clean-main-services: clean-daemon-service
|
||||
|
||||
clean-all-services: clean-main-services
|
||||
@@ -319,25 +286,25 @@ dist-clean:
|
||||
.PHONY: dist-clean
|
||||
|
||||
type-gen: api-gen
|
||||
go run ./gen/main.go
|
||||
go generate -x ./...
|
||||
$(GOCC) run ./gen/main.go
|
||||
$(GOCC) generate -x ./...
|
||||
goimports -w api/
|
||||
|
||||
method-gen: api-gen
|
||||
(cd ./lotuspond/front/src/chain && go run ./methodgen.go)
|
||||
(cd ./lotuspond/front/src/chain && $(GOCC) run ./methodgen.go)
|
||||
|
||||
actors-gen:
|
||||
go run ./chain/actors/agen
|
||||
go fmt ./...
|
||||
$(GOCC) run ./chain/actors/agen
|
||||
$(GOCC) fmt ./...
|
||||
|
||||
api-gen:
|
||||
go run ./gen/api
|
||||
$(GOCC) run ./gen/api
|
||||
goimports -w api
|
||||
goimports -w api
|
||||
.PHONY: api-gen
|
||||
|
||||
cfgdoc-gen:
|
||||
go run ./node/config/cfgdocgen > ./node/config/doc_gen.go
|
||||
$(GOCC) run ./node/config/cfgdocgen > ./node/config/doc_gen.go
|
||||
|
||||
appimage: lotus
|
||||
rm -rf appimage-builder-cache || true
|
||||
@@ -351,9 +318,9 @@ appimage: lotus
|
||||
docsgen: docsgen-md docsgen-openrpc
|
||||
|
||||
docsgen-md-bin: api-gen actors-gen
|
||||
go build $(GOFLAGS) -o docgen-md ./api/docgen/cmd
|
||||
$(GOCC) build $(GOFLAGS) -o docgen-md ./api/docgen/cmd
|
||||
docsgen-openrpc-bin: api-gen actors-gen
|
||||
go build $(GOFLAGS) -o docgen-openrpc ./api/docgen-openrpc/cmd
|
||||
$(GOCC) build $(GOFLAGS) -o docgen-openrpc ./api/docgen-openrpc/cmd
|
||||
|
||||
docsgen-md: docsgen-md-full docsgen-md-storage docsgen-md-worker
|
||||
|
||||
|
||||
+29
-9
@@ -12,14 +12,14 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
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"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
|
||||
apitypes "github.com/filecoin-project/lotus/api/types"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
@@ -29,6 +29,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/imports"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_full.go -package=mocks . FullNode
|
||||
@@ -113,6 +114,11 @@ type FullNode interface {
|
||||
// will be returned.
|
||||
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) //perm:read
|
||||
|
||||
// ChainGetTipSetAfterHeight looks back for a tipset at the specified epoch.
|
||||
// If there are no blocks at the specified epoch, the first non-nil tipset at a later epoch
|
||||
// will be returned.
|
||||
ChainGetTipSetAfterHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) //perm:read
|
||||
|
||||
// ChainReadObj reads ipld nodes referenced by the specified CID from chain
|
||||
// blockstore and returns raw bytes.
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error) //perm:read
|
||||
@@ -331,7 +337,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 imports.ID) 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.
|
||||
@@ -428,6 +434,8 @@ type FullNode interface {
|
||||
StateListMessages(ctx context.Context, match *MessageMatch, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) //perm:read
|
||||
// StateDecodeParams attempts to decode the provided params, based on the recipient actor address and method number.
|
||||
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error) //perm:read
|
||||
// StateEncodeParams attempts to encode the provided json params to the binary from
|
||||
StateEncodeParams(ctx context.Context, toActCode cid.Cid, method abi.MethodNum, params json.RawMessage) ([]byte, error) //perm:read
|
||||
|
||||
// StateNetworkName returns the name of the network the node is synced to
|
||||
StateNetworkName(context.Context) (dtypes.NetworkName, error) //perm:read
|
||||
@@ -723,16 +731,28 @@ type MinerSectors struct {
|
||||
|
||||
type ImportRes struct {
|
||||
Root cid.Cid
|
||||
ImportID multistore.StoreID
|
||||
ImportID imports.ID
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Key multistore.StoreID
|
||||
Key imports.ID
|
||||
Err string
|
||||
|
||||
Root *cid.Cid
|
||||
Source string
|
||||
Root *cid.Cid
|
||||
|
||||
// Source is the provenance of the import, e.g. "import", "unknown", else.
|
||||
// Currently useless but may be used in the future.
|
||||
Source string
|
||||
|
||||
// FilePath is the path of the original file. It is important that the file
|
||||
// is retained at this path, because it will be referenced during
|
||||
// the transfer (when we do the UnixFS chunking, we don't duplicate the
|
||||
// leaves, but rather point to chunks of the original data through
|
||||
// positional references).
|
||||
FilePath string
|
||||
|
||||
// CARPath is the path of the CAR file containing the DAG for this import.
|
||||
CARPath string
|
||||
}
|
||||
|
||||
type DealInfo struct {
|
||||
@@ -915,7 +935,7 @@ type RetrievalOrder struct {
|
||||
Piece *cid.Cid
|
||||
Size uint64
|
||||
|
||||
LocalStore *multistore.StoreID // if specified, get data from local store
|
||||
FromLocalCAR string // if specified, get data from a local CARv2 file.
|
||||
// TODO: support offset
|
||||
Total types.BigInt
|
||||
UnsealPrice types.BigInt
|
||||
|
||||
@@ -35,6 +35,7 @@ type Gateway interface {
|
||||
ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)
|
||||
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainNotify(context.Context) (<-chan []*HeadChange, error)
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
|
||||
+77
-3
@@ -13,13 +13,14 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"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/specs-actors/v2/actors/builtin/market"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/fsutil"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
@@ -166,6 +167,48 @@ type StorageMiner interface {
|
||||
MarketPendingDeals(ctx context.Context) (PendingDealInfo, error) //perm:write
|
||||
MarketPublishPendingDeals(ctx context.Context) error //perm:admin
|
||||
|
||||
// DagstoreListShards returns information about all shards known to the
|
||||
// DAG store. Only available on nodes running the markets subsystem.
|
||||
DagstoreListShards(ctx context.Context) ([]DagstoreShardInfo, error) //perm:read
|
||||
|
||||
// DagstoreInitializeShard initializes an uninitialized shard.
|
||||
//
|
||||
// Initialization consists of fetching the shard's data (deal payload) from
|
||||
// the storage subsystem, generating an index, and persisting the index
|
||||
// to facilitate later retrievals, and/or to publish to external sources.
|
||||
//
|
||||
// This operation is intended to complement the initial migration. The
|
||||
// migration registers a shard for every unique piece CID, with lazy
|
||||
// initialization. Thus, shards are not initialized immediately to avoid
|
||||
// IO activity competing with proving. Instead, shard are initialized
|
||||
// when first accessed. This method forces the initialization of a shard by
|
||||
// accessing it and immediately releasing it. This is useful to warm up the
|
||||
// cache to facilitate subsequent retrievals, and to generate the indexes
|
||||
// to publish them externally.
|
||||
//
|
||||
// This operation fails if the shard is not in ShardStateNew state.
|
||||
// It blocks until initialization finishes.
|
||||
DagstoreInitializeShard(ctx context.Context, key string) error //perm:write
|
||||
|
||||
// DagstoreRecoverShard attempts to recover a failed shard.
|
||||
//
|
||||
// This operation fails if the shard is not in ShardStateErrored state.
|
||||
// It blocks until recovery finishes. If recovery failed, it returns the
|
||||
// error.
|
||||
DagstoreRecoverShard(ctx context.Context, key string) error //perm:write
|
||||
|
||||
// DagstoreInitializeAll initializes all uninitialized shards in bulk,
|
||||
// according to the policy passed in the parameters.
|
||||
//
|
||||
// It is recommended to set a maximum concurrency to avoid extreme
|
||||
// IO pressure if the storage subsystem has a large amount of deals.
|
||||
//
|
||||
// It returns a stream of events to report progress.
|
||||
DagstoreInitializeAll(ctx context.Context, params DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) //perm:write
|
||||
|
||||
// DagstoreGC runs garbage collection on the DAG store.
|
||||
DagstoreGC(ctx context.Context) ([]DagstoreShardResult, error) //perm:admin
|
||||
|
||||
// RuntimeSubsystems returns the subsystems that are enabled
|
||||
// in this instance.
|
||||
RuntimeSubsystems(ctx context.Context) (MinerSubsystems, error) //perm:read
|
||||
@@ -336,3 +379,34 @@ type DealSchedule struct {
|
||||
StartEpoch abi.ChainEpoch
|
||||
EndEpoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
// DagstoreShardInfo is the serialized form of dagstore.DagstoreShardInfo that
|
||||
// we expose through JSON-RPC to avoid clients having to depend on the
|
||||
// dagstore lib.
|
||||
type DagstoreShardInfo struct {
|
||||
Key string
|
||||
State string
|
||||
Error string
|
||||
}
|
||||
|
||||
// DagstoreShardResult enumerates results per shard.
|
||||
type DagstoreShardResult struct {
|
||||
Key string
|
||||
Success bool
|
||||
Error string
|
||||
}
|
||||
|
||||
type DagstoreInitializeAllParams struct {
|
||||
MaxConcurrency int
|
||||
IncludeSealed bool
|
||||
}
|
||||
|
||||
// DagstoreInitializeAllEvent represents an initialization event.
|
||||
type DagstoreInitializeAllEvent struct {
|
||||
Key string
|
||||
Event string // "start", "end"
|
||||
Success bool
|
||||
Error string
|
||||
Total int
|
||||
Current int
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ func TestReturnTypes(t *testing.T) {
|
||||
seen[typ] = struct{}{}
|
||||
|
||||
if typ.Kind() == reflect.Interface && typ != bareIface && !typ.Implements(jmarsh) {
|
||||
t.Error("methods can't return interfaces", m.Name)
|
||||
t.Error("methods can't return interfaces or struct types not implementing json.Marshaller", m.Name)
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
|
||||
@@ -5,6 +5,7 @@ package api
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
var _ = cid.Undef
|
||||
var _ = math.E
|
||||
var _ = sort.Sort
|
||||
|
||||
func (t *PaymentInfo) MarshalCBOR(w io.Writer) error {
|
||||
|
||||
+15
-2
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-multistore"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-filestore"
|
||||
@@ -27,7 +28,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"
|
||||
@@ -43,6 +43,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
)
|
||||
|
||||
var ExampleValues = map[reflect.Type]interface{}{
|
||||
@@ -90,6 +91,7 @@ func init() {
|
||||
addExample(&pid)
|
||||
|
||||
multistoreIDExample := multistore.StoreID(50)
|
||||
storeIDExample := imports.ID(50)
|
||||
|
||||
addExample(bitfield.NewFromSet([]uint64{5}))
|
||||
addExample(abi.RegisteredSealProof_StackedDrg32GiBV1_1)
|
||||
@@ -120,6 +122,8 @@ func init() {
|
||||
addExample(time.Minute)
|
||||
addExample(datatransfer.TransferID(3))
|
||||
addExample(datatransfer.Ongoing)
|
||||
addExample(storeIDExample)
|
||||
addExample(&storeIDExample)
|
||||
addExample(multistoreIDExample)
|
||||
addExample(&multistoreIDExample)
|
||||
addExample(retrievalmarket.ClientEventDealAccepted)
|
||||
@@ -176,7 +180,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))
|
||||
@@ -271,6 +275,15 @@ func init() {
|
||||
api.SubsystemSectorStorage,
|
||||
api.SubsystemMarkets,
|
||||
})
|
||||
addExample(api.DagstoreShardResult{
|
||||
Key: "baga6ea4seaqecmtz7iak33dsfshi627abz4i4665dfuzr3qfs4bmad6dx3iigdq",
|
||||
Error: "<error>",
|
||||
})
|
||||
addExample(api.DagstoreShardInfo{
|
||||
Key: "baga6ea4seaqecmtz7iak33dsfshi627abz4i4665dfuzr3qfs4bmad6dx3iigdq",
|
||||
State: "ShardStateAvailable",
|
||||
Error: "<error>",
|
||||
})
|
||||
}
|
||||
|
||||
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
|
||||
|
||||
+33
-2
@@ -6,6 +6,7 @@ package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
json "encoding/json"
|
||||
reflect "reflect"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
@@ -14,7 +15,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 +26,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"
|
||||
imports "github.com/filecoin-project/lotus/node/repo/imports"
|
||||
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"
|
||||
@@ -343,6 +344,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetTipSet(arg0, arg1 interface{}) *gomo
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetTipSet", reflect.TypeOf((*MockFullNode)(nil).ChainGetTipSet), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetTipSetAfterHeight mocks base method.
|
||||
func (m *MockFullNode) ChainGetTipSetAfterHeight(arg0 context.Context, arg1 abi.ChainEpoch, arg2 types.TipSetKey) (*types.TipSet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChainGetTipSetAfterHeight", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*types.TipSet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ChainGetTipSetAfterHeight indicates an expected call of ChainGetTipSetAfterHeight.
|
||||
func (mr *MockFullNodeMockRecorder) ChainGetTipSetAfterHeight(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetTipSetAfterHeight", reflect.TypeOf((*MockFullNode)(nil).ChainGetTipSetAfterHeight), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ChainGetTipSetByHeight mocks base method.
|
||||
func (m *MockFullNode) ChainGetTipSetByHeight(arg0 context.Context, arg1 abi.ChainEpoch, arg2 types.TipSetKey) (*types.TipSet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -760,7 +776,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 imports.ID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClientRemoveImport", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -2229,6 +2245,21 @@ func (mr *MockFullNodeMockRecorder) StateDecodeParams(arg0, arg1, arg2, arg3, ar
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateDecodeParams", reflect.TypeOf((*MockFullNode)(nil).StateDecodeParams), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// StateEncodeParams mocks base method.
|
||||
func (m *MockFullNode) StateEncodeParams(arg0 context.Context, arg1 cid.Cid, arg2 abi.MethodNum, arg3 json.RawMessage) ([]byte, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StateEncodeParams", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].([]byte)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// StateEncodeParams indicates an expected call of StateEncodeParams.
|
||||
func (mr *MockFullNodeMockRecorder) StateEncodeParams(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateEncodeParams", reflect.TypeOf((*MockFullNode)(nil).StateEncodeParams), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// StateGetActor mocks base method.
|
||||
func (m *MockFullNode) StateGetActor(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (*types.Actor, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
+109
-4
@@ -4,6 +4,7 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@@ -13,7 +14,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 +29,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/imports"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -132,6 +133,8 @@ type FullNodeStruct struct {
|
||||
|
||||
ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) `perm:"read"`
|
||||
@@ -188,7 +191,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 imports.ID) error `perm:"admin"`
|
||||
|
||||
ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"`
|
||||
|
||||
@@ -340,6 +343,8 @@ type FullNodeStruct struct {
|
||||
|
||||
StateDecodeParams func(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) `perm:"read"`
|
||||
|
||||
StateEncodeParams func(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) `perm:"read"`
|
||||
|
||||
StateGetActor func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) `perm:"read"`
|
||||
|
||||
StateListActors func(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -474,6 +479,8 @@ type GatewayStruct struct {
|
||||
|
||||
ChainGetTipSet func(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) ``
|
||||
|
||||
ChainGetTipSetAfterHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) ``
|
||||
|
||||
ChainGetTipSetByHeight func(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) ``
|
||||
|
||||
ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) ``
|
||||
@@ -603,6 +610,16 @@ type StorageMinerStruct struct {
|
||||
|
||||
CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"`
|
||||
|
||||
DagstoreGC func(p0 context.Context) ([]DagstoreShardResult, error) `perm:"admin"`
|
||||
|
||||
DagstoreInitializeAll func(p0 context.Context, p1 DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) `perm:"write"`
|
||||
|
||||
DagstoreInitializeShard func(p0 context.Context, p1 string) error `perm:"write"`
|
||||
|
||||
DagstoreListShards func(p0 context.Context) ([]DagstoreShardInfo, error) `perm:"read"`
|
||||
|
||||
DagstoreRecoverShard func(p0 context.Context, p1 string) error `perm:"write"`
|
||||
|
||||
DealsConsiderOfflineRetrievalDeals func(p0 context.Context) (bool, error) `perm:"admin"`
|
||||
|
||||
DealsConsiderOfflineStorageDeals func(p0 context.Context) (bool, error) `perm:"admin"`
|
||||
@@ -1171,6 +1188,17 @@ func (s *FullNodeStub) ChainGetTipSet(p0 context.Context, p1 types.TipSetKey) (*
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
if s.Internal.ChainGetTipSetAfterHeight == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.ChainGetTipSetAfterHeight(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetTipSetByHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
if s.Internal.ChainGetTipSetByHeight == nil {
|
||||
return nil, ErrNotSupported
|
||||
@@ -1479,14 +1507,14 @@ func (s *FullNodeStub) ClientQueryAsk(p0 context.Context, p1 peer.ID, p2 address
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 imports.ID) error {
|
||||
if s.Internal.ClientRemoveImport == nil {
|
||||
return ErrNotSupported
|
||||
}
|
||||
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 imports.ID) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
@@ -2315,6 +2343,17 @@ func (s *FullNodeStub) StateDecodeParams(p0 context.Context, p1 address.Address,
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) StateEncodeParams(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) {
|
||||
if s.Internal.StateEncodeParams == nil {
|
||||
return *new([]byte), ErrNotSupported
|
||||
}
|
||||
return s.Internal.StateEncodeParams(p0, p1, p2, p3)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) StateEncodeParams(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) {
|
||||
return *new([]byte), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) StateGetActor(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) {
|
||||
if s.Internal.StateGetActor == nil {
|
||||
return nil, ErrNotSupported
|
||||
@@ -2997,6 +3036,17 @@ func (s *GatewayStub) ChainGetTipSet(p0 context.Context, p1 types.TipSetKey) (*t
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *GatewayStruct) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
if s.Internal.ChainGetTipSetAfterHeight == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.ChainGetTipSetAfterHeight(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *GatewayStub) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *GatewayStruct) ChainGetTipSetByHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {
|
||||
if s.Internal.ChainGetTipSetByHeight == nil {
|
||||
return nil, ErrNotSupported
|
||||
@@ -3569,6 +3619,61 @@ func (s *StorageMinerStub) CreateBackup(p0 context.Context, p1 string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DagstoreGC(p0 context.Context) ([]DagstoreShardResult, error) {
|
||||
if s.Internal.DagstoreGC == nil {
|
||||
return *new([]DagstoreShardResult), ErrNotSupported
|
||||
}
|
||||
return s.Internal.DagstoreGC(p0)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) DagstoreGC(p0 context.Context) ([]DagstoreShardResult, error) {
|
||||
return *new([]DagstoreShardResult), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DagstoreInitializeAll(p0 context.Context, p1 DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) {
|
||||
if s.Internal.DagstoreInitializeAll == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.DagstoreInitializeAll(p0, p1)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) DagstoreInitializeAll(p0 context.Context, p1 DagstoreInitializeAllParams) (<-chan DagstoreInitializeAllEvent, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DagstoreInitializeShard(p0 context.Context, p1 string) error {
|
||||
if s.Internal.DagstoreInitializeShard == nil {
|
||||
return ErrNotSupported
|
||||
}
|
||||
return s.Internal.DagstoreInitializeShard(p0, p1)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) DagstoreInitializeShard(p0 context.Context, p1 string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DagstoreListShards(p0 context.Context) ([]DagstoreShardInfo, error) {
|
||||
if s.Internal.DagstoreListShards == nil {
|
||||
return *new([]DagstoreShardInfo), ErrNotSupported
|
||||
}
|
||||
return s.Internal.DagstoreListShards(p0)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) DagstoreListShards(p0 context.Context) ([]DagstoreShardInfo, error) {
|
||||
return *new([]DagstoreShardInfo), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DagstoreRecoverShard(p0 context.Context, p1 string) error {
|
||||
if s.Internal.DagstoreRecoverShard == nil {
|
||||
return ErrNotSupported
|
||||
}
|
||||
return s.Internal.DagstoreRecoverShard(p0, p1)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) DagstoreRecoverShard(p0 context.Context, p1 string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) DealsConsiderOfflineRetrievalDeals(p0 context.Context) (bool, error) {
|
||||
if s.Internal.DealsConsiderOfflineRetrievalDeals == nil {
|
||||
return false, ErrNotSupported
|
||||
|
||||
+2
-2
@@ -8,7 +8,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/imports"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=v0mocks/mock_full.go -package=v0mocks . FullNode
|
||||
@@ -305,7 +305,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 imports.ID) 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.
|
||||
|
||||
@@ -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/imports"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -121,7 +121,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 imports.ID) error `perm:"admin"`
|
||||
|
||||
ClientRestartDataTransfer func(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error `perm:"write"`
|
||||
|
||||
@@ -939,14 +939,14 @@ func (s *FullNodeStub) ClientQueryAsk(p0 context.Context, p1 peer.ID, p2 address
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 multistore.StoreID) error {
|
||||
func (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 imports.ID) error {
|
||||
if s.Internal.ClientRemoveImport == nil {
|
||||
return ErrNotSupported
|
||||
}
|
||||
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 imports.ID) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
imports "github.com/filecoin-project/lotus/node/repo/imports"
|
||||
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"
|
||||
@@ -731,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 imports.ID) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ClientRemoveImport", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
+2
-2
@@ -54,8 +54,8 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion0 = newVer(1, 3, 1)
|
||||
FullAPIVersion1 = newVer(2, 1, 1)
|
||||
FullAPIVersion0 = newVer(1, 3, 0)
|
||||
FullAPIVersion1 = newVer(2, 1, 0)
|
||||
|
||||
MinerAPIVersion0 = newVer(1, 2, 0)
|
||||
WorkerAPIVersion0 = newVer(1, 1, 0)
|
||||
|
||||
@@ -119,6 +119,7 @@ TBD -- see [#6577](https://github.com/filecoin-project/lotus/issues/6577)
|
||||
It can also optionally compact/gc the coldstore after the copy (with the `--gc-coldstore` flag)
|
||||
and automatically rewrite the lotus config to disable splitstore (with the `--rewrite-config` flag).
|
||||
Note: the node *must be stopped* before running this command.
|
||||
- `clear` -- clears a splitstore installation for restart from snapshot.
|
||||
- `check` -- asynchronously runs a basic healthcheck on the splitstore.
|
||||
The results are appended to `<lotus-repo>/datastore/splitstore/check.txt`.
|
||||
- `info` -- prints some basic information about the splitstore.
|
||||
|
||||
@@ -21,15 +21,26 @@ type MarkSet interface {
|
||||
SetConcurrent()
|
||||
}
|
||||
|
||||
type MarkSetVisitor interface {
|
||||
MarkSet
|
||||
ObjectVisitor
|
||||
}
|
||||
|
||||
type MarkSetEnv interface {
|
||||
// Create creates a new markset within the environment.
|
||||
// name is a unique name for this markset, mapped to the filesystem in disk-backed environments
|
||||
// sizeHint is a hint about the expected size of the markset
|
||||
Create(name string, sizeHint int64) (MarkSet, error)
|
||||
// CreateVisitor is like Create, but returns a wider interface that supports atomic visits.
|
||||
// It may not be supported by some markset types (e.g. bloom).
|
||||
CreateVisitor(name string, sizeHint int64) (MarkSetVisitor, error)
|
||||
// SupportsVisitor returns true if the marksets created by this environment support the visitor interface.
|
||||
SupportsVisitor() bool
|
||||
Close() error
|
||||
}
|
||||
|
||||
func OpenMarkSetEnv(path string, mtype string) (MarkSetEnv, error) {
|
||||
switch mtype {
|
||||
case "bloom":
|
||||
return NewBloomMarkSetEnv()
|
||||
case "map":
|
||||
return NewMapMarkSetEnv()
|
||||
case "badger":
|
||||
|
||||
@@ -27,12 +27,14 @@ type BadgerMarkSet struct {
|
||||
writing map[int]map[string]struct{}
|
||||
writers int
|
||||
seqno int
|
||||
version int
|
||||
|
||||
db *badger.DB
|
||||
path string
|
||||
}
|
||||
|
||||
var _ MarkSet = (*BadgerMarkSet)(nil)
|
||||
var _ MarkSetVisitor = (*BadgerMarkSet)(nil)
|
||||
|
||||
var badgerMarkSetBatchSize = 16384
|
||||
|
||||
@@ -46,9 +48,241 @@ func NewBadgerMarkSetEnv(path string) (MarkSetEnv, error) {
|
||||
return &BadgerMarkSetEnv{path: msPath}, nil
|
||||
}
|
||||
|
||||
func (e *BadgerMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
func (e *BadgerMarkSetEnv) create(name string, sizeHint int64) (*BadgerMarkSet, error) {
|
||||
name += ".tmp"
|
||||
path := filepath.Join(e.path, name)
|
||||
|
||||
db, err := openTransientBadgerDB(path)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error creating badger db: %w", err)
|
||||
}
|
||||
|
||||
ms := &BadgerMarkSet{
|
||||
pend: make(map[string]struct{}),
|
||||
writing: make(map[int]map[string]struct{}),
|
||||
db: db,
|
||||
path: path,
|
||||
}
|
||||
ms.cond.L = &ms.mx
|
||||
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
func (e *BadgerMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
return e.create(name, sizeHint)
|
||||
}
|
||||
|
||||
func (e *BadgerMarkSetEnv) CreateVisitor(name string, sizeHint int64) (MarkSetVisitor, error) {
|
||||
return e.create(name, sizeHint)
|
||||
}
|
||||
|
||||
func (e *BadgerMarkSetEnv) SupportsVisitor() bool { return true }
|
||||
|
||||
func (e *BadgerMarkSetEnv) Close() error {
|
||||
return os.RemoveAll(e.path)
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Mark(c cid.Cid) error {
|
||||
s.mx.Lock()
|
||||
if s.pend == nil {
|
||||
s.mx.Unlock()
|
||||
return errMarkSetClosed
|
||||
}
|
||||
|
||||
write, seqno := s.put(string(c.Hash()))
|
||||
s.mx.Unlock()
|
||||
|
||||
if write {
|
||||
return s.write(seqno)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Has(c cid.Cid) (bool, error) {
|
||||
s.mx.RLock()
|
||||
defer s.mx.RUnlock()
|
||||
|
||||
key := c.Hash()
|
||||
pendKey := string(key)
|
||||
|
||||
has, err := s.tryPending(pendKey)
|
||||
if has || err != nil {
|
||||
return has, err
|
||||
}
|
||||
|
||||
return s.tryDB(key)
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Visit(c cid.Cid) (bool, error) {
|
||||
key := c.Hash()
|
||||
pendKey := string(key)
|
||||
|
||||
s.mx.RLock()
|
||||
|
||||
has, err := s.tryPending(pendKey)
|
||||
if has || err != nil {
|
||||
s.mx.RUnlock()
|
||||
return false, err
|
||||
}
|
||||
|
||||
has, err = s.tryDB(key)
|
||||
if has || err != nil {
|
||||
s.mx.RUnlock()
|
||||
return false, err
|
||||
}
|
||||
|
||||
// we need to upgrade the lock to exclusive in order to write; take the version count to see
|
||||
// if there was another write while we were upgrading
|
||||
version := s.version
|
||||
s.mx.RUnlock()
|
||||
|
||||
s.mx.Lock()
|
||||
// we have to do the check dance again
|
||||
has, err = s.tryPending(pendKey)
|
||||
if has || err != nil {
|
||||
s.mx.Unlock()
|
||||
return false, err
|
||||
}
|
||||
|
||||
if version != s.version {
|
||||
// something was written to the db, we need to check it
|
||||
has, err = s.tryDB(key)
|
||||
if has || err != nil {
|
||||
s.mx.Unlock()
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
write, seqno := s.put(pendKey)
|
||||
s.mx.Unlock()
|
||||
|
||||
if write {
|
||||
err = s.write(seqno)
|
||||
}
|
||||
|
||||
return true, err
|
||||
}
|
||||
|
||||
// reader holds the (r)lock
|
||||
func (s *BadgerMarkSet) tryPending(key string) (has bool, err error) {
|
||||
if s.pend == nil {
|
||||
return false, errMarkSetClosed
|
||||
}
|
||||
|
||||
if _, ok := s.pend[key]; ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, wr := range s.writing {
|
||||
if _, ok := wr[key]; ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) tryDB(key []byte) (has bool, err error) {
|
||||
err = s.db.View(func(txn *badger.Txn) error {
|
||||
_, err := txn.Get(key)
|
||||
return err
|
||||
})
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
return true, nil
|
||||
|
||||
case badger.ErrKeyNotFound:
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// writer holds the exclusive lock
|
||||
func (s *BadgerMarkSet) put(key string) (write bool, seqno int) {
|
||||
s.pend[key] = struct{}{}
|
||||
if len(s.pend) < badgerMarkSetBatchSize {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
seqno = s.seqno
|
||||
s.seqno++
|
||||
s.writing[seqno] = s.pend
|
||||
s.pend = make(map[string]struct{})
|
||||
|
||||
return true, seqno
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) write(seqno int) (err error) {
|
||||
s.mx.Lock()
|
||||
if s.pend == nil {
|
||||
s.mx.Unlock()
|
||||
return errMarkSetClosed
|
||||
}
|
||||
|
||||
pend := s.writing[seqno]
|
||||
s.writers++
|
||||
s.mx.Unlock()
|
||||
|
||||
defer func() {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
|
||||
if err == nil {
|
||||
delete(s.writing, seqno)
|
||||
s.version++
|
||||
}
|
||||
|
||||
s.writers--
|
||||
if s.writers == 0 {
|
||||
s.cond.Broadcast()
|
||||
}
|
||||
}()
|
||||
|
||||
empty := []byte{} // not nil
|
||||
|
||||
batch := s.db.NewWriteBatch()
|
||||
defer batch.Cancel()
|
||||
|
||||
for k := range pend {
|
||||
if err = batch.Set([]byte(k), empty); err != nil {
|
||||
return xerrors.Errorf("error setting batch: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = batch.Flush()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error flushing batch to badger markset: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Close() error {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
|
||||
if s.pend == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for s.writers > 0 {
|
||||
s.cond.Wait()
|
||||
}
|
||||
|
||||
s.pend = nil
|
||||
db := s.db
|
||||
s.db = nil
|
||||
|
||||
return closeTransientBadgerDB(db, s.path)
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) SetConcurrent() {}
|
||||
|
||||
func openTransientBadgerDB(path string) (*badger.DB, error) {
|
||||
// clean up first
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
@@ -76,140 +310,16 @@ func (e *BadgerMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error)
|
||||
skip2: log.Desugar().WithOptions(zap.AddCallerSkip(2)).Sugar(),
|
||||
}
|
||||
|
||||
db, err := badger.Open(opts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error creating badger markset: %w", err)
|
||||
}
|
||||
|
||||
ms := &BadgerMarkSet{
|
||||
pend: make(map[string]struct{}),
|
||||
writing: make(map[int]map[string]struct{}),
|
||||
db: db,
|
||||
path: path,
|
||||
}
|
||||
ms.cond.L = &ms.mx
|
||||
|
||||
return ms, nil
|
||||
return badger.Open(opts)
|
||||
}
|
||||
|
||||
func (e *BadgerMarkSetEnv) Close() error {
|
||||
return os.RemoveAll(e.path)
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Mark(c cid.Cid) error {
|
||||
s.mx.Lock()
|
||||
|
||||
if s.pend == nil {
|
||||
s.mx.Unlock()
|
||||
return errMarkSetClosed
|
||||
}
|
||||
|
||||
s.pend[string(c.Hash())] = struct{}{}
|
||||
|
||||
if len(s.pend) < badgerMarkSetBatchSize {
|
||||
s.mx.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
pend := s.pend
|
||||
seqno := s.seqno
|
||||
s.seqno++
|
||||
s.writing[seqno] = pend
|
||||
s.pend = make(map[string]struct{})
|
||||
s.writers++
|
||||
s.mx.Unlock()
|
||||
|
||||
defer func() {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
|
||||
delete(s.writing, seqno)
|
||||
s.writers--
|
||||
if s.writers == 0 {
|
||||
s.cond.Broadcast()
|
||||
}
|
||||
}()
|
||||
|
||||
empty := []byte{} // not nil
|
||||
|
||||
batch := s.db.NewWriteBatch()
|
||||
defer batch.Cancel()
|
||||
|
||||
for k := range pend {
|
||||
if err := batch.Set([]byte(k), empty); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := batch.Flush()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error flushing batch to badger markset: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Has(c cid.Cid) (bool, error) {
|
||||
s.mx.RLock()
|
||||
defer s.mx.RUnlock()
|
||||
|
||||
if s.pend == nil {
|
||||
return false, errMarkSetClosed
|
||||
}
|
||||
|
||||
key := c.Hash()
|
||||
pendKey := string(key)
|
||||
_, ok := s.pend[pendKey]
|
||||
if ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, wr := range s.writing {
|
||||
_, ok := wr[pendKey]
|
||||
if ok {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
err := s.db.View(func(txn *badger.Txn) error {
|
||||
_, err := txn.Get(key)
|
||||
return err
|
||||
})
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
return true, nil
|
||||
|
||||
case badger.ErrKeyNotFound:
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
return false, xerrors.Errorf("error checking badger markset: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) Close() error {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
|
||||
if s.pend == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for s.writers > 0 {
|
||||
s.cond.Wait()
|
||||
}
|
||||
|
||||
s.pend = nil
|
||||
db := s.db
|
||||
s.db = nil
|
||||
|
||||
func closeTransientBadgerDB(db *badger.DB, path string) error {
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error closing badger markset: %w", err)
|
||||
}
|
||||
|
||||
err = os.RemoveAll(s.path)
|
||||
err = os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error deleting badger markset: %w", err)
|
||||
}
|
||||
@@ -217,8 +327,6 @@ func (s *BadgerMarkSet) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BadgerMarkSet) SetConcurrent() {}
|
||||
|
||||
// badger logging through go-log
|
||||
type badgerLogger struct {
|
||||
*zap.SugaredLogger
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
bbloom "github.com/ipfs/bbloom"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
const (
|
||||
BloomFilterMinSize = 10_000_000
|
||||
BloomFilterProbability = 0.01
|
||||
)
|
||||
|
||||
type BloomMarkSetEnv struct{}
|
||||
|
||||
var _ MarkSetEnv = (*BloomMarkSetEnv)(nil)
|
||||
|
||||
type BloomMarkSet struct {
|
||||
salt []byte
|
||||
mx sync.RWMutex
|
||||
bf *bbloom.Bloom
|
||||
ts bool
|
||||
}
|
||||
|
||||
var _ MarkSet = (*BloomMarkSet)(nil)
|
||||
|
||||
func NewBloomMarkSetEnv() (*BloomMarkSetEnv, error) {
|
||||
return &BloomMarkSetEnv{}, nil
|
||||
}
|
||||
|
||||
func (e *BloomMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
size := int64(BloomFilterMinSize)
|
||||
for size < sizeHint {
|
||||
size += BloomFilterMinSize
|
||||
}
|
||||
|
||||
salt := make([]byte, 4)
|
||||
_, err := rand.Read(salt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error reading salt: %w", err)
|
||||
}
|
||||
|
||||
bf, err := bbloom.New(float64(size), BloomFilterProbability)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error creating bloom filter: %w", err)
|
||||
}
|
||||
|
||||
return &BloomMarkSet{salt: salt, bf: bf}, nil
|
||||
}
|
||||
|
||||
func (e *BloomMarkSetEnv) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BloomMarkSet) saltedKey(cid cid.Cid) []byte {
|
||||
hash := cid.Hash()
|
||||
key := make([]byte, len(s.salt)+len(hash))
|
||||
n := copy(key, s.salt)
|
||||
copy(key[n:], hash)
|
||||
rehash := sha256.Sum256(key)
|
||||
return rehash[:]
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -18,17 +18,28 @@ type MapMarkSet struct {
|
||||
}
|
||||
|
||||
var _ MarkSet = (*MapMarkSet)(nil)
|
||||
var _ MarkSetVisitor = (*MapMarkSet)(nil)
|
||||
|
||||
func NewMapMarkSetEnv() (*MapMarkSetEnv, error) {
|
||||
return &MapMarkSetEnv{}, nil
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
func (e *MapMarkSetEnv) create(name string, sizeHint int64) (*MapMarkSet, error) {
|
||||
return &MapMarkSet{
|
||||
set: make(map[string]struct{}, sizeHint),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) Create(name string, sizeHint int64) (MarkSet, error) {
|
||||
return e.create(name, sizeHint)
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) CreateVisitor(name string, sizeHint int64) (MarkSetVisitor, error) {
|
||||
return e.create(name, sizeHint)
|
||||
}
|
||||
|
||||
func (e *MapMarkSetEnv) SupportsVisitor() bool { return true }
|
||||
|
||||
func (e *MapMarkSetEnv) Close() error {
|
||||
return nil
|
||||
}
|
||||
@@ -61,6 +72,25 @@ func (s *MapMarkSet) Has(cid cid.Cid) (bool, error) {
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) Visit(c cid.Cid) (bool, error) {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
defer s.mx.Unlock()
|
||||
}
|
||||
|
||||
if s.set == nil {
|
||||
return false, errMarkSetClosed
|
||||
}
|
||||
|
||||
key := string(c.Hash())
|
||||
if _, ok := s.set[key]; ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
s.set[key] = struct{}{}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *MapMarkSet) Close() error {
|
||||
if s.ts {
|
||||
s.mx.Lock()
|
||||
|
||||
@@ -2,6 +2,7 @@ package splitstore
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
@@ -10,10 +11,7 @@ import (
|
||||
|
||||
func TestMapMarkSet(t *testing.T) {
|
||||
testMarkSet(t, "map")
|
||||
}
|
||||
|
||||
func TestBloomMarkSet(t *testing.T) {
|
||||
testMarkSet(t, "bloom")
|
||||
testMarkSetVisitor(t, "map")
|
||||
}
|
||||
|
||||
func TestBadgerMarkSet(t *testing.T) {
|
||||
@@ -23,16 +21,21 @@ func TestBadgerMarkSet(t *testing.T) {
|
||||
badgerMarkSetBatchSize = bs
|
||||
})
|
||||
testMarkSet(t, "badger")
|
||||
testMarkSetVisitor(t, "badger")
|
||||
}
|
||||
|
||||
func testMarkSet(t *testing.T, lsType string) {
|
||||
t.Helper()
|
||||
|
||||
path, err := ioutil.TempDir("", "sweep-test.*")
|
||||
path, err := ioutil.TempDir("", "markset.*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
_ = os.RemoveAll(path)
|
||||
})
|
||||
|
||||
env, err := OpenMarkSetEnv(path, lsType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -145,3 +148,74 @@ func testMarkSet(t *testing.T, lsType string) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testMarkSetVisitor(t *testing.T, lsType string) {
|
||||
t.Helper()
|
||||
|
||||
path, err := ioutil.TempDir("", "markset.*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
_ = os.RemoveAll(path)
|
||||
})
|
||||
|
||||
env, err := OpenMarkSetEnv(path, lsType)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer env.Close() //nolint:errcheck
|
||||
|
||||
visitor, err := env.CreateVisitor("test", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer visitor.Close() //nolint:errcheck
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
mustVisit := func(v ObjectVisitor, cid cid.Cid) {
|
||||
visit, err := v.Visit(cid)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !visit {
|
||||
t.Fatal("object should be visited")
|
||||
}
|
||||
}
|
||||
|
||||
mustNotVisit := func(v ObjectVisitor, cid cid.Cid) {
|
||||
visit, err := v.Visit(cid)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if visit {
|
||||
t.Fatal("unexpected visit")
|
||||
}
|
||||
}
|
||||
|
||||
k1 := makeCid("a")
|
||||
k2 := makeCid("b")
|
||||
k3 := makeCid("c")
|
||||
k4 := makeCid("d")
|
||||
|
||||
mustVisit(visitor, k1)
|
||||
mustVisit(visitor, k2)
|
||||
mustVisit(visitor, k3)
|
||||
mustVisit(visitor, k4)
|
||||
|
||||
mustNotVisit(visitor, k1)
|
||||
mustNotVisit(visitor, k2)
|
||||
mustNotVisit(visitor, k3)
|
||||
mustNotVisit(visitor, k4)
|
||||
}
|
||||
|
||||
@@ -142,7 +142,6 @@ type SplitStore struct {
|
||||
txnViews int
|
||||
txnViewsWaiting bool
|
||||
txnActive bool
|
||||
txnProtect MarkSet
|
||||
txnRefsMx sync.Mutex
|
||||
txnRefs map[cid.Cid]struct{}
|
||||
txnMissing map[cid.Cid]struct{}
|
||||
@@ -174,6 +173,10 @@ func Open(path string, ds dstore.Datastore, hot, cold bstore.Blockstore, cfg *Co
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !markSetEnv.SupportsVisitor() {
|
||||
return nil, xerrors.Errorf("markset type does not support atomic visitors")
|
||||
}
|
||||
|
||||
// and now we can make a SplitStore
|
||||
ss := &SplitStore{
|
||||
cfg: cfg,
|
||||
|
||||
@@ -83,7 +83,14 @@ func (s *SplitStore) doCheck(curTs *types.TipSet) error {
|
||||
write("--")
|
||||
|
||||
var coldCnt, missingCnt int64
|
||||
err = s.walkChain(curTs, boundaryEpoch, boundaryEpoch,
|
||||
|
||||
visitor, err := s.markSetEnv.CreateVisitor("check", 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error creating visitor: %w", err)
|
||||
}
|
||||
defer visitor.Close() //nolint
|
||||
|
||||
err = s.walkChain(curTs, boundaryEpoch, boundaryEpoch, visitor,
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
|
||||
@@ -211,7 +211,7 @@ func (s *SplitStore) trackTxnRefMany(cids []cid.Cid) {
|
||||
}
|
||||
|
||||
// protect all pending transactional references
|
||||
func (s *SplitStore) protectTxnRefs(markSet MarkSet) error {
|
||||
func (s *SplitStore) protectTxnRefs(markSet MarkSetVisitor) error {
|
||||
for {
|
||||
var txnRefs map[cid.Cid]struct{}
|
||||
|
||||
@@ -283,30 +283,29 @@ func (s *SplitStore) protectTxnRefs(markSet MarkSet) error {
|
||||
|
||||
// transactionally protect a reference by walking the object and marking.
|
||||
// concurrent markings are short circuited by checking the markset.
|
||||
func (s *SplitStore) doTxnProtect(root cid.Cid, markSet MarkSet) error {
|
||||
func (s *SplitStore) doTxnProtect(root cid.Cid, markSet MarkSetVisitor) error {
|
||||
if err := s.checkClosing(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note: cold objects are deleted heaviest first, so the consituents of an object
|
||||
// cannot be deleted before the object itself.
|
||||
return s.walkObjectIncomplete(root, cid.NewSet(),
|
||||
return s.walkObjectIncomplete(root, tmpVisitor(),
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
mark, err := markSet.Has(c)
|
||||
visit, err := markSet.Visit(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error checking markset: %w", err)
|
||||
return xerrors.Errorf("error visiting object: %w", err)
|
||||
}
|
||||
|
||||
// it's marked, nothing to do
|
||||
if mark {
|
||||
if !visit {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
return markSet.Mark(c)
|
||||
return nil
|
||||
},
|
||||
func(c cid.Cid) error {
|
||||
if s.txnMissing != nil {
|
||||
@@ -382,7 +381,7 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
|
||||
|
||||
log.Infow("running compaction", "currentEpoch", currentEpoch, "baseEpoch", s.baseEpoch, "boundaryEpoch", boundaryEpoch, "inclMsgsEpoch", inclMsgsEpoch, "compactionIndex", s.compactionIndex)
|
||||
|
||||
markSet, err := s.markSetEnv.Create("live", s.markSetSize)
|
||||
markSet, err := s.markSetEnv.CreateVisitor("live", s.markSetSize)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error creating mark set: %w", err)
|
||||
}
|
||||
@@ -410,14 +409,23 @@ func (s *SplitStore) doCompact(curTs *types.TipSet) error {
|
||||
startMark := time.Now()
|
||||
|
||||
var count int64
|
||||
err = s.walkChain(curTs, boundaryEpoch, inclMsgsEpoch,
|
||||
err = s.walkChain(curTs, boundaryEpoch, inclMsgsEpoch, &noopVisitor{},
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
visit, err := markSet.Visit(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error visiting object: %w", err)
|
||||
}
|
||||
|
||||
if !visit {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
count++
|
||||
return markSet.Mark(c)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -578,12 +586,8 @@ func (s *SplitStore) beginTxnProtect() {
|
||||
s.txnMissing = make(map[cid.Cid]struct{})
|
||||
}
|
||||
|
||||
func (s *SplitStore) beginTxnMarking(markSet MarkSet) {
|
||||
func (s *SplitStore) beginTxnMarking(markSet MarkSetVisitor) {
|
||||
markSet.SetConcurrent()
|
||||
|
||||
s.txnLk.Lock()
|
||||
s.txnProtect = markSet
|
||||
s.txnLk.Unlock()
|
||||
}
|
||||
|
||||
func (s *SplitStore) endTxnProtect() {
|
||||
@@ -594,21 +598,14 @@ func (s *SplitStore) endTxnProtect() {
|
||||
return
|
||||
}
|
||||
|
||||
// release markset memory
|
||||
if s.txnProtect != nil {
|
||||
_ = s.txnProtect.Close()
|
||||
}
|
||||
|
||||
s.txnActive = false
|
||||
s.txnProtect = nil
|
||||
s.txnRefs = nil
|
||||
s.txnMissing = nil
|
||||
}
|
||||
|
||||
func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEpoch,
|
||||
f func(cid.Cid) error) error {
|
||||
visited := cid.NewSet()
|
||||
walked := cid.NewSet()
|
||||
visitor ObjectVisitor, f func(cid.Cid) error) error {
|
||||
var walked *cid.Set
|
||||
toWalk := ts.Cids()
|
||||
walkCnt := 0
|
||||
scanCnt := 0
|
||||
@@ -616,7 +613,7 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
stopWalk := func(_ cid.Cid) error { return errStopWalk }
|
||||
|
||||
walkBlock := func(c cid.Cid) error {
|
||||
if !visited.Visit(c) {
|
||||
if !walked.Visit(c) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -640,19 +637,19 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
if inclMsgs < inclState {
|
||||
// we need to use walkObjectIncomplete here, as messages/receipts may be missing early on if we
|
||||
// synced from snapshot and have a long HotStoreMessageRetentionPolicy.
|
||||
if err := s.walkObjectIncomplete(hdr.Messages, walked, f, stopWalk); err != nil {
|
||||
if err := s.walkObjectIncomplete(hdr.Messages, visitor, f, stopWalk); err != nil {
|
||||
return xerrors.Errorf("error walking messages (cid: %s): %w", hdr.Messages, err)
|
||||
}
|
||||
|
||||
if err := s.walkObjectIncomplete(hdr.ParentMessageReceipts, walked, f, stopWalk); err != nil {
|
||||
if err := s.walkObjectIncomplete(hdr.ParentMessageReceipts, visitor, f, stopWalk); err != nil {
|
||||
return xerrors.Errorf("error walking messages receipts (cid: %s): %w", hdr.ParentMessageReceipts, err)
|
||||
}
|
||||
} else {
|
||||
if err := s.walkObject(hdr.Messages, walked, f); err != nil {
|
||||
if err := s.walkObject(hdr.Messages, visitor, f); err != nil {
|
||||
return xerrors.Errorf("error walking messages (cid: %s): %w", hdr.Messages, err)
|
||||
}
|
||||
|
||||
if err := s.walkObject(hdr.ParentMessageReceipts, walked, f); err != nil {
|
||||
if err := s.walkObject(hdr.ParentMessageReceipts, visitor, f); err != nil {
|
||||
return xerrors.Errorf("error walking message receipts (cid: %s): %w", hdr.ParentMessageReceipts, err)
|
||||
}
|
||||
}
|
||||
@@ -660,7 +657,7 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
|
||||
// state is only retained if within the inclState boundary, with the exception of genesis
|
||||
if hdr.Height >= inclState || hdr.Height == 0 {
|
||||
if err := s.walkObject(hdr.ParentStateRoot, walked, f); err != nil {
|
||||
if err := s.walkObject(hdr.ParentStateRoot, visitor, f); err != nil {
|
||||
return xerrors.Errorf("error walking state root (cid: %s): %w", hdr.ParentStateRoot, err)
|
||||
}
|
||||
scanCnt++
|
||||
@@ -679,6 +676,10 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
return err
|
||||
}
|
||||
|
||||
// the walk is BFS, so we can reset the walked set in every iteration and avoid building up
|
||||
// a set that contains all blocks (1M epochs -> 5M blocks -> 200MB worth of memory and growing
|
||||
// over time)
|
||||
walked = cid.NewSet()
|
||||
walking := toWalk
|
||||
toWalk = nil
|
||||
for _, c := range walking {
|
||||
@@ -693,8 +694,13 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SplitStore) walkObject(c cid.Cid, walked *cid.Set, f func(cid.Cid) error) error {
|
||||
if !walked.Visit(c) {
|
||||
func (s *SplitStore) walkObject(c cid.Cid, visitor ObjectVisitor, f func(cid.Cid) error) error {
|
||||
visit, err := visitor.Visit(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error visiting object: %w", err)
|
||||
}
|
||||
|
||||
if !visit {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -716,7 +722,7 @@ func (s *SplitStore) walkObject(c cid.Cid, walked *cid.Set, f func(cid.Cid) erro
|
||||
}
|
||||
|
||||
var links []cid.Cid
|
||||
err := s.view(c, func(data []byte) error {
|
||||
err = s.view(c, func(data []byte) error {
|
||||
return cbg.ScanForLinks(bytes.NewReader(data), func(c cid.Cid) {
|
||||
links = append(links, c)
|
||||
})
|
||||
@@ -727,7 +733,7 @@ func (s *SplitStore) walkObject(c cid.Cid, walked *cid.Set, f func(cid.Cid) erro
|
||||
}
|
||||
|
||||
for _, c := range links {
|
||||
err := s.walkObject(c, walked, f)
|
||||
err := s.walkObject(c, visitor, f)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error walking link (cid: %s): %w", c, err)
|
||||
}
|
||||
@@ -737,8 +743,13 @@ func (s *SplitStore) walkObject(c cid.Cid, walked *cid.Set, f func(cid.Cid) erro
|
||||
}
|
||||
|
||||
// like walkObject, but the object may be potentially incomplete (references missing)
|
||||
func (s *SplitStore) walkObjectIncomplete(c cid.Cid, walked *cid.Set, f, missing func(cid.Cid) error) error {
|
||||
if !walked.Visit(c) {
|
||||
func (s *SplitStore) walkObjectIncomplete(c cid.Cid, visitor ObjectVisitor, f, missing func(cid.Cid) error) error {
|
||||
visit, err := visitor.Visit(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error visiting object: %w", err)
|
||||
}
|
||||
|
||||
if !visit {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -777,7 +788,7 @@ func (s *SplitStore) walkObjectIncomplete(c cid.Cid, walked *cid.Set, f, missing
|
||||
}
|
||||
|
||||
var links []cid.Cid
|
||||
err := s.view(c, func(data []byte) error {
|
||||
err = s.view(c, func(data []byte) error {
|
||||
return cbg.ScanForLinks(bytes.NewReader(data), func(c cid.Cid) {
|
||||
links = append(links, c)
|
||||
})
|
||||
@@ -788,7 +799,7 @@ func (s *SplitStore) walkObjectIncomplete(c cid.Cid, walked *cid.Set, f, missing
|
||||
}
|
||||
|
||||
for _, c := range links {
|
||||
err := s.walkObjectIncomplete(c, walked, f, missing)
|
||||
err := s.walkObjectIncomplete(c, visitor, f, missing)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error walking link (cid: %s): %w", c, err)
|
||||
}
|
||||
@@ -984,7 +995,7 @@ func (s *SplitStore) purgeBatch(cids []cid.Cid, deleteBatch func([]cid.Cid) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SplitStore) purge(cids []cid.Cid, markSet MarkSet) error {
|
||||
func (s *SplitStore) purge(cids []cid.Cid, markSet MarkSetVisitor) error {
|
||||
deadCids := make([]cid.Cid, 0, batchSize)
|
||||
var purgeCnt, liveCnt int
|
||||
defer func() {
|
||||
@@ -1050,7 +1061,7 @@ func (s *SplitStore) purge(cids []cid.Cid, markSet MarkSet) error {
|
||||
// have this gem[TM].
|
||||
// My best guess is that they are parent message receipts or yet to be computed state roots; magik
|
||||
// thinks the cause may be block validation.
|
||||
func (s *SplitStore) waitForMissingRefs(markSet MarkSet) {
|
||||
func (s *SplitStore) waitForMissingRefs(markSet MarkSetVisitor) {
|
||||
s.txnLk.Lock()
|
||||
missing := s.txnMissing
|
||||
s.txnMissing = nil
|
||||
@@ -1079,27 +1090,27 @@ func (s *SplitStore) waitForMissingRefs(markSet MarkSet) {
|
||||
}
|
||||
|
||||
towalk := missing
|
||||
walked := cid.NewSet()
|
||||
visitor := tmpVisitor()
|
||||
missing = make(map[cid.Cid]struct{})
|
||||
|
||||
for c := range towalk {
|
||||
err := s.walkObjectIncomplete(c, walked,
|
||||
err := s.walkObjectIncomplete(c, visitor,
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
mark, err := markSet.Has(c)
|
||||
visit, err := markSet.Visit(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error checking markset for %s: %w", c, err)
|
||||
return xerrors.Errorf("error visiting object: %w", err)
|
||||
}
|
||||
|
||||
if mark {
|
||||
if !visit {
|
||||
return errStopWalk
|
||||
}
|
||||
|
||||
count++
|
||||
return markSet.Mark(c)
|
||||
return nil
|
||||
},
|
||||
func(c cid.Cid) error {
|
||||
missing[c] = struct{}{}
|
||||
|
||||
@@ -59,7 +59,15 @@ func (s *SplitStore) doWarmup(curTs *types.TipSet) error {
|
||||
count := int64(0)
|
||||
xcount := int64(0)
|
||||
missing := int64(0)
|
||||
err := s.walkChain(curTs, boundaryEpoch, epoch+1, // we don't load messages/receipts in warmup
|
||||
|
||||
visitor, err := s.markSetEnv.CreateVisitor("warmup", 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error creating visitor: %w", err)
|
||||
}
|
||||
defer visitor.Close() //nolint
|
||||
|
||||
err = s.walkChain(curTs, boundaryEpoch, epoch+1, // we don't load messages/receipts in warmup
|
||||
visitor,
|
||||
func(c cid.Cid) error {
|
||||
if isUnitaryObject(c) {
|
||||
return errStopWalk
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package splitstore
|
||||
|
||||
import (
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// ObjectVisitor is an interface for deduplicating objects during walks
|
||||
type ObjectVisitor interface {
|
||||
Visit(cid.Cid) (bool, error)
|
||||
}
|
||||
|
||||
type noopVisitor struct{}
|
||||
|
||||
var _ ObjectVisitor = (*noopVisitor)(nil)
|
||||
|
||||
func (v *noopVisitor) Visit(_ cid.Cid) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type cidSetVisitor struct {
|
||||
set *cid.Set
|
||||
}
|
||||
|
||||
var _ ObjectVisitor = (*cidSetVisitor)(nil)
|
||||
|
||||
func (v *cidSetVisitor) Visit(c cid.Cid) (bool, error) {
|
||||
return v.set.Visit(c), nil
|
||||
}
|
||||
|
||||
func tmpVisitor() ObjectVisitor {
|
||||
return &cidSetVisitor{set: cid.NewSet()}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -28,7 +28,6 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
|
||||
|
||||
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
|
||||
var UpgradePricelistOopsHeight = abi.ChainEpoch(-8)
|
||||
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
|
||||
var UpgradePersianHeight = abi.ChainEpoch(-10)
|
||||
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
|
||||
|
||||
@@ -28,7 +28,6 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(30)
|
||||
const UpgradeTapeHeight = 60
|
||||
const UpgradeLiftoffHeight = -5
|
||||
const UpgradeKumquatHeight = 90
|
||||
const UpgradePricelistOopsHeight = 119
|
||||
const UpgradeCalicoHeight = 120
|
||||
const UpgradePersianHeight = 150
|
||||
const UpgradeClausHeight = 180
|
||||
@@ -47,6 +46,8 @@ func init() {
|
||||
SetAddressNetwork(address.Testnet)
|
||||
|
||||
Devnet = true
|
||||
|
||||
BuildType = BuildButterflynet
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
|
||||
@@ -33,8 +33,6 @@ const UpgradeLiftoffHeight = -5
|
||||
|
||||
const UpgradeKumquatHeight = 90
|
||||
|
||||
const UpgradePricelistOopsHeight = 119
|
||||
|
||||
const UpgradeCalicoHeight = 120
|
||||
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1)
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
|
||||
|
||||
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
|
||||
var UpgradePricelistOopsHeight = abi.ChainEpoch(-8)
|
||||
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
|
||||
var UpgradePersianHeight = abi.ChainEpoch(-10)
|
||||
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
|
||||
|
||||
@@ -45,7 +45,6 @@ const UpgradeLiftoffHeight = 148888
|
||||
|
||||
const UpgradeKumquatHeight = 170000
|
||||
|
||||
const UpgradePricelistOopsHeight = 265199
|
||||
const UpgradeCalicoHeight = 265200
|
||||
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60)
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ const UpgradeTapeHeight = 60
|
||||
|
||||
const UpgradeKumquatHeight = 90
|
||||
|
||||
const UpgradePricelistOopsHeight = 99
|
||||
const UpgradeCalicoHeight = 100
|
||||
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 1)
|
||||
|
||||
@@ -67,6 +66,8 @@ func init() {
|
||||
//miner.WPoStChallengeLookback = abi.ChainEpoch(2)
|
||||
|
||||
Devnet = false
|
||||
|
||||
BuildType = BuildNerpanet
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
|
||||
@@ -26,7 +26,6 @@ const UnixfsLinksPerLevel = 1024
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version13
|
||||
const ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
// Epochs
|
||||
const ForkLengthThreshold = Finality
|
||||
|
||||
+15
-16
@@ -82,22 +82,21 @@ var (
|
||||
UpgradeBreezeHeight abi.ChainEpoch = -1
|
||||
BreezeGasTampingDuration abi.ChainEpoch = 0
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeTapeHeight abi.ChainEpoch = -4
|
||||
UpgradeAssemblyHeight abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -5
|
||||
UpgradeKumquatHeight abi.ChainEpoch = -6
|
||||
UpgradePricelistOopsHeight abi.ChainEpoch = -7
|
||||
UpgradeCalicoHeight abi.ChainEpoch = -8
|
||||
UpgradePersianHeight abi.ChainEpoch = -9
|
||||
UpgradeOrangeHeight abi.ChainEpoch = -10
|
||||
UpgradeClausHeight abi.ChainEpoch = -11
|
||||
UpgradeTrustHeight abi.ChainEpoch = -12
|
||||
UpgradeNorwegianHeight abi.ChainEpoch = -13
|
||||
UpgradeTurboHeight abi.ChainEpoch = -14
|
||||
UpgradeHyperdriveHeight abi.ChainEpoch = -15
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeTapeHeight abi.ChainEpoch = -4
|
||||
UpgradeAssemblyHeight abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -5
|
||||
UpgradeKumquatHeight abi.ChainEpoch = -6
|
||||
UpgradeCalicoHeight abi.ChainEpoch = -8
|
||||
UpgradePersianHeight abi.ChainEpoch = -9
|
||||
UpgradeOrangeHeight abi.ChainEpoch = -10
|
||||
UpgradeClausHeight abi.ChainEpoch = -11
|
||||
UpgradeTrustHeight abi.ChainEpoch = -12
|
||||
UpgradeNorwegianHeight abi.ChainEpoch = -13
|
||||
UpgradeTurboHeight abi.ChainEpoch = -14
|
||||
UpgradeHyperdriveHeight abi.ChainEpoch = -15
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
|
||||
+14
-8
@@ -6,12 +6,14 @@ var CurrentCommit string
|
||||
var BuildType int
|
||||
|
||||
const (
|
||||
BuildDefault = 0
|
||||
BuildMainnet = 0x1
|
||||
Build2k = 0x2
|
||||
BuildDebug = 0x3
|
||||
BuildCalibnet = 0x4
|
||||
BuildInteropnet = 0x5
|
||||
BuildDefault = 0
|
||||
BuildMainnet = 0x1
|
||||
Build2k = 0x2
|
||||
BuildDebug = 0x3
|
||||
BuildCalibnet = 0x4
|
||||
BuildInteropnet = 0x5
|
||||
BuildNerpanet = 0x6
|
||||
BuildButterflynet = 0x7
|
||||
)
|
||||
|
||||
func buildType() string {
|
||||
@@ -28,13 +30,17 @@ func buildType() string {
|
||||
return "+calibnet"
|
||||
case BuildInteropnet:
|
||||
return "+interopnet"
|
||||
case BuildNerpanet:
|
||||
return "+nerpanet"
|
||||
case BuildButterflynet:
|
||||
return "+butterflynet"
|
||||
default:
|
||||
return "+huh?"
|
||||
}
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "1.11.1-rc1"
|
||||
// BuildVersion is the local build version
|
||||
const BuildVersion = "1.11.2"
|
||||
|
||||
func UserVersion() string {
|
||||
if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" {
|
||||
|
||||
@@ -38,7 +38,7 @@ func init() {
|
||||
|
||||
var Methods = builtin{{.latestVersion}}.MethodsMiner
|
||||
|
||||
// Unchanged between v0, v2, v3, and v4 actors
|
||||
// Unchanged between v0, v2, v3, v4, and v5 actors
|
||||
var WPoStProvingPeriod = miner0.WPoStProvingPeriod
|
||||
var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines
|
||||
var WPoStChallengeWindow = miner0.WPoStChallengeWindow
|
||||
|
||||
@@ -61,7 +61,7 @@ func init() {
|
||||
|
||||
var Methods = builtin5.MethodsMiner
|
||||
|
||||
// Unchanged between v0, v2, v3, and v4 actors
|
||||
// Unchanged between v0, v2, v3, v4, and v5 actors
|
||||
var WPoStProvingPeriod = miner0.WPoStProvingPeriod
|
||||
var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines
|
||||
var WPoStChallengeWindow = miner0.WPoStChallengeWindow
|
||||
|
||||
@@ -479,12 +479,15 @@ func (s *state{{.v}}) EraseAllUnproven() error {
|
||||
|
||||
return dls.UpdateDeadline(s.store, dindx, dl)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.State.SaveDeadlines(s.store, dls)
|
||||
{{else}}
|
||||
// field doesn't exist until v2
|
||||
return nil
|
||||
{{end}}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deadline{{.v}}) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -444,8 +444,8 @@ func (s *state0) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreC
|
||||
func (s *state0) EraseAllUnproven() error {
|
||||
|
||||
// field doesn't exist until v2
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (d *deadline0) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -470,10 +470,12 @@ func (s *state2) EraseAllUnproven() error {
|
||||
|
||||
return dls.UpdateDeadline(s.store, dindx, dl)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.State.SaveDeadlines(s.store, dls)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deadline2) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -467,10 +467,12 @@ func (s *state3) EraseAllUnproven() error {
|
||||
|
||||
return dls.UpdateDeadline(s.store, dindx, dl)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.State.SaveDeadlines(s.store, dls)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deadline3) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -467,10 +467,12 @@ func (s *state4) EraseAllUnproven() error {
|
||||
|
||||
return dls.UpdateDeadline(s.store, dindx, dl)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.State.SaveDeadlines(s.store, dls)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deadline4) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -467,10 +467,12 @@ func (s *state5) EraseAllUnproven() error {
|
||||
|
||||
return dls.UpdateDeadline(s.store, dindx, dl)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.State.SaveDeadlines(s.store, dls)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *deadline5) LoadPartition(idx uint64) (Partition, error) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
@@ -168,31 +169,31 @@ func SetMinVerifiedDealSize(size abi.StoragePower) {
|
||||
|
||||
}
|
||||
|
||||
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch {
|
||||
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (abi.ChainEpoch, error) {
|
||||
switch ver {
|
||||
|
||||
case actors.Version0:
|
||||
|
||||
return miner0.MaxSealDuration[t]
|
||||
return miner0.MaxSealDuration[t], nil
|
||||
|
||||
case actors.Version2:
|
||||
|
||||
return miner2.MaxProveCommitDuration[t]
|
||||
return miner2.MaxProveCommitDuration[t], nil
|
||||
|
||||
case actors.Version3:
|
||||
|
||||
return miner3.MaxProveCommitDuration[t]
|
||||
return miner3.MaxProveCommitDuration[t], nil
|
||||
|
||||
case actors.Version4:
|
||||
|
||||
return miner4.MaxProveCommitDuration[t]
|
||||
return miner4.MaxProveCommitDuration[t], nil
|
||||
|
||||
case actors.Version5:
|
||||
|
||||
return miner5.MaxProveCommitDuration[t]
|
||||
return miner5.MaxProveCommitDuration[t], nil
|
||||
|
||||
default:
|
||||
panic("unsupported actors version")
|
||||
return 0, xerrors.Errorf("unsupported actors version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,31 +228,40 @@ func DealProviderCollateralBounds(
|
||||
size abi.PaddedPieceSize, verified bool,
|
||||
rawBytePower, qaPower, baselinePower abi.StoragePower,
|
||||
circulatingFil abi.TokenAmount, nwVer network.Version,
|
||||
) (min, max abi.TokenAmount) {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
) (min, max abi.TokenAmount, err error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return big.Zero(), big.Zero(), err
|
||||
}
|
||||
switch v {
|
||||
|
||||
case actors.Version0:
|
||||
|
||||
return market0.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||
min, max := market0.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||
return min, max, nil
|
||||
|
||||
case actors.Version2:
|
||||
|
||||
return market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
min, max := market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
return min, max, nil
|
||||
|
||||
case actors.Version3:
|
||||
|
||||
return market3.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
min, max := market3.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
return min, max, nil
|
||||
|
||||
case actors.Version4:
|
||||
|
||||
return market4.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
min, max := market4.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
return min, max, nil
|
||||
|
||||
case actors.Version5:
|
||||
|
||||
return market5.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
min, max := market5.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
return min, max, nil
|
||||
|
||||
default:
|
||||
panic("unsupported actors version")
|
||||
return big.Zero(), big.Zero(), xerrors.Errorf("unsupported actors version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,13 +315,20 @@ func GetMaxSectorExpirationExtension() abi.ChainEpoch {
|
||||
return miner5.MaxSectorExpirationExtension
|
||||
}
|
||||
|
||||
func GetMinSectorExpiration() abi.ChainEpoch {
|
||||
return miner5.MinSectorExpiration
|
||||
}
|
||||
|
||||
func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, error) {
|
||||
sectorsPerPart, err := builtin5.PoStProofWindowPoStPartitionSectors(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
maxSectors := uint64(GetAddressedSectorsMax(nv))
|
||||
return int(maxSectors / sectorsPerPart), nil
|
||||
maxSectors, err := GetAddressedSectorsMax(nv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(uint64(maxSectors) / sectorsPerPart), nil
|
||||
}
|
||||
|
||||
func GetDefaultSectorSize() abi.SectorSize {
|
||||
@@ -345,82 +362,94 @@ func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version)
|
||||
return builtin5.SealProofPoliciesV11[proof].SectorMaxLifetime
|
||||
}
|
||||
|
||||
func GetAddressedSectorsMax(nwVer network.Version) int {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func GetAddressedSectorsMax(nwVer network.Version) (int, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v {
|
||||
|
||||
case actors.Version0:
|
||||
return miner0.AddressedSectorsMax
|
||||
return miner0.AddressedSectorsMax, nil
|
||||
|
||||
case actors.Version2:
|
||||
return miner2.AddressedSectorsMax
|
||||
return miner2.AddressedSectorsMax, nil
|
||||
|
||||
case actors.Version3:
|
||||
return miner3.AddressedSectorsMax
|
||||
return miner3.AddressedSectorsMax, nil
|
||||
|
||||
case actors.Version4:
|
||||
return miner4.AddressedSectorsMax
|
||||
return miner4.AddressedSectorsMax, nil
|
||||
|
||||
case actors.Version5:
|
||||
return miner5.AddressedSectorsMax
|
||||
return miner5.AddressedSectorsMax, nil
|
||||
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return 0, xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeclarationsMax(nwVer network.Version) int {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func GetDeclarationsMax(nwVer network.Version) (int, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v {
|
||||
|
||||
case actors.Version0:
|
||||
|
||||
// TODO: Should we instead panic here since the concept doesn't exist yet?
|
||||
return miner0.AddressedPartitionsMax
|
||||
// TODO: Should we instead error here since the concept doesn't exist yet?
|
||||
return miner0.AddressedPartitionsMax, nil
|
||||
|
||||
case actors.Version2:
|
||||
|
||||
return miner2.DeclarationsMax
|
||||
return miner2.DeclarationsMax, nil
|
||||
|
||||
case actors.Version3:
|
||||
|
||||
return miner3.DeclarationsMax
|
||||
return miner3.DeclarationsMax, nil
|
||||
|
||||
case actors.Version4:
|
||||
|
||||
return miner4.DeclarationsMax
|
||||
return miner4.DeclarationsMax, nil
|
||||
|
||||
case actors.Version5:
|
||||
|
||||
return miner5.DeclarationsMax
|
||||
return miner5.DeclarationsMax, nil
|
||||
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return 0, xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) abi.TokenAmount {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
switch v {
|
||||
|
||||
case actors.Version0:
|
||||
|
||||
return big.Zero()
|
||||
return big.Zero(), nil
|
||||
|
||||
case actors.Version2:
|
||||
|
||||
return big.Zero()
|
||||
return big.Zero(), nil
|
||||
|
||||
case actors.Version3:
|
||||
|
||||
return big.Zero()
|
||||
return big.Zero(), nil
|
||||
|
||||
case actors.Version4:
|
||||
|
||||
return big.Zero()
|
||||
return big.Zero(), nil
|
||||
|
||||
case actors.Version5:
|
||||
|
||||
return miner5.AggregateNetworkFee(aggregateSize, baseFee)
|
||||
return miner5.AggregateNetworkFee(aggregateSize, baseFee), nil
|
||||
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return big.Zero(), xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
@@ -117,18 +118,18 @@ func SetMinVerifiedDealSize(size abi.StoragePower) {
|
||||
{{end}}
|
||||
}
|
||||
|
||||
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch {
|
||||
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) (abi.ChainEpoch, error) {
|
||||
switch ver {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
{{if (eq . 0)}}
|
||||
return miner{{.}}.MaxSealDuration[t]
|
||||
return miner{{.}}.MaxSealDuration[t], nil
|
||||
{{else}}
|
||||
return miner{{.}}.MaxProveCommitDuration[t]
|
||||
return miner{{.}}.MaxProveCommitDuration[t], nil
|
||||
{{end}}
|
||||
{{end}}
|
||||
default:
|
||||
panic("unsupported actors version")
|
||||
return 0, xerrors.Errorf("unsupported actors version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,18 +151,24 @@ func DealProviderCollateralBounds(
|
||||
size abi.PaddedPieceSize, verified bool,
|
||||
rawBytePower, qaPower, baselinePower abi.StoragePower,
|
||||
circulatingFil abi.TokenAmount, nwVer network.Version,
|
||||
) (min, max abi.TokenAmount) {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
) (min, max abi.TokenAmount, err error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return big.Zero(), big.Zero(), err
|
||||
}
|
||||
switch v {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
{{if (eq . 0)}}
|
||||
return market{{.}}.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||
min, max := market{{.}}.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||
return min, max, nil
|
||||
{{else}}
|
||||
return market{{.}}.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
min, max := market{{.}}.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
return min, max, nil
|
||||
{{end}}
|
||||
{{end}}
|
||||
default:
|
||||
panic("unsupported actors version")
|
||||
return big.Zero(), big.Zero(), xerrors.Errorf("unsupported actors version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,13 +203,20 @@ func GetMaxSectorExpirationExtension() abi.ChainEpoch {
|
||||
return miner{{.latestVersion}}.MaxSectorExpirationExtension
|
||||
}
|
||||
|
||||
func GetMinSectorExpiration() abi.ChainEpoch {
|
||||
return miner{{.latestVersion}}.MinSectorExpiration
|
||||
}
|
||||
|
||||
func GetMaxPoStPartitions(nv network.Version, p abi.RegisteredPoStProof) (int, error) {
|
||||
sectorsPerPart, err := builtin{{.latestVersion}}.PoStProofWindowPoStPartitionSectors(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
maxSectors := uint64(GetAddressedSectorsMax(nv))
|
||||
return int(maxSectors / sectorsPerPart), nil
|
||||
maxSectors, err := GetAddressedSectorsMax(nv)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(uint64(maxSectors) / sectorsPerPart), nil
|
||||
}
|
||||
|
||||
func GetDefaultSectorSize() abi.SectorSize {
|
||||
@@ -236,44 +250,56 @@ func GetSectorMaxLifetime(proof abi.RegisteredSealProof, nwVer network.Version)
|
||||
return builtin{{.latestVersion}}.SealProofPoliciesV11[proof].SectorMaxLifetime
|
||||
}
|
||||
|
||||
func GetAddressedSectorsMax(nwVer network.Version) int {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func GetAddressedSectorsMax(nwVer network.Version) (int, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
return miner{{.}}.AddressedSectorsMax
|
||||
return miner{{.}}.AddressedSectorsMax, nil
|
||||
{{end}}
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return 0, xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
func GetDeclarationsMax(nwVer network.Version) int {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func GetDeclarationsMax(nwVer network.Version) (int, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch v {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
{{if (eq . 0)}}
|
||||
// TODO: Should we instead panic here since the concept doesn't exist yet?
|
||||
return miner{{.}}.AddressedPartitionsMax
|
||||
// TODO: Should we instead error here since the concept doesn't exist yet?
|
||||
return miner{{.}}.AddressedPartitionsMax, nil
|
||||
{{else}}
|
||||
return miner{{.}}.DeclarationsMax
|
||||
return miner{{.}}.DeclarationsMax, nil
|
||||
{{end}}
|
||||
{{end}}
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return 0, xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) abi.TokenAmount {
|
||||
switch actors.VersionForNetwork(nwVer) {
|
||||
func AggregateNetworkFee(nwVer network.Version, aggregateSize int, baseFee abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
v, err := actors.VersionForNetwork(nwVer)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
switch v {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
{{if (le . 4)}}
|
||||
return big.Zero()
|
||||
return big.Zero(), nil
|
||||
{{else}}
|
||||
return miner{{.}}.AggregateNetworkFee(aggregateSize, baseFee)
|
||||
return miner{{.}}.AggregateNetworkFee(aggregateSize, baseFee), nil
|
||||
{{end}}
|
||||
{{end}}
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
return big.Zero(), xerrors.Errorf("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,19 +21,19 @@ const (
|
||||
)
|
||||
|
||||
// Converts a network version into an actors adt version.
|
||||
func VersionForNetwork(version network.Version) Version {
|
||||
func VersionForNetwork(version network.Version) (Version, error) {
|
||||
switch version {
|
||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||
return Version0
|
||||
case network.Version4, network.Version5, network.Version6, network.Version6AndAHalf, network.Version7, network.Version8, network.Version9:
|
||||
return Version2
|
||||
return Version0, nil
|
||||
case network.Version4, network.Version5, network.Version6, network.Version7, network.Version8, network.Version9:
|
||||
return Version2, nil
|
||||
case network.Version10, network.Version11:
|
||||
return Version3
|
||||
return Version3, nil
|
||||
case network.Version12:
|
||||
return Version4
|
||||
return Version4, nil
|
||||
case network.Version13:
|
||||
return Version5
|
||||
return Version5, nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||
return -1, fmt.Errorf("unsupported network version %d", version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package exchange
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
var _ = cid.Undef
|
||||
var _ = math.E
|
||||
var _ = sort.Sort
|
||||
|
||||
var lengthBufRequest = []byte{131}
|
||||
|
||||
+2
-2
@@ -233,7 +233,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
||||
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, bs, ds, sys, j)
|
||||
cs := store.NewChainStore(bs, bs, ds, j)
|
||||
|
||||
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
||||
@@ -247,7 +247,7 @@ func NewGeneratorWithSectorsAndUpgradeSchedule(numSectors int, us stmgr.UpgradeS
|
||||
mgen[genesis2.MinerAddress(uint64(i))] = &wppProvider{}
|
||||
}
|
||||
|
||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(cs, us)
|
||||
sm, err := stmgr.NewStateManagerWithUpgradeSchedule(cs, sys, us)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("initing stmgr: %w", err)
|
||||
}
|
||||
|
||||
@@ -149,7 +149,10 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
|
||||
av := actors.VersionForNetwork(template.NetworkVersion)
|
||||
av, err := actors.VersionForNetwork(template.NetworkVersion)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("getting network version: %w", err)
|
||||
}
|
||||
|
||||
// Create system actor
|
||||
|
||||
@@ -471,7 +474,7 @@ func createMultisigAccount(ctx context.Context, cst cbor.IpldStore, state *state
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot cid.Cid, template genesis.Template, keyIDs map[address.Address]address.Address, nv network.Version) (cid.Cid, error) {
|
||||
func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, sys vm.SyscallBuilder, stateroot cid.Cid, template genesis.Template, keyIDs map[address.Address]address.Address, nv network.Version) (cid.Cid, error) {
|
||||
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
|
||||
var sum abi.PaddedPieceSize
|
||||
|
||||
@@ -480,7 +483,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.StateBlockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
Syscalls: mkFakedSigSyscalls(sys),
|
||||
CircSupplyCalc: nil,
|
||||
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
||||
return nv
|
||||
@@ -559,15 +562,15 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
|
||||
}
|
||||
|
||||
// temp chainstore
|
||||
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), sys, j)
|
||||
cs := store.NewChainStore(bs, bs, datastore.NewMapDatastore(), j)
|
||||
|
||||
// Verify PreSealed Data
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs, template.NetworkVersion)
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, sys, stateroot, template, keyIDs, template.NetworkVersion)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to verify presealed data: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, template.Miners, template.NetworkVersion)
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, sys, stateroot, template.Miners, template.NetworkVersion)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup miners failed: %w", err)
|
||||
}
|
||||
|
||||
+49
-34
@@ -6,30 +6,6 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
power4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power"
|
||||
|
||||
reward4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward"
|
||||
|
||||
market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -39,12 +15,28 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||
reward2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/reward"
|
||||
market4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market"
|
||||
power4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power"
|
||||
reward4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward"
|
||||
runtime5 "github.com/filecoin-project/specs-actors/v5/actors/runtime"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -78,10 +70,13 @@ func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder {
|
||||
}
|
||||
|
||||
// Note: Much of this is brittle, if the methodNum / param / return changes, it will break things
|
||||
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, miners []genesis.Miner, nv network.Version) (cid.Cid, error) {
|
||||
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.SyscallBuilder, sroot cid.Cid, miners []genesis.Miner, nv network.Version) (cid.Cid, error) {
|
||||
|
||||
cst := cbor.NewCborStore(cs.StateBlockstore())
|
||||
av := actors.VersionForNetwork(nv)
|
||||
av, err := actors.VersionForNetwork(nv)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to get network version: %w", err)
|
||||
}
|
||||
|
||||
csc := func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) {
|
||||
return big.Zero(), nil
|
||||
@@ -92,7 +87,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
Epoch: 0,
|
||||
Rand: &fakeRand{},
|
||||
Bstore: cs.StateBlockstore(),
|
||||
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
|
||||
Syscalls: mkFakedSigSyscalls(sys),
|
||||
CircSupplyCalc: csc,
|
||||
NtwkVersion: func(_ context.Context, _ abi.ChainEpoch) network.Version {
|
||||
return nv
|
||||
@@ -291,7 +286,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, xerrors.Errorf("setting power state: %w", err)
|
||||
}
|
||||
|
||||
rewact, err := SetupRewardActor(ctx, cs.StateBlockstore(), big.Zero(), actors.VersionForNetwork(nv))
|
||||
rewact, err := SetupRewardActor(ctx, cs.StateBlockstore(), big.Zero(), av)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("setup reward actor: %w", err)
|
||||
}
|
||||
@@ -401,8 +396,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
|
||||
if av > actors.Version2 {
|
||||
// post v2, we need to explicitly Claim this power since ConfirmSectorProofsValid doesn't do it anymore
|
||||
if av >= actors.Version2 {
|
||||
// post v0, we need to explicitly Claim this power since ConfirmSectorProofsValid doesn't do it anymore
|
||||
claimParams := &power4.UpdateClaimedPowerParams{
|
||||
RawByteDelta: types.NewInt(uint64(m.SectorSize)),
|
||||
QualityAdjustedDelta: sectorWeight,
|
||||
@@ -534,7 +529,6 @@ func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs [
|
||||
SectorExpiry: sectorExpiry,
|
||||
}
|
||||
|
||||
var dealWeights market0.VerifyDealsForActivationReturn
|
||||
ret, err := doExecValue(ctx, vm,
|
||||
market.Address,
|
||||
maddr,
|
||||
@@ -545,11 +539,23 @@ func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs [
|
||||
if err != nil {
|
||||
return big.Zero(), big.Zero(), err
|
||||
}
|
||||
if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
var weight, verifiedWeight abi.DealWeight
|
||||
if av < actors.Version2 {
|
||||
var dealWeights market0.VerifyDealsForActivationReturn
|
||||
err = dealWeights.UnmarshalCBOR(bytes.NewReader(ret))
|
||||
weight = dealWeights.DealWeight
|
||||
verifiedWeight = dealWeights.VerifiedDealWeight
|
||||
} else {
|
||||
var dealWeights market2.VerifyDealsForActivationReturn
|
||||
err = dealWeights.UnmarshalCBOR(bytes.NewReader(ret))
|
||||
weight = dealWeights.DealWeight
|
||||
verifiedWeight = dealWeights.VerifiedDealWeight
|
||||
}
|
||||
if err != nil {
|
||||
return big.Zero(), big.Zero(), err
|
||||
}
|
||||
|
||||
return dealWeights.DealWeight, dealWeights.VerifiedDealWeight, nil
|
||||
return weight, verifiedWeight, nil
|
||||
}
|
||||
params := &market4.VerifyDealsForActivationParams{Sectors: []market4.SectorDeals{{
|
||||
SectorExpiry: sectorExpiry,
|
||||
@@ -581,7 +587,8 @@ func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Addre
|
||||
}
|
||||
|
||||
// TODO: This hack should move to reward actor wrapper
|
||||
if av <= actors.Version2 {
|
||||
switch av {
|
||||
case actors.Version0:
|
||||
var epochReward reward0.ThisEpochRewardReturn
|
||||
|
||||
if err := epochReward.UnmarshalCBOR(bytes.NewReader(rwret)); err != nil {
|
||||
@@ -589,6 +596,14 @@ func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Addre
|
||||
}
|
||||
|
||||
return epochReward.ThisEpochBaselinePower, *epochReward.ThisEpochRewardSmoothed, nil
|
||||
case actors.Version2:
|
||||
var epochReward reward2.ThisEpochRewardReturn
|
||||
|
||||
if err := epochReward.UnmarshalCBOR(bytes.NewReader(rwret)); err != nil {
|
||||
return big.Zero(), builtin.FilterEstimate{}, err
|
||||
}
|
||||
|
||||
return epochReward.ThisEpochBaselinePower, builtin.FilterEstimate(epochReward.ThisEpochRewardSmoothed), nil
|
||||
}
|
||||
|
||||
var epochReward reward4.ThisEpochRewardReturn
|
||||
|
||||
@@ -5,6 +5,7 @@ package market
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
var _ = cid.Undef
|
||||
var _ = math.E
|
||||
var _ = sort.Sort
|
||||
|
||||
var lengthBufFundedAddressState = []byte{131}
|
||||
|
||||
@@ -281,7 +281,7 @@ func (mp *MessagePool) checkMessages(ctx context.Context, msgs []*types.Message,
|
||||
// gas checks
|
||||
|
||||
// 4. Min Gas
|
||||
minGas := vm.PricelistByVersion(nv).OnChainMessage(m.ChainLength())
|
||||
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength())
|
||||
|
||||
check = api.MessageCheckStatus{
|
||||
Cid: m.Cid(),
|
||||
|
||||
@@ -616,7 +616,8 @@ func (mp *MessagePool) addLocal(ctx context.Context, m *types.SignedMessage) err
|
||||
// For non local messages, if the message cannot be included in the next 20 blocks it returns
|
||||
// a (soft) validation error.
|
||||
func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) {
|
||||
minGas := vm.PricelistByVersion(build.NewestNetworkVersion).OnChainMessage(m.ChainLength())
|
||||
epoch := curTs.Height()
|
||||
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength())
|
||||
|
||||
if err := m.VMMessage().ValidForBlockInclusion(minGas.Total(), build.NewestNetworkVersion); err != nil {
|
||||
return false, xerrors.Errorf("message will not be included in a block: %w", err)
|
||||
|
||||
@@ -749,7 +749,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
|
||||
}
|
||||
curNonce++
|
||||
|
||||
minGas := vm.PricelistByVersion(build.NewestNetworkVersion).OnChainMessage(m.ChainLength()).Total()
|
||||
minGas := vm.PricelistByEpoch(ts.Height()).OnChainMessage(m.ChainLength()).Total()
|
||||
if m.Message.GasLimit < minGas {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"go.uber.org/fx"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||
)
|
||||
|
||||
var log = logging.Logger("metrics")
|
||||
|
||||
const baseTopic = "/fil/headnotifs/"
|
||||
|
||||
type Update struct {
|
||||
Type string
|
||||
}
|
||||
|
||||
func SendHeadNotifs(nickname string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, chain full.ChainAPI) error {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, chain full.ChainAPI) error {
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(_ context.Context) error {
|
||||
gen, err := chain.Chain.GetGenesis()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
topic := baseTopic + gen.Cid().String()
|
||||
|
||||
go func() {
|
||||
if err := sendHeadNotifs(ctx, ps, topic, chain, nickname); err != nil {
|
||||
log.Error("consensus metrics error", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
sub, err := ps.Subscribe(topic) //nolint
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer sub.Cancel()
|
||||
|
||||
for {
|
||||
if _, err := sub.Next(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type message struct {
|
||||
// TipSet
|
||||
Cids []cid.Cid
|
||||
Blocks []*types.BlockHeader
|
||||
Height abi.ChainEpoch
|
||||
Weight types.BigInt
|
||||
Time uint64
|
||||
Nonce uint64
|
||||
|
||||
// Meta
|
||||
|
||||
NodeName string
|
||||
}
|
||||
|
||||
func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain full.ChainAPI, nickname string) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
notifs, err := chain.ChainNotify(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// using unix nano time makes very sure we pick a nonce higher than previous restart
|
||||
nonce := uint64(build.Clock.Now().UnixNano())
|
||||
|
||||
for {
|
||||
select {
|
||||
case notif := <-notifs:
|
||||
n := notif[len(notif)-1]
|
||||
|
||||
w, err := chain.ChainTipSetWeight(ctx, n.Val.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := message{
|
||||
Cids: n.Val.Cids(),
|
||||
Blocks: n.Val.Blocks(),
|
||||
Height: n.Val.Height(),
|
||||
Weight: w,
|
||||
NodeName: nickname,
|
||||
Time: uint64(build.Clock.Now().UnixNano() / 1000_000),
|
||||
Nonce: nonce,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint
|
||||
if err := ps.Publish(topic, b); err != nil {
|
||||
return err
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
}
|
||||
|
||||
nonce++
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("failed to load state tree: %s", err)
|
||||
return nil, xerrors.Errorf("failed to load state tree: %w", err)
|
||||
return nil, xerrors.Errorf("failed to load state tree %s: %w", c, err)
|
||||
}
|
||||
|
||||
s := &StateTree{
|
||||
|
||||
@@ -0,0 +1,551 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"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/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
)
|
||||
|
||||
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
state, err := sm.StateTree(st)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load state tree: %w", err)
|
||||
}
|
||||
act, err := state.GetActor(maddr)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("failed to load actor info: %w", err)
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
||||
}
|
||||
|
||||
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
|
||||
}
|
||||
|
||||
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, power.Address, st)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, xerrors.Errorf("(get sset) failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
pas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
|
||||
tpow, err := pas.TotalPower()
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
|
||||
var mpow power.Claim
|
||||
var minpow bool
|
||||
if maddr != address.Undef {
|
||||
var found bool
|
||||
mpow, found, err = pas.MinerPower(maddr)
|
||||
if err != nil || !found {
|
||||
return power.Claim{}, tpow, false, err
|
||||
}
|
||||
|
||||
minpow, err = pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return mpow, tpow, minpow, nil
|
||||
}
|
||||
|
||||
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorPreCommitOnChainInfo, error) {
|
||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.GetPrecommittedSector(sid)
|
||||
}
|
||||
|
||||
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
|
||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.GetSector(sid)
|
||||
}
|
||||
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, nv network.Version, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]builtin.SectorInfo, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
var provingSectors bitfield.BitField
|
||||
if nv < network.Version7 {
|
||||
allSectors, err := miner.AllPartSectors(mas, miner.Partition.AllSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get all sectors: %w", err)
|
||||
}
|
||||
|
||||
faultySectors, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get faulty sectors: %w", err)
|
||||
}
|
||||
|
||||
provingSectors, err = bitfield.SubtractBitField(allSectors, faultySectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("calc proving sectors: %w", err)
|
||||
}
|
||||
} else {
|
||||
provingSectors, err = miner.AllPartSectors(mas, miner.Partition.ActiveSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get active sectors sectors: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
numProvSect, err := provingSectors.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
||||
}
|
||||
|
||||
// TODO(review): is this right? feels fishy to me
|
||||
if numProvSect == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
mid, err := address.IDFromAddress(maddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
||||
}
|
||||
|
||||
proofType, err := miner.WinningPoStProofTypeFromWindowPoStProofType(nv, info.WindowPoStProofType)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("determining winning post proof type: %w", err)
|
||||
}
|
||||
|
||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, proofType, abi.ActorID(mid), rand, numProvSect)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
||||
}
|
||||
|
||||
iter, err := provingSectors.BitIterator()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||
}
|
||||
|
||||
// Select winning sectors by _index_ in the all-sectors bitfield.
|
||||
selectedSectors := bitfield.New()
|
||||
prev := uint64(0)
|
||||
for _, n := range ids {
|
||||
sno, err := iter.Nth(n - prev)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||
}
|
||||
selectedSectors.Set(sno)
|
||||
prev = n
|
||||
}
|
||||
|
||||
sectors, err := mas.LoadSectors(&selectedSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading proving sectors: %w", err)
|
||||
}
|
||||
|
||||
out := make([]builtin.SectorInfo, len(sectors))
|
||||
for i, sinfo := range sectors {
|
||||
out[i] = builtin.SectorInfo{
|
||||
SealProof: sinfo.SealProof,
|
||||
SectorNumber: sinfo.SectorNumber,
|
||||
SealedCID: sinfo.SealedCID,
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
spas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
_, ok, err := spas.MinerPower(maddr)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("getting miner power: %w", err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
act, err := sm.LoadActor(ctx, market.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load market actor: %w", err)
|
||||
}
|
||||
|
||||
state, err := market.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load market actor state: %w", err)
|
||||
}
|
||||
|
||||
proposals, err := state.Proposals()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proposal, found, err := proposals.Get(dealID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !found {
|
||||
return nil, xerrors.Errorf(
|
||||
"deal %d not found "+
|
||||
"- deal may not have completed sealing before deal proposal "+
|
||||
"start epoch, or deal may have been slashed",
|
||||
dealID)
|
||||
}
|
||||
|
||||
states, err := state.States()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, found, err := states.Get(dealID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !found {
|
||||
st = market.EmptyDealState()
|
||||
}
|
||||
|
||||
return &api.MarketDeal{
|
||||
Proposal: *proposal,
|
||||
State: *st,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
powState, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
return powState.ListAllMiners()
|
||||
}
|
||||
|
||||
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) {
|
||||
ts, err := sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
|
||||
}
|
||||
|
||||
prev, err := sm.ChainStore().GetLatestBeaconEntry(ts)
|
||||
if err != nil {
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") != "_yes_" {
|
||||
return nil, xerrors.Errorf("failed to get latest beacon entry: %w", err)
|
||||
}
|
||||
|
||||
prev = &types.BeaconEntry{}
|
||||
}
|
||||
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rbase := *prev
|
||||
if len(entries) > 0 {
|
||||
rbase = entries[len(entries)-1]
|
||||
}
|
||||
|
||||
lbts, lbst, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
||||
}
|
||||
|
||||
act, err := sm.LoadActorRaw(ctx, maddr, lbst)
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
_, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading miner in current state: %w", err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := maddr.MarshalCBOR(buf); err != nil {
|
||||
return nil, xerrors.Errorf("failed to marshal miner address: %w", err)
|
||||
}
|
||||
|
||||
prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
||||
}
|
||||
|
||||
nv := sm.GetNtwkVersion(ctx, ts.Height())
|
||||
|
||||
sectors, err := GetSectorsForWinningPoSt(ctx, nv, pv, sm, lbst, maddr, prand)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
|
||||
}
|
||||
|
||||
if len(sectors) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Not ideal performance...This method reloads miner and power state (already looked up here and in GetPowerRaw)
|
||||
eligible, err := MinerEligibleToMine(ctx, sm, maddr, ts, lbts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("determining miner eligibility: %w", err)
|
||||
}
|
||||
|
||||
return &api.MiningBaseInfo{
|
||||
MinerPower: mpow.QualityAdjPower,
|
||||
NetworkPower: tpow.QualityAdjPower,
|
||||
Sectors: sectors,
|
||||
WorkerKey: worker,
|
||||
SectorSize: info.SectorSize,
|
||||
PrevBeaconEntry: *prev,
|
||||
BeaconEntries: entries,
|
||||
EligibleForMining: eligible,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||
}
|
||||
|
||||
ps, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
||||
}
|
||||
|
||||
func MinerEligibleToMine(ctx context.Context, sm *StateManager, addr address.Address, baseTs *types.TipSet, lookbackTs *types.TipSet) (bool, error) {
|
||||
hmp, err := minerHasMinPower(ctx, sm, addr, lookbackTs)
|
||||
|
||||
// TODO: We're blurring the lines between a "runtime network version" and a "Lotus upgrade epoch", is that unavoidable?
|
||||
if sm.GetNtwkVersion(ctx, baseTs.Height()) <= network.Version3 {
|
||||
return hmp, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !hmp {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Post actors v2, also check MinerEligibleForElection with base ts
|
||||
|
||||
pact, err := sm.LoadActor(ctx, power.Address, baseTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||
}
|
||||
|
||||
pstate, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
mact, err := sm.LoadActor(ctx, addr, baseTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading miner actor state: %w", err)
|
||||
}
|
||||
|
||||
mstate, err := miner.Load(sm.cs.ActorStore(ctx), mact)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Non-empty power claim.
|
||||
if claim, found, err := pstate.MinerPower(addr); err != nil {
|
||||
return false, err
|
||||
} else if !found {
|
||||
return false, err
|
||||
} else if claim.QualityAdjPower.LessThanEqual(big.Zero()) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// No fee debt.
|
||||
if debt, err := mstate.FeeDebt(); err != nil {
|
||||
return false, err
|
||||
} else if !debt.IsZero() {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// No active consensus faults.
|
||||
if mInfo, err := mstate.Info(); err != nil {
|
||||
return false, err
|
||||
} else if baseTs.Height() <= mInfo.ConsensusFaultElapsed {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
||||
st, err := sm.ParentState(ts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
act, err := st.GetActor(addr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
actState, err := paych.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return act, actState, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (market.State, error) {
|
||||
st, err := sm.ParentState(ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
act, err := st.GetActor(market.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actState, err := market.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return actState, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MarketBalance, error) {
|
||||
mstate, err := sm.GetMarketState(ctx, ts)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
|
||||
addr, err = sm.LookupID(ctx, addr, ts)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
|
||||
var out api.MarketBalance
|
||||
|
||||
et, err := mstate.EscrowTable()
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
out.Escrow, err = et.Get(addr)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, xerrors.Errorf("getting escrow balance: %w", err)
|
||||
}
|
||||
|
||||
lt, err := mstate.LockedTable()
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
out.Locked, err = lt.Get(addr)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, xerrors.Errorf("getting locked balance: %w", err)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
var _ StateManagerAPI = (*StateManager)(nil)
|
||||
+2
-2
@@ -64,7 +64,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
|
||||
Epoch: pheight + 1,
|
||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
Syscalls: sm.syscalls,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: types.NewInt(0),
|
||||
@@ -179,7 +179,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
Epoch: ts.Height() + 1,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
Syscalls: sm.syscalls,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/cron"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
)
|
||||
|
||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, em ExecMonitor, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) {
|
||||
done := metrics.Timer(ctx, metrics.VMApplyBlocksTotal)
|
||||
defer done()
|
||||
|
||||
partDone := metrics.Timer(ctx, metrics.VMApplyEarly)
|
||||
defer func() {
|
||||
partDone()
|
||||
}()
|
||||
|
||||
makeVmWithBaseState := func(base cid.Cid) (*vm.VM, error) {
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: epoch,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Syscalls: sm.syscalls,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
||||
}
|
||||
|
||||
return sm.newVM(ctx, vmopt)
|
||||
}
|
||||
|
||||
vmi, err := makeVmWithBaseState(pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||
}
|
||||
|
||||
runCron := func(epoch abi.ChainEpoch) error {
|
||||
cronMsg := &types.Message{
|
||||
To: cron.Address,
|
||||
From: builtin.SystemActorAddr,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little
|
||||
Method: cron.Methods.EpochTick,
|
||||
Params: nil,
|
||||
}
|
||||
ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if em != nil {
|
||||
if err := em.MessageApplied(ctx, ts, cronMsg.Cid(), cronMsg, ret, true); err != nil {
|
||||
return xerrors.Errorf("callback failed on cron message: %w", err)
|
||||
}
|
||||
}
|
||||
if ret.ExitCode != 0 {
|
||||
return xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := parentEpoch; i < epoch; i++ {
|
||||
if i > parentEpoch {
|
||||
// run cron for null rounds if any
|
||||
if err := runCron(i); err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
pstate, err = vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// handle state forks
|
||||
// XXX: The state tree
|
||||
newState, err := sm.handleStateForks(ctx, pstate, i, em, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
|
||||
if pstate != newState {
|
||||
vmi, err = makeVmWithBaseState(newState)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
vmi.SetBlockHeight(i + 1)
|
||||
pstate = newState
|
||||
}
|
||||
|
||||
partDone()
|
||||
partDone = metrics.Timer(ctx, metrics.VMApplyMessages)
|
||||
|
||||
var receipts []cbg.CBORMarshaler
|
||||
processedMsgs := make(map[cid.Cid]struct{})
|
||||
for _, b := range bms {
|
||||
penalty := types.NewInt(0)
|
||||
gasReward := big.Zero()
|
||||
|
||||
for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
|
||||
m := cm.VMMessage()
|
||||
if _, found := processedMsgs[m.Cid()]; found {
|
||||
continue
|
||||
}
|
||||
r, err := vmi.ApplyMessage(ctx, cm)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
receipts = append(receipts, &r.MessageReceipt)
|
||||
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
|
||||
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)
|
||||
|
||||
if em != nil {
|
||||
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
}
|
||||
processedMsgs[m.Cid()] = struct{}{}
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&reward.AwardBlockRewardParams{
|
||||
Miner: b.Miner,
|
||||
Penalty: penalty,
|
||||
GasReward: gasReward,
|
||||
WinCount: b.WinCount,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)
|
||||
}
|
||||
|
||||
rwMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasLimit: 1 << 30,
|
||||
Method: reward.Methods.AwardBlockReward,
|
||||
Params: params,
|
||||
}
|
||||
ret, actErr := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||
if actErr != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, actErr)
|
||||
}
|
||||
if em != nil {
|
||||
if err := em.MessageApplied(ctx, ts, rwMsg.Cid(), rwMsg, ret, true); err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("callback failed on reward message: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if ret.ExitCode != 0 {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("reward application message failed (exit %d): %s", ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
}
|
||||
|
||||
partDone()
|
||||
partDone = metrics.Timer(ctx, metrics.VMApplyCron)
|
||||
|
||||
if err := runCron(epoch); err != nil {
|
||||
return cid.Cid{}, cid.Cid{}, err
|
||||
}
|
||||
|
||||
partDone()
|
||||
partDone = metrics.Timer(ctx, metrics.VMApplyFlush)
|
||||
|
||||
rectarr := blockadt.MakeEmptyArray(sm.cs.ActorStore(ctx))
|
||||
for i, receipt := range receipts {
|
||||
if err := rectarr.Set(uint64(i), receipt); err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
||||
}
|
||||
}
|
||||
rectroot, err := rectarr.Root()
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
|
||||
}
|
||||
|
||||
st, err := vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("vm flush failed: %w", err)
|
||||
}
|
||||
|
||||
stats.Record(ctx, metrics.VMSends.M(int64(atomic.LoadUint64(&vm.StatSends))),
|
||||
metrics.VMApplied.M(int64(atomic.LoadUint64(&vm.StatApplied))))
|
||||
|
||||
return st, rectroot, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) {
|
||||
ctx, span := trace.StartSpan(ctx, "tipSetState")
|
||||
defer span.End()
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(trace.StringAttribute("tipset", fmt.Sprint(ts.Cids())))
|
||||
}
|
||||
|
||||
ck := cidsToKey(ts.Cids())
|
||||
sm.stlk.Lock()
|
||||
cw, cwok := sm.compWait[ck]
|
||||
if cwok {
|
||||
sm.stlk.Unlock()
|
||||
span.AddAttributes(trace.BoolAttribute("waited", true))
|
||||
select {
|
||||
case <-cw:
|
||||
sm.stlk.Lock()
|
||||
case <-ctx.Done():
|
||||
return cid.Undef, cid.Undef, ctx.Err()
|
||||
}
|
||||
}
|
||||
cached, ok := sm.stCache[ck]
|
||||
if ok {
|
||||
sm.stlk.Unlock()
|
||||
span.AddAttributes(trace.BoolAttribute("cache", true))
|
||||
return cached[0], cached[1], nil
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
sm.compWait[ck] = ch
|
||||
|
||||
defer func() {
|
||||
sm.stlk.Lock()
|
||||
delete(sm.compWait, ck)
|
||||
if st != cid.Undef {
|
||||
sm.stCache[ck] = []cid.Cid{st, rec}
|
||||
}
|
||||
sm.stlk.Unlock()
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
sm.stlk.Unlock()
|
||||
|
||||
if ts.Height() == 0 {
|
||||
// NB: This is here because the process that executes blocks requires that the
|
||||
// block miner reference a valid miner in the state tree. Unless we create some
|
||||
// magical genesis miner, this won't work properly, so we short circuit here
|
||||
// This avoids the question of 'who gets paid the genesis block reward'
|
||||
return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil
|
||||
}
|
||||
|
||||
st, rec, err = sm.computeTipSetState(ctx, ts, sm.tsExecMonitor)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
return st, rec, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) ExecutionTraceWithMonitor(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, error) {
|
||||
st, _, err := sm.computeTipSetState(ctx, ts, em)
|
||||
return st, err
|
||||
}
|
||||
|
||||
func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||
var invocTrace []*api.InvocResult
|
||||
st, err := sm.ExecutionTraceWithMonitor(ctx, ts, &InvocationTracer{trace: &invocTrace})
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
return st, invocTrace, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet, em ExecMonitor) (cid.Cid, cid.Cid, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "computeTipSetState")
|
||||
defer span.End()
|
||||
|
||||
blks := ts.Blocks()
|
||||
|
||||
for i := 0; i < len(blks); i++ {
|
||||
for j := i + 1; j < len(blks); j++ {
|
||||
if blks[i].Miner == blks[j].Miner {
|
||||
return cid.Undef, cid.Undef,
|
||||
xerrors.Errorf("duplicate miner in a tipset (%s %s)",
|
||||
blks[i].Miner, blks[j].Miner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var parentEpoch abi.ChainEpoch
|
||||
pstate := blks[0].ParentStateRoot
|
||||
if blks[0].Height > 0 {
|
||||
parent, err := sm.cs.GetBlock(blks[0].Parents[0])
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("getting parent block: %w", err)
|
||||
}
|
||||
|
||||
parentEpoch = parent.Height
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("getting block messages for tipset: %w", err)
|
||||
}
|
||||
|
||||
baseFee := blks[0].ParentBaseFee
|
||||
|
||||
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, em, baseFee, ts)
|
||||
}
|
||||
+8
-1080
File diff suppressed because it is too large
Load Diff
@@ -121,7 +121,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||
@@ -250,7 +250,7 @@ func TestForkRefuseCall(t *testing.T) {
|
||||
}
|
||||
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Expensive: true,
|
||||
Height: testForkHeight,
|
||||
@@ -365,7 +365,7 @@ func TestForkPreMigration(t *testing.T) {
|
||||
counter := make(chan struct{}, 10)
|
||||
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
cg.ChainStore(), cg.StateManager().VMSys(), UpgradeSchedule{{
|
||||
Network: network.Version1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cache MigrationCache, cb ExecMonitor,
|
||||
|
||||
@@ -31,6 +31,14 @@ func (sm *StateManager) ParentState(ts *types.TipSet) (*state.StateTree, error)
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
return ts.ParentState()
|
||||
}
|
||||
|
||||
func (sm *StateManager) StateTree(st cid.Cid) (*state.StateTree, error) {
|
||||
cst := cbor.NewCborStore(sm.cs.StateBlockstore())
|
||||
state, err := state.LoadStateTree(cst, st)
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
|
||||
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
|
||||
// chain for at least confidence epochs without being reverted before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
msg, err := sm.cs.GetCMessage(mcid)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err)
|
||||
}
|
||||
|
||||
tsub := sm.cs.SubHeadChanges(ctx)
|
||||
|
||||
head, ok := <-tsub
|
||||
if !ok {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("SubHeadChanges stream was invalid")
|
||||
}
|
||||
|
||||
if len(head) != 1 {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("SubHeadChanges first entry should have been one item")
|
||||
}
|
||||
|
||||
if head[0].Type != store.HCCurrent {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("expected current head on SHC stream (got %s)", head[0].Type)
|
||||
}
|
||||
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(head[0].Val, mcid, msg.VMMessage(), allowReplaced)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, err
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return head[0].Val, r, foundMsg, nil
|
||||
}
|
||||
|
||||
var backTs *types.TipSet
|
||||
var backRcp *types.MessageReceipt
|
||||
var backFm cid.Cid
|
||||
backSearchWait := make(chan struct{})
|
||||
go func() {
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit, allowReplaced)
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
backTs = fts
|
||||
backRcp = r
|
||||
backFm = foundMsg
|
||||
close(backSearchWait)
|
||||
}()
|
||||
|
||||
var candidateTs *types.TipSet
|
||||
var candidateRcp *types.MessageReceipt
|
||||
var candidateFm cid.Cid
|
||||
heightOfHead := head[0].Val.Height()
|
||||
reverts := map[types.TipSetKey]bool{}
|
||||
|
||||
for {
|
||||
select {
|
||||
case notif, ok := <-tsub:
|
||||
if !ok {
|
||||
return nil, nil, cid.Undef, ctx.Err()
|
||||
}
|
||||
for _, val := range notif {
|
||||
switch val.Type {
|
||||
case store.HCRevert:
|
||||
if val.Val.Equals(candidateTs) {
|
||||
candidateTs = nil
|
||||
candidateRcp = nil
|
||||
candidateFm = cid.Undef
|
||||
}
|
||||
if backSearchWait != nil {
|
||||
reverts[val.Val.Key()] = true
|
||||
}
|
||||
case store.HCApply:
|
||||
if candidateTs != nil && val.Val.Height() >= candidateTs.Height()+abi.ChainEpoch(confidence) {
|
||||
return candidateTs, candidateRcp, candidateFm, nil
|
||||
}
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(val.Val, mcid, msg.VMMessage(), allowReplaced)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, err
|
||||
}
|
||||
if r != nil {
|
||||
if confidence == 0 {
|
||||
return val.Val, r, foundMsg, err
|
||||
}
|
||||
candidateTs = val.Val
|
||||
candidateRcp = r
|
||||
candidateFm = foundMsg
|
||||
}
|
||||
heightOfHead = val.Val.Height()
|
||||
}
|
||||
}
|
||||
case <-backSearchWait:
|
||||
// check if we found the message in the chain and that is hasn't been reverted since we started searching
|
||||
if backTs != nil && !reverts[backTs.Key()] {
|
||||
// if head is at or past confidence interval, return immediately
|
||||
if heightOfHead >= backTs.Height()+abi.ChainEpoch(confidence) {
|
||||
return backTs, backRcp, backFm, nil
|
||||
}
|
||||
|
||||
// wait for confidence interval
|
||||
candidateTs = backTs
|
||||
candidateRcp = backRcp
|
||||
candidateFm = backFm
|
||||
}
|
||||
reverts = nil
|
||||
backSearchWait = nil
|
||||
case <-ctx.Done():
|
||||
return nil, nil, cid.Undef, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) SearchForMessage(ctx context.Context, head *types.TipSet, mcid cid.Cid, lookbackLimit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
msg, err := sm.cs.GetCMessage(mcid)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("failed to load message: %w", err)
|
||||
}
|
||||
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(head, mcid, msg.VMMessage(), allowReplaced)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, err
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return head, r, foundMsg, nil
|
||||
}
|
||||
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, lookbackLimit, allowReplaced)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message %s", mcid)
|
||||
return nil, nil, cid.Undef, err
|
||||
}
|
||||
|
||||
if fts == nil {
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
return fts, r, foundMsg, nil
|
||||
}
|
||||
|
||||
// searchBackForMsg searches up to limit tipsets backwards from the given
|
||||
// tipset for a message receipt.
|
||||
// If limit is
|
||||
// - 0 then no tipsets are searched
|
||||
// - 5 then five tipset are searched
|
||||
// - LookbackNoLimit then there is no limit
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch, allowReplaced bool) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
limitHeight := from.Height() - limit
|
||||
noLimit := limit == LookbackNoLimit
|
||||
|
||||
cur := from
|
||||
curActor, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset")
|
||||
}
|
||||
|
||||
mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err)
|
||||
}
|
||||
|
||||
mNonce := m.VMMessage().Nonce
|
||||
|
||||
for {
|
||||
// If we've reached the genesis block, or we've reached the limit of
|
||||
// how far back to look
|
||||
if cur.Height() == 0 || !noLimit && cur.Height() <= limitHeight {
|
||||
// it ain't here!
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, nil, cid.Undef, nil
|
||||
default:
|
||||
}
|
||||
|
||||
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||
// either way, no reason to lookback, it ain't there
|
||||
if curActor == nil || curActor.Nonce == 0 || curActor.Nonce < mNonce {
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
pts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
}
|
||||
|
||||
act, err := sm.LoadActor(ctx, mFromId, pts)
|
||||
actorNoExist := errors.Is(err, types.ErrActorNotFound)
|
||||
if err != nil && !actorNoExist {
|
||||
return nil, nil, cid.Cid{}, xerrors.Errorf("failed to load the actor: %w", err)
|
||||
}
|
||||
|
||||
// check that between cur and parent tipset the nonce fell into range of our message
|
||||
if actorNoExist || (curActor.Nonce > mNonce && act.Nonce <= mNonce) {
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(cur, m.Cid(), m.VMMessage(), allowReplaced)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return cur, r, foundMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
cur = pts
|
||||
curActor = act
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) tipsetExecutedMessage(ts *types.TipSet, msg cid.Cid, vmm *types.Message, allowReplaced bool) (*types.MessageReceipt, cid.Cid, error) {
|
||||
// The genesis block did not execute any messages
|
||||
if ts.Height() == 0 {
|
||||
return nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
pts, err := sm.cs.LoadTipSet(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
|
||||
cm, err := sm.cs.MessagesForTipset(pts)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
|
||||
for ii := range cm {
|
||||
// iterate in reverse because we going backwards through the chain
|
||||
i := len(cm) - ii - 1
|
||||
m := cm[i]
|
||||
|
||||
if m.VMMessage().From == vmm.From { // cheaper to just check origin first
|
||||
if m.VMMessage().Nonce == vmm.Nonce {
|
||||
if allowReplaced && m.VMMessage().EqualCall(vmm) {
|
||||
if m.Cid() != msg {
|
||||
log.Warnw("found message with equal nonce and call params but different CID",
|
||||
"wanted", msg, "found", m.Cid(), "nonce", vmm.Nonce, "from", vmm.From)
|
||||
}
|
||||
|
||||
pr, err := sm.cs.GetParentReceipt(ts.Blocks()[0], i)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
return pr, m.Cid(), nil
|
||||
}
|
||||
|
||||
// this should be that message
|
||||
return nil, cid.Undef, xerrors.Errorf("found message with equal nonce as the one we are looking for (F:%s n %d, TS: %s n%d)",
|
||||
msg, vmm.Nonce, m.Cid(), m.VMMessage().Nonce)
|
||||
}
|
||||
if m.VMMessage().Nonce < vmm.Nonce {
|
||||
return nil, cid.Undef, nil // don't bother looking further
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cid.Undef, nil
|
||||
}
|
||||
+13
-1149
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,473 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// sets up information about the vesting schedule
|
||||
func (sm *StateManager) setupGenesisVestingSchedule(ctx context.Context) error {
|
||||
|
||||
gb, err := sm.cs.GetGenesis()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis block: %w", err)
|
||||
}
|
||||
|
||||
gts, err := types.NewTipSet([]*types.BlockHeader{gb})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset: %w", err)
|
||||
}
|
||||
|
||||
st, _, err := sm.TipSetState(ctx, gts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis tipset state: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.StateBlockstore())
|
||||
sTree, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading state tree: %w", err)
|
||||
}
|
||||
|
||||
gmf, err := getFilMarketLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis market funds: %w", err)
|
||||
}
|
||||
|
||||
gp, err := getFilPowerLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis pledge: %w", err)
|
||||
}
|
||||
|
||||
sm.genesisMarketFunds = gmf
|
||||
sm.genesisPledge = gp
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixMonths] = big.NewInt(49_929_341)
|
||||
totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700))
|
||||
|
||||
// 1 year
|
||||
oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
|
||||
sm.preIgnitionVesting = make([]msig0.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := msig0.State{
|
||||
InitialBalance: v,
|
||||
UnlockDuration: k,
|
||||
PendingTxns: cid.Undef,
|
||||
}
|
||||
sm.preIgnitionVesting = append(sm.preIgnitionVesting, ns)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sets up information about the vesting schedule post the ignition upgrade
|
||||
func (sm *StateManager) setupPostIgnitionVesting(ctx context.Context) error {
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixMonths] = big.NewInt(49_929_341)
|
||||
totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700))
|
||||
|
||||
// 1 year
|
||||
oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
|
||||
sm.postIgnitionVesting = make([]msig0.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := msig0.State{
|
||||
// In the pre-ignition logic, we incorrectly set this value in Fil, not attoFil, an off-by-10^18 error
|
||||
InitialBalance: big.Mul(v, big.NewInt(int64(build.FilecoinPrecision))),
|
||||
UnlockDuration: k,
|
||||
PendingTxns: cid.Undef,
|
||||
// In the pre-ignition logic, the start epoch was 0. This changes in the fork logic of the Ignition upgrade itself.
|
||||
StartEpoch: build.UpgradeLiftoffHeight,
|
||||
}
|
||||
sm.postIgnitionVesting = append(sm.postIgnitionVesting, ns)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sets up information about the vesting schedule post the calico upgrade
|
||||
func (sm *StateManager) setupPostCalicoVesting(ctx context.Context) error {
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 0 days
|
||||
zeroDays := abi.ChainEpoch(0)
|
||||
totalsByEpoch[zeroDays] = big.NewInt(10_632_000)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixMonths] = big.NewInt(19_015_887)
|
||||
totalsByEpoch[sixMonths] = big.Add(totalsByEpoch[sixMonths], big.NewInt(32_787_700))
|
||||
|
||||
// 1 year
|
||||
oneYear := abi.ChainEpoch(365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
totalsByEpoch[oneYear] = big.Add(totalsByEpoch[oneYear], big.NewInt(9_400_000))
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
totalsByEpoch[threeYears] = big.Add(totalsByEpoch[threeYears], big.NewInt(898_958))
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(9_805_053))
|
||||
|
||||
sm.postCalicoVesting = make([]msig0.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := msig0.State{
|
||||
InitialBalance: big.Mul(v, big.NewInt(int64(build.FilecoinPrecision))),
|
||||
UnlockDuration: k,
|
||||
PendingTxns: cid.Undef,
|
||||
StartEpoch: build.UpgradeLiftoffHeight,
|
||||
}
|
||||
sm.postCalicoVesting = append(sm.postCalicoVesting, ns)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetVestedFunds returns all funds that have "left" actors that are in the genesis state:
|
||||
// - For Multisigs, it counts the actual amounts that have vested at the given epoch
|
||||
// - For Accounts, it counts max(currentBalance - genesisBalance, 0).
|
||||
func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
vf := big.Zero()
|
||||
if height <= build.UpgradeIgnitionHeight {
|
||||
for _, v := range sm.preIgnitionVesting {
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height))
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
} else if height <= build.UpgradeCalicoHeight {
|
||||
for _, v := range sm.postIgnitionVesting {
|
||||
// In the pre-ignition logic, we simply called AmountLocked(height), assuming startEpoch was 0.
|
||||
// The start epoch changed in the Ignition upgrade.
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height-v.StartEpoch))
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
} else {
|
||||
for _, v := range sm.postCalicoVesting {
|
||||
// In the pre-ignition logic, we simply called AmountLocked(height), assuming startEpoch was 0.
|
||||
// The start epoch changed in the Ignition upgrade.
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height-v.StartEpoch))
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
}
|
||||
|
||||
// After UpgradeAssemblyHeight these funds are accounted for in GetFilReserveDisbursed
|
||||
if height <= build.UpgradeAssemblyHeight {
|
||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||
vf = big.Add(vf, sm.genesisPledge)
|
||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||
vf = big.Add(vf, sm.genesisMarketFunds)
|
||||
}
|
||||
|
||||
return vf, nil
|
||||
}
|
||||
|
||||
func GetFilReserveDisbursed(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
ract, err := st.GetActor(builtin.ReserveAddress)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to get reserve actor: %w", err)
|
||||
}
|
||||
|
||||
// If money enters the reserve actor, this could lead to a negative term
|
||||
return big.Sub(big.NewFromGo(build.InitialFilReserved), ract.Balance), nil
|
||||
}
|
||||
|
||||
func GetFilMined(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
ractor, err := st.GetActor(reward.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load reward actor state: %w", err)
|
||||
}
|
||||
|
||||
rst, err := reward.Load(adt.WrapStore(ctx, st.Store), ractor)
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
}
|
||||
|
||||
return rst.TotalStoragePowerReward()
|
||||
}
|
||||
|
||||
func getFilMarketLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
act, err := st.GetActor(market.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load market actor: %w", err)
|
||||
}
|
||||
|
||||
mst, err := market.Load(adt.WrapStore(ctx, st.Store), act)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load market state: %w", err)
|
||||
}
|
||||
|
||||
return mst.TotalLocked()
|
||||
}
|
||||
|
||||
func getFilPowerLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
pactor, err := st.GetActor(power.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
pst, err := power.Load(adt.WrapStore(ctx, st.Store), pactor)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load power state: %w", err)
|
||||
}
|
||||
|
||||
return pst.TotalLocked()
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetFilLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
|
||||
filMarketLocked, err := getFilMarketLocked(ctx, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to get filMarketLocked: %w", err)
|
||||
}
|
||||
|
||||
filPowerLocked, err := getFilPowerLocked(ctx, st)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to get filPowerLocked: %w", err)
|
||||
}
|
||||
|
||||
return types.BigAdd(filMarketLocked, filPowerLocked), nil
|
||||
}
|
||||
|
||||
func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
burnt, err := st.GetActor(builtin.BurntFundsActorAddr)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load burnt actor: %w", err)
|
||||
}
|
||||
|
||||
return burnt.Balance, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
cs, err := sm.GetVMCirculatingSupplyDetailed(ctx, height, st)
|
||||
if err != nil {
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return cs.FilCirculating, err
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.preIgnitionVesting == nil || sm.genesisPledge.IsZero() || sm.genesisMarketFunds.IsZero() {
|
||||
err := sm.setupGenesisVestingSchedule(ctx)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup pre-ignition vesting schedule: %w", err)
|
||||
}
|
||||
}
|
||||
if sm.postIgnitionVesting == nil {
|
||||
err := sm.setupPostIgnitionVesting(ctx)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup post-ignition vesting schedule: %w", err)
|
||||
}
|
||||
}
|
||||
if sm.postCalicoVesting == nil {
|
||||
err := sm.setupPostCalicoVesting(ctx)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup post-calico vesting schedule: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
filVested, err := sm.GetFilVested(ctx, height, st)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||
}
|
||||
|
||||
filReserveDisbursed := big.Zero()
|
||||
if height > build.UpgradeAssemblyHeight {
|
||||
filReserveDisbursed, err = GetFilReserveDisbursed(ctx, st)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filReserveDisbursed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
filMined, err := GetFilMined(ctx, st)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filMined: %w", err)
|
||||
}
|
||||
|
||||
filBurnt, err := GetFilBurnt(ctx, st)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filBurnt: %w", err)
|
||||
}
|
||||
|
||||
filLocked, err := sm.GetFilLocked(ctx, st)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filLocked: %w", err)
|
||||
}
|
||||
|
||||
ret := types.BigAdd(filVested, filMined)
|
||||
ret = types.BigAdd(ret, filReserveDisbursed)
|
||||
ret = types.BigSub(ret, filBurnt)
|
||||
ret = types.BigSub(ret, filLocked)
|
||||
|
||||
if ret.LessThan(big.Zero()) {
|
||||
ret = big.Zero()
|
||||
}
|
||||
|
||||
return api.CirculatingSupply{
|
||||
FilVested: filVested,
|
||||
FilMined: filMined,
|
||||
FilBurnt: filBurnt,
|
||||
FilLocked: filLocked,
|
||||
FilCirculating: ret,
|
||||
FilReserveDisbursed: filReserveDisbursed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
circ := big.Zero()
|
||||
unCirc := big.Zero()
|
||||
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
|
||||
switch {
|
||||
case actor.Balance.IsZero():
|
||||
// Do nothing for zero-balance actors
|
||||
break
|
||||
case a == _init.Address ||
|
||||
a == reward.Address ||
|
||||
a == verifreg.Address ||
|
||||
// The power actor itself should never receive funds
|
||||
a == power.Address ||
|
||||
a == builtin.SystemActorAddr ||
|
||||
a == builtin.CronActorAddr ||
|
||||
a == builtin.BurntFundsActorAddr ||
|
||||
a == builtin.SaftAddress ||
|
||||
a == builtin.ReserveAddress:
|
||||
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
|
||||
case a == market.Address:
|
||||
mst, err := market.Load(sm.cs.ActorStore(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.TotalLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||
unCirc = big.Add(unCirc, lb)
|
||||
|
||||
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
|
||||
circ = big.Add(circ, actor.Balance)
|
||||
|
||||
case builtin.IsStorageMinerActor(actor.Code):
|
||||
mst, err := miner.Load(sm.cs.ActorStore(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab, err := mst.AvailableBalance(actor.Balance)
|
||||
|
||||
if err == nil {
|
||||
circ = big.Add(circ, ab)
|
||||
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
|
||||
} else {
|
||||
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
|
||||
// In this case, the actor's entire balance is considered "uncirculating"
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
}
|
||||
|
||||
case builtin.IsMultisigActor(actor.Code):
|
||||
mst, err := multisig.Load(sm.cs.ActorStore(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.LockedBalance(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab := big.Sub(actor.Balance, lb)
|
||||
circ = big.Add(circ, big.Max(ab, big.Zero()))
|
||||
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
|
||||
default:
|
||||
return xerrors.Errorf("unexpected actor: %s", a)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
total := big.Add(circ, unCirc)
|
||||
if !total.Equals(types.TotalFilecoinInt) {
|
||||
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
|
||||
}
|
||||
|
||||
return circ, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+119
-565
@@ -1,540 +1,38 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/rt"
|
||||
|
||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
||||
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
||||
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, init_.Address, st)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ias, err := init_.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return ias.NetworkName()
|
||||
}
|
||||
|
||||
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||
state, err := sm.StateTree(st)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load state tree: %w", err)
|
||||
}
|
||||
act, err := state.GetActor(maddr)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("failed to load actor info: %w", err)
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
||||
}
|
||||
|
||||
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
|
||||
}
|
||||
|
||||
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, power.Address, st)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, xerrors.Errorf("(get sset) failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
pas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
|
||||
tpow, err := pas.TotalPower()
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
|
||||
var mpow power.Claim
|
||||
var minpow bool
|
||||
if maddr != address.Undef {
|
||||
var found bool
|
||||
mpow, found, err = pas.MinerPower(maddr)
|
||||
if err != nil || !found {
|
||||
return power.Claim{}, tpow, false, err
|
||||
}
|
||||
|
||||
minpow, err = pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return mpow, tpow, minpow, nil
|
||||
}
|
||||
|
||||
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorPreCommitOnChainInfo, error) {
|
||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.GetPrecommittedSector(sid)
|
||||
}
|
||||
|
||||
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
|
||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
return mas.GetSector(sid)
|
||||
}
|
||||
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, nv network.Version, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]builtin.SectorInfo, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
var provingSectors bitfield.BitField
|
||||
if nv < network.Version7 {
|
||||
allSectors, err := miner.AllPartSectors(mas, miner.Partition.AllSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get all sectors: %w", err)
|
||||
}
|
||||
|
||||
faultySectors, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get faulty sectors: %w", err)
|
||||
}
|
||||
|
||||
provingSectors, err = bitfield.SubtractBitField(allSectors, faultySectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("calc proving sectors: %w", err)
|
||||
}
|
||||
} else {
|
||||
provingSectors, err = miner.AllPartSectors(mas, miner.Partition.ActiveSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get active sectors sectors: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
numProvSect, err := provingSectors.Count()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
||||
}
|
||||
|
||||
// TODO(review): is this right? feels fishy to me
|
||||
if numProvSect == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting miner info: %w", err)
|
||||
}
|
||||
|
||||
mid, err := address.IDFromAddress(maddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
||||
}
|
||||
|
||||
proofType, err := miner.WinningPoStProofTypeFromWindowPoStProofType(nv, info.WindowPoStProofType)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("determining winning post proof type: %w", err)
|
||||
}
|
||||
|
||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, proofType, abi.ActorID(mid), rand, numProvSect)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
||||
}
|
||||
|
||||
iter, err := provingSectors.BitIterator()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||
}
|
||||
|
||||
// Select winning sectors by _index_ in the all-sectors bitfield.
|
||||
selectedSectors := bitfield.New()
|
||||
prev := uint64(0)
|
||||
for _, n := range ids {
|
||||
sno, err := iter.Nth(n - prev)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||
}
|
||||
selectedSectors.Set(sno)
|
||||
prev = n
|
||||
}
|
||||
|
||||
sectors, err := mas.LoadSectors(&selectedSectors)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading proving sectors: %w", err)
|
||||
}
|
||||
|
||||
out := make([]builtin.SectorInfo, len(sectors))
|
||||
for i, sinfo := range sectors {
|
||||
out[i] = builtin.SectorInfo{
|
||||
SealProof: sinfo.SealProof,
|
||||
SectorNumber: sinfo.SectorNumber,
|
||||
SealedCID: sinfo.SealedCID,
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
spas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
_, ok, err := spas.MinerPower(maddr)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("getting miner power: %w", err)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
act, err := sm.LoadActor(ctx, market.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load market actor: %w", err)
|
||||
}
|
||||
|
||||
state, err := market.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load market actor state: %w", err)
|
||||
}
|
||||
|
||||
proposals, err := state.Proposals()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proposal, found, err := proposals.Get(dealID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !found {
|
||||
return nil, xerrors.Errorf(
|
||||
"deal %d not found "+
|
||||
"- deal may not have completed sealing before deal proposal "+
|
||||
"start epoch, or deal may have been slashed",
|
||||
dealID)
|
||||
}
|
||||
|
||||
states, err := state.States()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, found, err := states.Get(dealID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !found {
|
||||
st = market.EmptyDealState()
|
||||
}
|
||||
|
||||
return &api.MarketDeal{
|
||||
Proposal: *proposal,
|
||||
State: *st,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
powState, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||
}
|
||||
|
||||
return powState.ListAllMiners()
|
||||
}
|
||||
|
||||
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
base, trace, err := sm.ExecutionTrace(ctx, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
for i := ts.Height(); i < height; i++ {
|
||||
// handle state forks
|
||||
base, err = sm.handleStateForks(ctx, base, i, &InvocationTracer{trace: &trace}, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
|
||||
// TODO: should we also run cron here?
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: height,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
||||
}
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
for i, msg := range msgs {
|
||||
// TODO: Use the signed message length for secp messages
|
||||
ret, err := vmi.ApplyMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
|
||||
}
|
||||
if ret.ExitCode != 0 {
|
||||
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
return root, trace, nil
|
||||
}
|
||||
|
||||
func LookbackStateGetterForTipset(sm *StateManager, ts *types.TipSet) vm.LookbackStateGetter {
|
||||
return func(ctx context.Context, round abi.ChainEpoch) (*state.StateTree, error) {
|
||||
_, st, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sm.StateTree(st)
|
||||
}
|
||||
}
|
||||
|
||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, cid.Cid, error) {
|
||||
var lbr abi.ChainEpoch
|
||||
lb := policy.GetWinningPoStSectorSetLookback(sm.GetNtwkVersion(ctx, round))
|
||||
if round > lb {
|
||||
lbr = round - lb
|
||||
}
|
||||
|
||||
// more null blocks than our lookback
|
||||
if lbr >= ts.Height() {
|
||||
// This should never happen at this point, but may happen before
|
||||
// network version 3 (where the lookback was only 10 blocks).
|
||||
st, _, err := sm.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
return ts, st, nil
|
||||
}
|
||||
|
||||
// Get the tipset after the lookback tipset, or the next non-null one.
|
||||
nextTs, err := sm.ChainStore().GetTipsetByHeight(ctx, lbr+1, ts, false)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to get lookback tipset+1: %w", err)
|
||||
}
|
||||
|
||||
if lbr > nextTs.Height() {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to find non-null tipset %s (%d) which is known to exist, found %s (%d)", ts.Key(), ts.Height(), nextTs.Key(), nextTs.Height())
|
||||
|
||||
}
|
||||
|
||||
lbts, err := sm.ChainStore().GetTipSetFromKey(nextTs.Parents())
|
||||
if err != nil {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to resolve lookback tipset: %w", err)
|
||||
}
|
||||
|
||||
return lbts, nextTs.ParentState(), nil
|
||||
}
|
||||
|
||||
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) {
|
||||
ts, err := sm.ChainStore().LoadTipSet(tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
|
||||
}
|
||||
|
||||
prev, err := sm.ChainStore().GetLatestBeaconEntry(ts)
|
||||
if err != nil {
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") != "_yes_" {
|
||||
return nil, xerrors.Errorf("failed to get latest beacon entry: %w", err)
|
||||
}
|
||||
|
||||
prev = &types.BeaconEntry{}
|
||||
}
|
||||
|
||||
entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rbase := *prev
|
||||
if len(entries) > 0 {
|
||||
rbase = entries[len(entries)-1]
|
||||
}
|
||||
|
||||
lbts, lbst, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
||||
}
|
||||
|
||||
act, err := sm.LoadActorRaw(ctx, maddr, lbst)
|
||||
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||
_, err := sm.LoadActor(ctx, maddr, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loading miner in current state: %w", err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||
}
|
||||
|
||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := maddr.MarshalCBOR(buf); err != nil {
|
||||
return nil, xerrors.Errorf("failed to marshal miner address: %w", err)
|
||||
}
|
||||
|
||||
prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
||||
}
|
||||
|
||||
nv := sm.GetNtwkVersion(ctx, ts.Height())
|
||||
|
||||
sectors, err := GetSectorsForWinningPoSt(ctx, nv, pv, sm, lbst, maddr, prand)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
|
||||
}
|
||||
|
||||
if len(sectors) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||
}
|
||||
|
||||
info, err := mas.Info()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Not ideal performance...This method reloads miner and power state (already looked up here and in GetPowerRaw)
|
||||
eligible, err := MinerEligibleToMine(ctx, sm, maddr, ts, lbts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("determining miner eligibility: %w", err)
|
||||
}
|
||||
|
||||
return &api.MiningBaseInfo{
|
||||
MinerPower: mpow.QualityAdjPower,
|
||||
NetworkPower: tpow.QualityAdjPower,
|
||||
Sectors: sectors,
|
||||
WorkerKey: worker,
|
||||
SectorSize: info.SectorSize,
|
||||
PrevBeaconEntry: *prev,
|
||||
BeaconEntries: entries,
|
||||
EligibleForMining: eligible,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type MethodMeta struct {
|
||||
Name string
|
||||
|
||||
@@ -621,86 +119,124 @@ func GetParamType(actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, e
|
||||
return reflect.New(m.Params.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
|
||||
func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, init_.Address, st)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||
return "", err
|
||||
}
|
||||
ias, err := init_.Load(sm.cs.ActorStore(ctx), act)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ps, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
||||
return ias.NetworkName()
|
||||
}
|
||||
|
||||
func MinerEligibleToMine(ctx context.Context, sm *StateManager, addr address.Address, baseTs *types.TipSet, lookbackTs *types.TipSet) (bool, error) {
|
||||
hmp, err := minerHasMinPower(ctx, sm, addr, lookbackTs)
|
||||
|
||||
// TODO: We're blurring the lines between a "runtime network version" and a "Lotus upgrade epoch", is that unavoidable?
|
||||
if sm.GetNtwkVersion(ctx, baseTs.Height()) <= network.Version3 {
|
||||
return hmp, err
|
||||
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
base, trace, err := sm.ExecutionTrace(ctx, ts)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
if !hmp {
|
||||
return false, nil
|
||||
for i := ts.Height(); i < height; i++ {
|
||||
// handle state forks
|
||||
base, err = sm.handleStateForks(ctx, base, i, &InvocationTracer{trace: &trace}, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
|
||||
// TODO: should we also run cron here?
|
||||
}
|
||||
|
||||
// Post actors v2, also check MinerEligibleForElection with base ts
|
||||
|
||||
pact, err := sm.LoadActor(ctx, power.Address, baseTs)
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: height,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Syscalls: sm.syscalls,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
LookbackState: LookbackStateGetterForTipset(sm, ts),
|
||||
}
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
pstate, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
||||
for i, msg := range msgs {
|
||||
// TODO: Use the signed message length for secp messages
|
||||
ret, err := vmi.ApplyMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
|
||||
}
|
||||
if ret.ExitCode != 0 {
|
||||
log.Infof("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
|
||||
}
|
||||
}
|
||||
|
||||
root, err := vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
mact, err := sm.LoadActor(ctx, addr, baseTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("loading miner actor state: %w", err)
|
||||
}
|
||||
|
||||
mstate, err := miner.Load(sm.cs.ActorStore(ctx), mact)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Non-empty power claim.
|
||||
if claim, found, err := pstate.MinerPower(addr); err != nil {
|
||||
return false, err
|
||||
} else if !found {
|
||||
return false, err
|
||||
} else if claim.QualityAdjPower.LessThanEqual(big.Zero()) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// No fee debt.
|
||||
if debt, err := mstate.FeeDebt(); err != nil {
|
||||
return false, err
|
||||
} else if !debt.IsZero() {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// No active consensus faults.
|
||||
if mInfo, err := mstate.Info(); err != nil {
|
||||
return false, err
|
||||
} else if baseTs.Height() <= mInfo.ConsensusFaultElapsed {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return root, trace, nil
|
||||
}
|
||||
|
||||
func CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
str, err := state.LoadStateTree(sm.ChainStore().ActorStore(ctx), ts.ParentState())
|
||||
func LookbackStateGetterForTipset(sm *StateManager, ts *types.TipSet) vm.LookbackStateGetter {
|
||||
return func(ctx context.Context, round abi.ChainEpoch) (*state.StateTree, error) {
|
||||
_, st, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sm.StateTree(st)
|
||||
}
|
||||
}
|
||||
|
||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, cid.Cid, error) {
|
||||
var lbr abi.ChainEpoch
|
||||
lb := policy.GetWinningPoStSectorSetLookback(sm.GetNtwkVersion(ctx, round))
|
||||
if round > lb {
|
||||
lbr = round - lb
|
||||
}
|
||||
|
||||
// more null blocks than our lookback
|
||||
if lbr >= ts.Height() {
|
||||
// This should never happen at this point, but may happen before
|
||||
// network version 3 (where the lookback was only 10 blocks).
|
||||
st, _, err := sm.TipSetState(ctx, ts)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, err
|
||||
}
|
||||
return ts, st, nil
|
||||
}
|
||||
|
||||
// Get the tipset after the lookback tipset, or the next non-null one.
|
||||
nextTs, err := sm.ChainStore().GetTipsetByHeight(ctx, lbr+1, ts, false)
|
||||
if err != nil {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to get lookback tipset+1: %w", err)
|
||||
}
|
||||
|
||||
if lbr > nextTs.Height() {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to find non-null tipset %s (%d) which is known to exist, found %s (%d)", ts.Key(), ts.Height(), nextTs.Key(), nextTs.Height())
|
||||
|
||||
}
|
||||
|
||||
lbts, err := sm.ChainStore().GetTipSetFromKey(nextTs.Parents())
|
||||
if err != nil {
|
||||
return nil, cid.Undef, xerrors.Errorf("failed to resolve lookback tipset: %w", err)
|
||||
}
|
||||
|
||||
return lbts, nextTs.ParentState(), nil
|
||||
}
|
||||
|
||||
func CheckTotalFIL(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
str, err := state.LoadStateTree(cs.ActorStore(ctx), ts.ParentState())
|
||||
if err != nil {
|
||||
return abi.TokenAmount{}, err
|
||||
}
|
||||
@@ -729,3 +265,21 @@ func MakeMsgGasCost(msg *types.Message, ret *vm.ApplyRet) api.MsgGasCost {
|
||||
TotalCost: big.Sub(msg.RequiredFunds(), ret.GasCosts.Refund),
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) {
|
||||
stateTree, err := sm.StateTree(sm.parentState(ts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []address.Address
|
||||
err = stateTree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
out = append(out, addr)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestIndexSeeks(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
nbs := blockstore.NewMemorySync()
|
||||
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil, nil)
|
||||
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
_, err = cs.Import(bytes.NewReader(gencar))
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
block "github.com/ipfs/go-block-format"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type storable interface {
|
||||
ToStorageBlock() (block.Block, error)
|
||||
}
|
||||
|
||||
func PutMessage(bs bstore.Blockstore, m storable) (cid.Cid, error) {
|
||||
b, err := m.ToStorageBlock()
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
if err := bs.Put(b); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return b.Cid(), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PutMessage(m storable) (cid.Cid, error) {
|
||||
return PutMessage(cs.chainBlockstore, m)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetCMessage(c cid.Cid) (types.ChainMsg, error) {
|
||||
m, err := cs.GetMessage(c)
|
||||
if err == nil {
|
||||
return m, nil
|
||||
}
|
||||
if err != bstore.ErrNotFound {
|
||||
log.Warnf("GetCMessage: unexpected error getting unsigned message: %s", err)
|
||||
}
|
||||
|
||||
return cs.GetSignedMessage(c)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetMessage(c cid.Cid) (*types.Message, error) {
|
||||
var msg *types.Message
|
||||
err := cs.chainLocalBlockstore.View(c, func(b []byte) (err error) {
|
||||
msg, err = types.DecodeMessage(b)
|
||||
return err
|
||||
})
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error) {
|
||||
var msg *types.SignedMessage
|
||||
err := cs.chainLocalBlockstore.View(c, func(b []byte) (err error) {
|
||||
msg, err = types.DecodeSignedMessage(b)
|
||||
return err
|
||||
})
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
|
||||
ctx := context.TODO()
|
||||
// block headers use adt0, for now.
|
||||
a, err := blockadt.AsArray(cs.ActorStore(ctx), root)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
cids []cid.Cid
|
||||
cborCid cbg.CborCid
|
||||
)
|
||||
if err := a.ForEach(&cborCid, func(i int64) error {
|
||||
c := cid.Cid(cborCid)
|
||||
cids = append(cids, c)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, xerrors.Errorf("failed to traverse amt: %w", err)
|
||||
}
|
||||
|
||||
if uint64(len(cids)) != a.Length() {
|
||||
return nil, xerrors.Errorf("found %d cids, expected %d", len(cids), a.Length())
|
||||
}
|
||||
|
||||
return cids, nil
|
||||
}
|
||||
|
||||
type BlockMessages struct {
|
||||
Miner address.Address
|
||||
BlsMessages []types.ChainMsg
|
||||
SecpkMessages []types.ChainMsg
|
||||
WinCount int64
|
||||
}
|
||||
|
||||
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
||||
applied := make(map[address.Address]uint64)
|
||||
|
||||
cst := cbor.NewCborStore(cs.stateBlockstore)
|
||||
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load state tree at tipset %s: %w", ts, err)
|
||||
}
|
||||
|
||||
selectMsg := func(m *types.Message) (bool, error) {
|
||||
var sender address.Address
|
||||
if ts.Height() >= build.UpgradeHyperdriveHeight {
|
||||
sender, err = st.LookupID(m.From)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
sender = m.From
|
||||
}
|
||||
|
||||
// The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
|
||||
if _, ok := applied[sender]; !ok {
|
||||
applied[sender] = m.Nonce
|
||||
}
|
||||
|
||||
if applied[sender] != m.Nonce {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
applied[sender]++
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var out []BlockMessages
|
||||
for _, b := range ts.Blocks() {
|
||||
|
||||
bms, sms, err := cs.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get messages for block: %w", err)
|
||||
}
|
||||
|
||||
bm := BlockMessages{
|
||||
Miner: b.Miner,
|
||||
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
|
||||
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
|
||||
WinCount: b.ElectionProof.WinCount,
|
||||
}
|
||||
|
||||
for _, bmsg := range bms {
|
||||
b, err := selectMsg(bmsg.VMMessage())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
|
||||
}
|
||||
|
||||
if b {
|
||||
bm.BlsMessages = append(bm.BlsMessages, bmsg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, smsg := range sms {
|
||||
b, err := selectMsg(smsg.VMMessage())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
|
||||
}
|
||||
|
||||
if b {
|
||||
bm.SecpkMessages = append(bm.SecpkMessages, smsg)
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, bm)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||
bmsgs, err := cs.BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []types.ChainMsg
|
||||
for _, bm := range bmsgs {
|
||||
for _, blsm := range bm.BlsMessages {
|
||||
out = append(out, blsm)
|
||||
}
|
||||
|
||||
for _, secm := range bm.SecpkMessages {
|
||||
out = append(out, secm)
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type mmCids struct {
|
||||
bls []cid.Cid
|
||||
secpk []cid.Cid
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ReadMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
||||
o, ok := cs.mmCache.Get(mmc)
|
||||
if ok {
|
||||
mmcids := o.(*mmCids)
|
||||
return mmcids.bls, mmcids.secpk, nil
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(cs.chainLocalBlockstore)
|
||||
var msgmeta types.MsgMeta
|
||||
if err := cst.Get(context.TODO(), mmc, &msgmeta); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to load msgmeta (%s): %w", mmc, err)
|
||||
}
|
||||
|
||||
blscids, err := cs.readAMTCids(msgmeta.BlsMessages)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading bls message cids for block: %w", err)
|
||||
}
|
||||
|
||||
secpkcids, err := cs.readAMTCids(msgmeta.SecpkMessages)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading secpk message cids for block: %w", err)
|
||||
}
|
||||
|
||||
cs.mmCache.Add(mmc, &mmCids{
|
||||
bls: blscids,
|
||||
secpk: secpkcids,
|
||||
})
|
||||
|
||||
return blscids, secpkcids, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
blscids, secpkcids, err := cs.ReadMsgMetaCids(b.Messages)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
blsmsgs, err := cs.LoadMessagesFromCids(blscids)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading bls messages for block: %w", err)
|
||||
}
|
||||
|
||||
secpkmsgs, err := cs.LoadSignedMessagesFromCids(secpkcids)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading secpk messages for block: %w", err)
|
||||
}
|
||||
|
||||
return blsmsgs, secpkmsgs, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
|
||||
ctx := context.TODO()
|
||||
// block headers use adt0, for now.
|
||||
a, err := blockadt.AsArray(cs.ActorStore(ctx), b.ParentMessageReceipts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
|
||||
var r types.MessageReceipt
|
||||
if found, err := a.Get(uint64(i), &r); err != nil {
|
||||
return nil, err
|
||||
} else if !found {
|
||||
return nil, xerrors.Errorf("failed to find receipt %d", i)
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) LoadMessagesFromCids(cids []cid.Cid) ([]*types.Message, error) {
|
||||
msgs := make([]*types.Message, 0, len(cids))
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) LoadSignedMessagesFromCids(cids []cid.Cid) ([]*types.SignedMessage, error) {
|
||||
msgs := make([]*types.SignedMessage, 0, len(cids))
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetSignedMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/minio/blake2b-simd"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
h := blake2b.New256()
|
||||
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
VRFDigest := blake2b.Sum256(rbase)
|
||||
_, err := h.Write(VRFDigest[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||
}
|
||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
_, err = h.Write(entropy)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing entropy: %w", err)
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetBeaconRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
be, err := cs.GetLatestBeaconEntry(randTs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(be.Data, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetChainRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := randTs.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
cur := ts
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := cur.Blocks()[0].BeaconEntries
|
||||
if len(cbe) > 0 {
|
||||
return &cbe[len(cbe)-1], nil
|
||||
}
|
||||
|
||||
if cur.Height() == 0 {
|
||||
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
|
||||
}
|
||||
|
||||
next, err := cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
||||
return &types.BeaconEntry{
|
||||
Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
||||
type chainRand struct {
|
||||
cs *ChainStore
|
||||
blks []cid.Cid
|
||||
}
|
||||
|
||||
func NewChainRand(cs *ChainStore, blks []cid.Cid) vm.Rand {
|
||||
return &chainRand{
|
||||
cs: cs,
|
||||
blks: blks,
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
}
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipld/go-car"
|
||||
carutil "github.com/ipld/go-car/util"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error {
|
||||
h := &car.CarHeader{
|
||||
Roots: ts.Cids(),
|
||||
Version: 1,
|
||||
}
|
||||
|
||||
if err := car.WriteHeader(h, w); err != nil {
|
||||
return xerrors.Errorf("failed to write car header: %s", err)
|
||||
}
|
||||
|
||||
unionBs := bstore.Union(cs.stateBlockstore, cs.chainBlockstore)
|
||||
return cs.WalkSnapshot(ctx, ts, inclRecentRoots, skipOldMsgs, true, func(c cid.Cid) error {
|
||||
blk, err := unionBs.Get(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing object to car, bs.Get: %w", err)
|
||||
}
|
||||
|
||||
if err := carutil.LdWrite(w, c.Bytes(), blk.RawData()); err != nil {
|
||||
return xerrors.Errorf("failed to write block to car output: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
|
||||
// TODO: writing only to the state blockstore is incorrect.
|
||||
// At this time, both the state and chain blockstores are backed by the
|
||||
// universal store. When we physically segregate the stores, we will need
|
||||
// to route state objects to the state blockstore, and chain objects to
|
||||
// the chain blockstore.
|
||||
header, err := car.LoadCar(cs.StateBlockstore(), r)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loadcar failed: %w", err)
|
||||
}
|
||||
|
||||
root, err := cs.LoadTipSet(types.NewTipSetKey(header.Roots...))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs, skipMsgReceipts bool, cb func(cid.Cid) error) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
seen := cid.NewSet()
|
||||
walked := cid.NewSet()
|
||||
|
||||
blocksToWalk := ts.Cids()
|
||||
currentMinHeight := ts.Height()
|
||||
|
||||
walkChain := func(blk cid.Cid) error {
|
||||
if !seen.Visit(blk) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cb(blk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := cs.chainBlockstore.Get(blk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting block: %w", err)
|
||||
}
|
||||
|
||||
var b types.BlockHeader
|
||||
if err := b.UnmarshalCBOR(bytes.NewBuffer(data.RawData())); err != nil {
|
||||
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
|
||||
if currentMinHeight > b.Height {
|
||||
currentMinHeight = b.Height
|
||||
if currentMinHeight%builtin.EpochsInDay == 0 {
|
||||
log.Infow("export", "height", currentMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
var cids []cid.Cid
|
||||
if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots {
|
||||
if walked.Visit(b.Messages) {
|
||||
mcids, err := recurseLinks(cs.chainBlockstore, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
}
|
||||
cids = mcids
|
||||
}
|
||||
}
|
||||
|
||||
if b.Height > 0 {
|
||||
for _, p := range b.Parents {
|
||||
blocksToWalk = append(blocksToWalk, p)
|
||||
}
|
||||
} else {
|
||||
// include the genesis block
|
||||
cids = append(cids, b.Parents...)
|
||||
}
|
||||
|
||||
out := cids
|
||||
|
||||
if b.Height == 0 || b.Height > ts.Height()-inclRecentRoots {
|
||||
if walked.Visit(b.ParentStateRoot) {
|
||||
cids, err := recurseLinks(cs.stateBlockstore, walked, b.ParentStateRoot, []cid.Cid{b.ParentStateRoot})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing genesis state failed: %w", err)
|
||||
}
|
||||
|
||||
out = append(out, cids...)
|
||||
}
|
||||
|
||||
if !skipMsgReceipts && walked.Visit(b.ParentMessageReceipts) {
|
||||
out = append(out, b.ParentMessageReceipts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range out {
|
||||
if seen.Visit(c) {
|
||||
if c.Prefix().Codec != cid.DagCBOR {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cb(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infow("export started")
|
||||
exportStart := build.Clock.Now()
|
||||
|
||||
for len(blocksToWalk) > 0 {
|
||||
next := blocksToWalk[0]
|
||||
blocksToWalk = blocksToWalk[1:]
|
||||
if err := walkChain(next); err != nil {
|
||||
return xerrors.Errorf("walk chain failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("export finished", "duration", build.Clock.Now().Sub(exportStart).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
if root.Prefix().Codec != cid.DagCBOR {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
data, err := bs.Get(root)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("recurse links get (%s) failed: %w", root, err)
|
||||
}
|
||||
|
||||
var rerr error
|
||||
err = cbg.ScanForLinks(bytes.NewReader(data.RawData()), func(c cid.Cid) {
|
||||
if rerr != nil {
|
||||
// No error return on ScanForLinks :(
|
||||
return
|
||||
}
|
||||
|
||||
// traversed this already...
|
||||
if !walked.Visit(c) {
|
||||
return
|
||||
}
|
||||
|
||||
in = append(in, c)
|
||||
var err error
|
||||
in, err = recurseLinks(bs, walked, c, in)
|
||||
if err != nil {
|
||||
rerr = err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("scanning for links failed: %w", err)
|
||||
}
|
||||
|
||||
return in, rerr
|
||||
}
|
||||
+2
-658
@@ -1,36 +1,24 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/minio/blake2b-simd"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
bstore "github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
|
||||
@@ -48,9 +36,6 @@ import (
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/ipld/go-car"
|
||||
carutil "github.com/ipld/go-car/util"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"github.com/whyrusleeping/pubsub"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
@@ -134,11 +119,9 @@ type ChainStore struct {
|
||||
reorgCh chan<- reorg
|
||||
reorgNotifeeCh chan ReorgNotifee
|
||||
|
||||
mmCache *lru.ARCCache
|
||||
mmCache *lru.ARCCache // msg meta cache (mh.Messages -> secp, bls []cid)
|
||||
tsCache *lru.ARCCache
|
||||
|
||||
vmcalls vm.SyscallBuilder
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
journal journal.Journal
|
||||
|
||||
@@ -146,7 +129,7 @@ type ChainStore struct {
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder, j journal.Journal) *ChainStore {
|
||||
func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dstore.Batching, j journal.Journal) *ChainStore {
|
||||
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||
if j == nil {
|
||||
@@ -166,7 +149,6 @@ func NewChainStore(chainBs bstore.Blockstore, stateBs bstore.Blockstore, ds dsto
|
||||
tipsets: make(map[abi.ChainEpoch][]cid.Cid),
|
||||
mmCache: c,
|
||||
tsCache: tsc,
|
||||
vmcalls: vmcalls,
|
||||
cancelFn: cancel,
|
||||
journal: j,
|
||||
}
|
||||
@@ -988,27 +970,6 @@ func (cs *ChainStore) PersistBlockHeaders(b ...*types.BlockHeader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
type storable interface {
|
||||
ToStorageBlock() (block.Block, error)
|
||||
}
|
||||
|
||||
func PutMessage(bs bstore.Blockstore, m storable) (cid.Cid, error) {
|
||||
b, err := m.ToStorageBlock()
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
if err := bs.Put(b); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return b.Cid(), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PutMessage(m storable) (cid.Cid, error) {
|
||||
return PutMessage(cs.chainBlockstore, m)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) expandTipset(b *types.BlockHeader) (*types.TipSet, error) {
|
||||
// Hold lock for the whole function for now, if it becomes a problem we can
|
||||
// fix pretty easily
|
||||
@@ -1080,203 +1041,6 @@ func (cs *ChainStore) GetGenesis() (*types.BlockHeader, error) {
|
||||
return cs.GetBlock(c)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetCMessage(c cid.Cid) (types.ChainMsg, error) {
|
||||
m, err := cs.GetMessage(c)
|
||||
if err == nil {
|
||||
return m, nil
|
||||
}
|
||||
if err != bstore.ErrNotFound {
|
||||
log.Warnf("GetCMessage: unexpected error getting unsigned message: %s", err)
|
||||
}
|
||||
|
||||
return cs.GetSignedMessage(c)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetMessage(c cid.Cid) (*types.Message, error) {
|
||||
var msg *types.Message
|
||||
err := cs.chainLocalBlockstore.View(c, func(b []byte) (err error) {
|
||||
msg, err = types.DecodeMessage(b)
|
||||
return err
|
||||
})
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error) {
|
||||
var msg *types.SignedMessage
|
||||
err := cs.chainLocalBlockstore.View(c, func(b []byte) (err error) {
|
||||
msg, err = types.DecodeSignedMessage(b)
|
||||
return err
|
||||
})
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
|
||||
ctx := context.TODO()
|
||||
// block headers use adt0, for now.
|
||||
a, err := blockadt.AsArray(cs.ActorStore(ctx), root)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
|
||||
var (
|
||||
cids []cid.Cid
|
||||
cborCid cbg.CborCid
|
||||
)
|
||||
if err := a.ForEach(&cborCid, func(i int64) error {
|
||||
c := cid.Cid(cborCid)
|
||||
cids = append(cids, c)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, xerrors.Errorf("failed to traverse amt: %w", err)
|
||||
}
|
||||
|
||||
if uint64(len(cids)) != a.Length() {
|
||||
return nil, xerrors.Errorf("found %d cids, expected %d", len(cids), a.Length())
|
||||
}
|
||||
|
||||
return cids, nil
|
||||
}
|
||||
|
||||
type BlockMessages struct {
|
||||
Miner address.Address
|
||||
BlsMessages []types.ChainMsg
|
||||
SecpkMessages []types.ChainMsg
|
||||
WinCount int64
|
||||
}
|
||||
|
||||
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
|
||||
applied := make(map[address.Address]uint64)
|
||||
|
||||
cst := cbor.NewCborStore(cs.stateBlockstore)
|
||||
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load state tree")
|
||||
}
|
||||
|
||||
selectMsg := func(m *types.Message) (bool, error) {
|
||||
var sender address.Address
|
||||
if ts.Height() >= build.UpgradeHyperdriveHeight {
|
||||
sender, err = st.LookupID(m.From)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
sender = m.From
|
||||
}
|
||||
|
||||
// The first match for a sender is guaranteed to have correct nonce -- the block isn't valid otherwise
|
||||
if _, ok := applied[sender]; !ok {
|
||||
applied[sender] = m.Nonce
|
||||
}
|
||||
|
||||
if applied[sender] != m.Nonce {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
applied[sender]++
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var out []BlockMessages
|
||||
for _, b := range ts.Blocks() {
|
||||
|
||||
bms, sms, err := cs.MessagesForBlock(b)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get messages for block: %w", err)
|
||||
}
|
||||
|
||||
bm := BlockMessages{
|
||||
Miner: b.Miner,
|
||||
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
|
||||
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
|
||||
WinCount: b.ElectionProof.WinCount,
|
||||
}
|
||||
|
||||
for _, bmsg := range bms {
|
||||
b, err := selectMsg(bmsg.VMMessage())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
|
||||
}
|
||||
|
||||
if b {
|
||||
bm.BlsMessages = append(bm.BlsMessages, bmsg)
|
||||
}
|
||||
}
|
||||
|
||||
for _, smsg := range sms {
|
||||
b, err := selectMsg(smsg.VMMessage())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
|
||||
}
|
||||
|
||||
if b {
|
||||
bm.SecpkMessages = append(bm.SecpkMessages, smsg)
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, bm)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
|
||||
bmsgs, err := cs.BlockMsgsForTipset(ts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []types.ChainMsg
|
||||
for _, bm := range bmsgs {
|
||||
for _, blsm := range bm.BlsMessages {
|
||||
out = append(out, blsm)
|
||||
}
|
||||
|
||||
for _, secm := range bm.SecpkMessages {
|
||||
out = append(out, secm)
|
||||
}
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type mmCids struct {
|
||||
bls []cid.Cid
|
||||
secpk []cid.Cid
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ReadMsgMetaCids(mmc cid.Cid) ([]cid.Cid, []cid.Cid, error) {
|
||||
o, ok := cs.mmCache.Get(mmc)
|
||||
if ok {
|
||||
mmcids := o.(*mmCids)
|
||||
return mmcids.bls, mmcids.secpk, nil
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(cs.chainLocalBlockstore)
|
||||
var msgmeta types.MsgMeta
|
||||
if err := cst.Get(context.TODO(), mmc, &msgmeta); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to load msgmeta (%s): %w", mmc, err)
|
||||
}
|
||||
|
||||
blscids, err := cs.readAMTCids(msgmeta.BlsMessages)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading bls message cids for block: %w", err)
|
||||
}
|
||||
|
||||
secpkcids, err := cs.readAMTCids(msgmeta.SecpkMessages)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading secpk message cids for block: %w", err)
|
||||
}
|
||||
|
||||
cs.mmCache.Add(mmc, &mmCids{
|
||||
bls: blscids,
|
||||
secpk: secpkcids,
|
||||
})
|
||||
|
||||
return blscids, secpkcids, nil
|
||||
}
|
||||
|
||||
// GetPath returns the sequence of atomic head change operations that
|
||||
// need to be applied in order to switch the head of the chain from the `from`
|
||||
// tipset to the `to` tipset.
|
||||
@@ -1304,71 +1068,6 @@ func (cs *ChainStore) GetPath(ctx context.Context, from types.TipSetKey, to type
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
||||
blscids, secpkcids, err := cs.ReadMsgMetaCids(b.Messages)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
blsmsgs, err := cs.LoadMessagesFromCids(blscids)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading bls messages for block: %w", err)
|
||||
}
|
||||
|
||||
secpkmsgs, err := cs.LoadSignedMessagesFromCids(secpkcids)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("loading secpk messages for block: %w", err)
|
||||
}
|
||||
|
||||
return blsmsgs, secpkmsgs, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
|
||||
ctx := context.TODO()
|
||||
// block headers use adt0, for now.
|
||||
a, err := blockadt.AsArray(cs.ActorStore(ctx), b.ParentMessageReceipts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
|
||||
var r types.MessageReceipt
|
||||
if found, err := a.Get(uint64(i), &r); err != nil {
|
||||
return nil, err
|
||||
} else if !found {
|
||||
return nil, xerrors.Errorf("failed to find receipt %d", i)
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) LoadMessagesFromCids(cids []cid.Cid) ([]*types.Message, error) {
|
||||
msgs := make([]*types.Message, 0, len(cids))
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) LoadSignedMessagesFromCids(cids []cid.Cid) ([]*types.SignedMessage, error) {
|
||||
msgs := make([]*types.SignedMessage, 0, len(cids))
|
||||
for i, c := range cids {
|
||||
m, err := cs.GetSignedMessage(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get message: (%s):%d: %w", c, i, err)
|
||||
}
|
||||
|
||||
msgs = append(msgs, m)
|
||||
}
|
||||
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// ChainBlockstore returns the chain blockstore. Currently the chain and state
|
||||
// // stores are both backed by the same physical store, albeit with different
|
||||
// // caching policies, but in the future they will segregate.
|
||||
@@ -1391,10 +1090,6 @@ func (cs *ChainStore) ActorStore(ctx context.Context) adt.Store {
|
||||
return ActorStore(ctx, cs.stateBlockstore)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) VMSys() vm.SyscallBuilder {
|
||||
return cs.vmcalls
|
||||
}
|
||||
|
||||
func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
|
||||
var out []*types.FullBlock
|
||||
|
||||
@@ -1417,108 +1112,6 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
|
||||
return NewFullTipSet(out), nil
|
||||
}
|
||||
|
||||
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
h := blake2b.New256()
|
||||
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
VRFDigest := blake2b.Sum256(rbase)
|
||||
_, err := h.Write(VRFDigest[:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||
}
|
||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||
return nil, xerrors.Errorf("deriving randomness: %w", err)
|
||||
}
|
||||
_, err = h.Write(entropy)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("hashing entropy: %w", err)
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetBeaconRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetBeaconRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetBeaconRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
be, err := cs.GetLatestBeaconEntry(randTs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(be.Data, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingBack(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, true)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomnessLookingForward(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cs.GetChainRandomness(ctx, blks, pers, round, entropy, false)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetChainRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte, lookback bool) ([]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "store.GetChainRandomness")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
|
||||
|
||||
ts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if round > ts.Height() {
|
||||
return nil, xerrors.Errorf("cannot draw randomness from the future")
|
||||
}
|
||||
|
||||
searchHeight := round
|
||||
if searchHeight < 0 {
|
||||
searchHeight = 0
|
||||
}
|
||||
|
||||
randTs, err := cs.GetTipsetByHeight(ctx, searchHeight, ts, lookback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtb := randTs.MinTicketBlock()
|
||||
|
||||
// if at (or just past -- for null epochs) appropriate epoch
|
||||
// or at genesis (works for negative epochs)
|
||||
return DrawRandomness(mtb.Ticket.VRFProof, pers, round, entropy)
|
||||
}
|
||||
|
||||
// GetTipsetByHeight returns the tipset on the chain behind 'ts' at the given
|
||||
// height. In the case that the given height is a null round, the 'prev' flag
|
||||
// selects the tipset before the null round if true, and the tipset following
|
||||
@@ -1555,252 +1148,3 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
||||
|
||||
return cs.LoadTipSet(lbts.Parents())
|
||||
}
|
||||
|
||||
func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.Cid) ([]cid.Cid, error) {
|
||||
if root.Prefix().Codec != cid.DagCBOR {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
data, err := bs.Get(root)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("recurse links get (%s) failed: %w", root, err)
|
||||
}
|
||||
|
||||
var rerr error
|
||||
err = cbg.ScanForLinks(bytes.NewReader(data.RawData()), func(c cid.Cid) {
|
||||
if rerr != nil {
|
||||
// No error return on ScanForLinks :(
|
||||
return
|
||||
}
|
||||
|
||||
// traversed this already...
|
||||
if !walked.Visit(c) {
|
||||
return
|
||||
}
|
||||
|
||||
in = append(in, c)
|
||||
var err error
|
||||
in, err = recurseLinks(bs, walked, c, in)
|
||||
if err != nil {
|
||||
rerr = err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("scanning for links failed: %w", err)
|
||||
}
|
||||
|
||||
return in, rerr
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error {
|
||||
h := &car.CarHeader{
|
||||
Roots: ts.Cids(),
|
||||
Version: 1,
|
||||
}
|
||||
|
||||
if err := car.WriteHeader(h, w); err != nil {
|
||||
return xerrors.Errorf("failed to write car header: %s", err)
|
||||
}
|
||||
|
||||
unionBs := bstore.Union(cs.stateBlockstore, cs.chainBlockstore)
|
||||
return cs.WalkSnapshot(ctx, ts, inclRecentRoots, skipOldMsgs, true, func(c cid.Cid) error {
|
||||
blk, err := unionBs.Get(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing object to car, bs.Get: %w", err)
|
||||
}
|
||||
|
||||
if err := carutil.LdWrite(w, c.Bytes(), blk.RawData()); err != nil {
|
||||
return xerrors.Errorf("failed to write block to car output: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *ChainStore) WalkSnapshot(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs, skipMsgReceipts bool, cb func(cid.Cid) error) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
seen := cid.NewSet()
|
||||
walked := cid.NewSet()
|
||||
|
||||
blocksToWalk := ts.Cids()
|
||||
currentMinHeight := ts.Height()
|
||||
|
||||
walkChain := func(blk cid.Cid) error {
|
||||
if !seen.Visit(blk) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := cb(blk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := cs.chainBlockstore.Get(blk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting block: %w", err)
|
||||
}
|
||||
|
||||
var b types.BlockHeader
|
||||
if err := b.UnmarshalCBOR(bytes.NewBuffer(data.RawData())); err != nil {
|
||||
return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err)
|
||||
}
|
||||
|
||||
if currentMinHeight > b.Height {
|
||||
currentMinHeight = b.Height
|
||||
if currentMinHeight%builtin.EpochsInDay == 0 {
|
||||
log.Infow("export", "height", currentMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
var cids []cid.Cid
|
||||
if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots {
|
||||
if walked.Visit(b.Messages) {
|
||||
mcids, err := recurseLinks(cs.chainBlockstore, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing messages failed: %w", err)
|
||||
}
|
||||
cids = mcids
|
||||
}
|
||||
}
|
||||
|
||||
if b.Height > 0 {
|
||||
for _, p := range b.Parents {
|
||||
blocksToWalk = append(blocksToWalk, p)
|
||||
}
|
||||
} else {
|
||||
// include the genesis block
|
||||
cids = append(cids, b.Parents...)
|
||||
}
|
||||
|
||||
out := cids
|
||||
|
||||
if b.Height == 0 || b.Height > ts.Height()-inclRecentRoots {
|
||||
if walked.Visit(b.ParentStateRoot) {
|
||||
cids, err := recurseLinks(cs.stateBlockstore, walked, b.ParentStateRoot, []cid.Cid{b.ParentStateRoot})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("recursing genesis state failed: %w", err)
|
||||
}
|
||||
|
||||
out = append(out, cids...)
|
||||
}
|
||||
|
||||
if !skipMsgReceipts && walked.Visit(b.ParentMessageReceipts) {
|
||||
out = append(out, b.ParentMessageReceipts)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range out {
|
||||
if seen.Visit(c) {
|
||||
if c.Prefix().Codec != cid.DagCBOR {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cb(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infow("export started")
|
||||
exportStart := build.Clock.Now()
|
||||
|
||||
for len(blocksToWalk) > 0 {
|
||||
next := blocksToWalk[0]
|
||||
blocksToWalk = blocksToWalk[1:]
|
||||
if err := walkChain(next); err != nil {
|
||||
return xerrors.Errorf("walk chain failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("export finished", "duration", build.Clock.Now().Sub(exportStart).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
|
||||
// TODO: writing only to the state blockstore is incorrect.
|
||||
// At this time, both the state and chain blockstores are backed by the
|
||||
// universal store. When we physically segregate the stores, we will need
|
||||
// to route state objects to the state blockstore, and chain objects to
|
||||
// the chain blockstore.
|
||||
header, err := car.LoadCar(cs.StateBlockstore(), r)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loadcar failed: %w", err)
|
||||
}
|
||||
|
||||
root, err := cs.LoadTipSet(types.NewTipSetKey(header.Roots...))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) {
|
||||
cur := ts
|
||||
for i := 0; i < 20; i++ {
|
||||
cbe := cur.Blocks()[0].BeaconEntries
|
||||
if len(cbe) > 0 {
|
||||
return &cbe[len(cbe)-1], nil
|
||||
}
|
||||
|
||||
if cur.Height() == 0 {
|
||||
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
|
||||
}
|
||||
|
||||
next, err := cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_IGNORE_DRAND") == "_yes_" {
|
||||
return &types.BeaconEntry{
|
||||
Data: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
||||
type chainRand struct {
|
||||
cs *ChainStore
|
||||
blks []cid.Cid
|
||||
}
|
||||
|
||||
func NewChainRand(cs *ChainStore, blks []cid.Cid) vm.Rand {
|
||||
return &chainRand{
|
||||
cs: cs,
|
||||
blks: blks,
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetChainRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetChainRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingBack(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingBack(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cr *chainRand) GetBeaconRandomnessLookingForward(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
|
||||
return cr.cs.GetBeaconRandomnessLookingForward(ctx, cr.blks, pers, round, entropy)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetFromKey(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
if tsk.IsEmpty() {
|
||||
return cs.GetHeaviestTipSet(), nil
|
||||
}
|
||||
return cs.LoadTipSet(tsk)
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, bs, mds, nil, nil)
|
||||
cs := store.NewChainStore(bs, bs, mds, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -105,7 +105,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
nbs := blockstore.NewMemory()
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil, nil)
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
root, err := cs.Import(buf)
|
||||
@@ -140,7 +140,7 @@ func TestChainExportImportFull(t *testing.T) {
|
||||
}
|
||||
|
||||
nbs := blockstore.NewMemory()
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil, nil)
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
root, err := cs.Import(buf)
|
||||
@@ -157,7 +157,7 @@ func TestChainExportImportFull(t *testing.T) {
|
||||
t.Fatal("imported chain differed from exported chain")
|
||||
}
|
||||
|
||||
sm := stmgr.NewStateManager(cs)
|
||||
sm := stmgr.NewStateManager(cs, nil)
|
||||
for i := 0; i < 100; i++ {
|
||||
ts, err := cs.GetTipsetByHeight(context.TODO(), abi.ChainEpoch(i), nil, false)
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -1060,7 +1060,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
}
|
||||
|
||||
nv := syncer.sm.GetNtwkVersion(ctx, b.Header.Height)
|
||||
pl := vm.PricelistByVersion(nv)
|
||||
pl := vm.PricelistByEpoch(baseTs.Height())
|
||||
var sumGasLimit int64
|
||||
checkMsg := func(msg types.ChainMsg) error {
|
||||
m := msg.VMMessage()
|
||||
|
||||
@@ -5,6 +5,7 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
var _ = cid.Undef
|
||||
var _ = math.E
|
||||
var _ = sort.Sort
|
||||
|
||||
var lengthBufBlockHeader = []byte{144}
|
||||
|
||||
+15
-13
@@ -7,7 +7,7 @@ import (
|
||||
addr "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
vmr5 "github.com/filecoin-project/specs-actors/v5/actors/runtime"
|
||||
proof5 "github.com/filecoin-project/specs-actors/v5/actors/runtime/proof"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -79,8 +79,8 @@ type Pricelist interface {
|
||||
OnVerifyConsensusFault() GasCharge
|
||||
}
|
||||
|
||||
var prices = map[network.Version]Pricelist{
|
||||
network.Version0: &pricelistV0{
|
||||
var prices = map[abi.ChainEpoch]Pricelist{
|
||||
abi.ChainEpoch(0): &pricelistV0{
|
||||
computeGasMulti: 1,
|
||||
storageGasMulti: 1000,
|
||||
|
||||
@@ -129,7 +129,7 @@ var prices = map[network.Version]Pricelist{
|
||||
verifyPostDiscount: true,
|
||||
verifyConsensusFault: 495422,
|
||||
},
|
||||
network.Version6AndAHalf: &pricelistV0{
|
||||
abi.ChainEpoch(build.UpgradeCalicoHeight): &pricelistV0{
|
||||
computeGasMulti: 1,
|
||||
storageGasMulti: 1300,
|
||||
|
||||
@@ -207,19 +207,21 @@ var prices = map[network.Version]Pricelist{
|
||||
},
|
||||
}
|
||||
|
||||
// PricelistByVersion finds the latest prices for the given network version
|
||||
func PricelistByVersion(version network.Version) Pricelist {
|
||||
bestVersion := network.Version0
|
||||
bestPrice := prices[bestVersion]
|
||||
for nv, pl := range prices {
|
||||
// if `nv > bestVersion` and `nv <= version`
|
||||
if nv > bestVersion && nv <= version {
|
||||
bestVersion = nv
|
||||
// PricelistByEpoch finds the latest prices for the given epoch
|
||||
func PricelistByEpoch(epoch abi.ChainEpoch) Pricelist {
|
||||
// since we are storing the prices as map or epoch to price
|
||||
// we need to get the price with the highest epoch that is lower or equal to the `epoch` arg
|
||||
bestEpoch := abi.ChainEpoch(0)
|
||||
bestPrice := prices[bestEpoch]
|
||||
for e, pl := range prices {
|
||||
// if `e` happened after `bestEpoch` and `e` is earlier or equal to the target `epoch`
|
||||
if e > bestEpoch && e <= epoch {
|
||||
bestEpoch = e
|
||||
bestPrice = pl
|
||||
}
|
||||
}
|
||||
if bestPrice == nil {
|
||||
panic(fmt.Sprintf("bad setup: no gas prices available for version %d", version))
|
||||
panic(fmt.Sprintf("bad setup: no gas prices available for epoch %d", epoch))
|
||||
}
|
||||
return bestPrice
|
||||
}
|
||||
|
||||
+5
-2
@@ -39,7 +39,10 @@ type ActorPredicate func(vmr.Runtime, rtt.VMActor) error
|
||||
|
||||
func ActorsVersionPredicate(ver actors.Version) ActorPredicate {
|
||||
return func(rt vmr.Runtime, v rtt.VMActor) error {
|
||||
aver := actors.VersionForNetwork(rt.NetworkVersion())
|
||||
aver, err := actors.VersionForNetwork(rt.NetworkVersion())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("unsupported network version: %w", err)
|
||||
}
|
||||
if aver != ver {
|
||||
return xerrors.Errorf("actor %s is a version %d actor; chain only supports actor version %d at height %d and nver %d", v.Code(), ver, aver, rt.CurrEpoch(), rt.NetworkVersion())
|
||||
}
|
||||
@@ -228,7 +231,7 @@ func DumpActorState(act *types.Actor, b []byte) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
i := NewActorRegistry() // TODO: register builtins in init block
|
||||
i := NewActorRegistry()
|
||||
|
||||
actInfo, ok := i.actors[act.Code]
|
||||
if !ok {
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@@ -80,6 +82,30 @@ func (basicContract) InvokeSomething10(rt runtime2.Runtime, params *basicParams)
|
||||
return nil
|
||||
}
|
||||
|
||||
type basicRtMessage struct{}
|
||||
|
||||
var _ runtime2.Message = (*basicRtMessage)(nil)
|
||||
|
||||
func (*basicRtMessage) Caller() address.Address {
|
||||
a, err := address.NewIDAddress(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (*basicRtMessage) Receiver() address.Address {
|
||||
a, err := address.NewIDAddress(1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (*basicRtMessage) ValueReceived() abi.TokenAmount {
|
||||
return big.NewInt(0)
|
||||
}
|
||||
|
||||
func TestInvokerBasic(t *testing.T) {
|
||||
inv := ActorRegistry{}
|
||||
code, err := inv.transform(basicContract{})
|
||||
@@ -89,7 +115,7 @@ func TestInvokerBasic(t *testing.T) {
|
||||
bParam, err := actors.SerializeParams(&basicParams{B: 1})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, aerr := code[0](&Runtime{}, bParam)
|
||||
_, aerr := code[0](&Runtime{Message: &basicRtMessage{}}, bParam)
|
||||
|
||||
assert.Equal(t, exitcode.ExitCode(1), aerrors.RetCode(aerr), "return code should be 1")
|
||||
if aerrors.IsFatal(aerr) {
|
||||
@@ -101,7 +127,7 @@ func TestInvokerBasic(t *testing.T) {
|
||||
bParam, err := actors.SerializeParams(&basicParams{B: 2})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, aerr := code[10](&Runtime{}, bParam)
|
||||
_, aerr := code[10](&Runtime{Message: &basicRtMessage{}}, bParam)
|
||||
assert.Equal(t, exitcode.ExitCode(12), aerrors.RetCode(aerr), "return code should be 12")
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
@@ -113,6 +139,7 @@ func TestInvokerBasic(t *testing.T) {
|
||||
vm: &VM{ntwkVersion: func(ctx context.Context, epoch abi.ChainEpoch) network.Version {
|
||||
return network.Version0
|
||||
}},
|
||||
Message: &basicRtMessage{},
|
||||
}, []byte{99})
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
@@ -125,6 +152,7 @@ func TestInvokerBasic(t *testing.T) {
|
||||
vm: &VM{ntwkVersion: func(ctx context.Context, epoch abi.ChainEpoch) network.Version {
|
||||
return network.Version7
|
||||
}},
|
||||
Message: &basicRtMessage{},
|
||||
}, []byte{99})
|
||||
if aerrors.IsFatal(aerr) {
|
||||
t.Fatal("err should not be fatal")
|
||||
|
||||
+7
-2
@@ -41,7 +41,7 @@ var EmptyObjectCid cid.Cid
|
||||
|
||||
// TryCreateAccountActor creates account actors from only BLS/SECP256K1 addresses.
|
||||
func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, address.Address, aerrors.ActorError) {
|
||||
if err := rt.chargeGasSafe(PricelistByVersion(rt.NetworkVersion()).OnCreateActor()); err != nil {
|
||||
if err := rt.chargeGasSafe(PricelistByEpoch(rt.height).OnCreateActor()); err != nil {
|
||||
return nil, address.Undef, err
|
||||
}
|
||||
|
||||
@@ -54,7 +54,12 @@ func TryCreateAccountActor(rt *Runtime, addr address.Address) (*types.Actor, add
|
||||
return nil, address.Undef, aerrors.Escalate(err, "registering actor address")
|
||||
}
|
||||
|
||||
act, aerr := makeActor(actors.VersionForNetwork(rt.NetworkVersion()), addr)
|
||||
av, err := actors.VersionForNetwork(rt.NetworkVersion())
|
||||
if err != nil {
|
||||
return nil, address.Undef, aerrors.Escalate(err, "unsupported network version")
|
||||
}
|
||||
|
||||
act, aerr := makeActor(av, addr)
|
||||
if aerr != nil {
|
||||
return nil, address.Undef, aerr
|
||||
}
|
||||
|
||||
+2
-2
@@ -146,7 +146,7 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if ar, ok := r.(aerrors.ActorError); ok {
|
||||
log.Warnf("VM.Call failure: %+v", ar)
|
||||
log.Warnf("VM.Call failure in call from: %s to %s: %+v", rt.Caller(), rt.Receiver(), ar)
|
||||
aerr = ar
|
||||
return
|
||||
}
|
||||
@@ -391,7 +391,7 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m cbor.Marshal
|
||||
if err.IsFatal() {
|
||||
panic(err)
|
||||
}
|
||||
log.Warnf("vmctx send failed: to: %s, method: %d: ret: %d, err: %s", to, method, ret, err)
|
||||
log.Warnf("vmctx send failed: from: %s to: %s, method: %d: err: %s", rt.Receiver(), to, method, err)
|
||||
return err.RetCode()
|
||||
}
|
||||
_ = rt.chargeGasSafe(gasOnActorExec)
|
||||
|
||||
+2
-11
@@ -135,7 +135,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runti
|
||||
gasAvailable: msg.GasLimit,
|
||||
depth: 0,
|
||||
numActorsCreated: 0,
|
||||
pricelist: PricelistByVersion(vm.ntwkVersion(ctx, vm.blockHeight)),
|
||||
pricelist: PricelistByEpoch(vm.blockHeight),
|
||||
allowInternal: true,
|
||||
callerValidated: false,
|
||||
executionTrace: types.ExecutionTrace{Msg: msg},
|
||||
@@ -424,7 +424,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pl := PricelistByVersion(vm.ntwkVersion(ctx, vm.blockHeight))
|
||||
pl := PricelistByEpoch(vm.blockHeight)
|
||||
|
||||
msgGas := pl.OnChainMessage(cmsg.ChainLength())
|
||||
msgGasCost := msgGas.Total()
|
||||
@@ -641,15 +641,6 @@ func (vm *VM) ShouldBurn(ctx context.Context, st *state.StateTree, msg *types.Me
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (vm *VM) ActorBalance(addr address.Address) (types.BigInt, aerrors.ActorError) {
|
||||
act, err := vm.cstate.GetActor(addr)
|
||||
if err != nil {
|
||||
return types.EmptyInt, aerrors.Absorb(err, 1, "failed to find actor")
|
||||
}
|
||||
|
||||
return act.Balance, nil
|
||||
}
|
||||
|
||||
type vmFlushKey struct{}
|
||||
|
||||
func (vm *VM) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ var AuthApiInfoToken = &cli.Command{
|
||||
|
||||
ainfo, err := GetAPIInfo(cctx, t)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get API info: %w", err)
|
||||
return xerrors.Errorf("could not get API info for %s: %w", t, err)
|
||||
}
|
||||
|
||||
// TODO: Log in audit log when it is implemented
|
||||
|
||||
+39
-37
@@ -10,7 +10,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -1347,7 +1346,7 @@ var ChainEncodeCmd = &cli.Command{
|
||||
var chainEncodeParamsCmd = &cli.Command{
|
||||
Name: "params",
|
||||
Usage: "Encodes the given JSON params",
|
||||
ArgsUsage: "[toAddr method params]",
|
||||
ArgsUsage: "[dest method params]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "tipset",
|
||||
@@ -1357,62 +1356,65 @@ var chainEncodeParamsCmd = &cli.Command{
|
||||
Value: "base64",
|
||||
Usage: "specify input encoding to parse",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "to-code",
|
||||
Usage: "interpret dest as code CID instead of as address",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if cctx.Args().Len() != 3 {
|
||||
return ShowHelp(cctx, fmt.Errorf("incorrect number of arguments"))
|
||||
}
|
||||
|
||||
to, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing toAddr: %w", err)
|
||||
}
|
||||
|
||||
method, err := strconv.ParseInt(cctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing method id: %w", err)
|
||||
}
|
||||
|
||||
ts, err := LoadTipSet(ctx, cctx, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
act, err := api.StateGetActor(ctx, to, ts.Key())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
var p []byte
|
||||
if !cctx.Bool("to-code") {
|
||||
svc, err := GetFullNodeServices(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer svc.Close() // nolint
|
||||
|
||||
methodMeta, found := stmgr.MethodsMap[act.Code][abi.MethodNum(method)]
|
||||
if !found {
|
||||
return fmt.Errorf("method %d not found on actor %s", method, act.Code)
|
||||
}
|
||||
to, err := address.NewFromString(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing to addr: %w", err)
|
||||
}
|
||||
|
||||
p := reflect.New(methodMeta.Params.Elem()).Interface().(cbg.CBORMarshaler)
|
||||
p, err = svc.DecodeTypedParamsFromJSON(ctx, to, abi.MethodNum(method), cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding json params: %w", err)
|
||||
}
|
||||
} else {
|
||||
api, done, err := GetFullNodeAPIV1(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer done()
|
||||
|
||||
if err := json.Unmarshal([]byte(cctx.Args().Get(2)), p); err != nil {
|
||||
return fmt.Errorf("unmarshaling input into params type: %w", err)
|
||||
}
|
||||
to, err := cid.Parse(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parsing to addr: %w", err)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := p.MarshalCBOR(buf); err != nil {
|
||||
return err
|
||||
p, err = api.StateEncodeParams(ctx, to, abi.MethodNum(method), json.RawMessage(cctx.Args().Get(2)))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding json params: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
switch cctx.String("encoding") {
|
||||
case "base64":
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(buf.Bytes()))
|
||||
case "base64", "b64":
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(p))
|
||||
case "hex":
|
||||
fmt.Println(hex.EncodeToString(buf.Bytes()))
|
||||
fmt.Println(hex.EncodeToString(p))
|
||||
default:
|
||||
return xerrors.Errorf("unrecognized encoding: %s", cctx.String("encoding"))
|
||||
return xerrors.Errorf("unknown encoding")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+11
-9
@@ -24,7 +24,6 @@ import (
|
||||
"github.com/docker/go-units"
|
||||
"github.com/fatih/color"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-cidutil/cidenc"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -32,12 +31,14 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
|
||||
"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"
|
||||
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
lapi "github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
@@ -46,6 +47,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
)
|
||||
|
||||
var CidBaseFlag = cli.StringFlag{
|
||||
@@ -174,18 +176,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, imports.ID(id)); err != nil {
|
||||
return xerrors.Errorf("removing import %d: %w", id, err)
|
||||
}
|
||||
}
|
||||
@@ -1104,8 +1106,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,
|
||||
FromLocalCAR: i.CARPath,
|
||||
|
||||
Total: big.Zero(),
|
||||
UnsealPrice: big.Zero(),
|
||||
|
||||
@@ -58,7 +58,6 @@ var GetMarketsAPI = cliutil.GetMarketsAPI
|
||||
var GetWorkerAPI = cliutil.GetWorkerAPI
|
||||
|
||||
var CommonCommands = []*cli.Command{
|
||||
NetCmd,
|
||||
AuthCmd,
|
||||
LogCmd,
|
||||
WaitApiCmd,
|
||||
|
||||
+5
-5
@@ -381,8 +381,8 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
Usage: "automatically reprice the specified message",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "max-fee",
|
||||
Usage: "Spend up to X attoFIL for this message (applicable for auto mode)",
|
||||
Name: "fee-limit",
|
||||
Usage: "Spend up to X FIL for this message in units of FIL. Previously when flag was `max-fee` units were in attoFIL. Applicable for auto mode",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "<from nonce> | <message-cid>",
|
||||
@@ -457,13 +457,13 @@ var MpoolReplaceCmd = &cli.Command{
|
||||
minRBF := messagepool.ComputeMinRBF(msg.GasPremium)
|
||||
|
||||
var mss *lapi.MessageSendSpec
|
||||
if cctx.IsSet("max-fee") {
|
||||
maxFee, err := types.BigFromString(cctx.String("max-fee"))
|
||||
if cctx.IsSet("fee-limit") {
|
||||
maxFee, err := types.ParseFIL(cctx.String("fee-limit"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing max-spend: %w", err)
|
||||
}
|
||||
mss = &lapi.MessageSendSpec{
|
||||
MaxFee: maxFee,
|
||||
MaxFee: abi.TokenAmount(maxFee),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ var PprofGoroutines = &cli.Command{
|
||||
}
|
||||
ainfo, err := GetAPIInfo(cctx, t)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get API info: %w", err)
|
||||
return xerrors.Errorf("could not get API info for %s: %w", t, err)
|
||||
}
|
||||
addr, err := ainfo.Host()
|
||||
if err != nil {
|
||||
|
||||
+24
-2
@@ -2,6 +2,7 @@ package cliutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -142,6 +143,15 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
return APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err)
|
||||
}
|
||||
|
||||
exists, err := r.Exists()
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("repo.Exists returned an error: %w", err)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return APIInfo{}, errors.New("repo directory does not exist. Make sure your configuration is correct")
|
||||
}
|
||||
|
||||
ma, err := r.APIEndpoint()
|
||||
if err != nil {
|
||||
return APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err)
|
||||
@@ -171,7 +181,7 @@ func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) {
|
||||
func GetRawAPI(ctx *cli.Context, t repo.RepoType, version string) (string, http.Header, error) {
|
||||
ainfo, err := GetAPIInfo(ctx, t)
|
||||
if err != nil {
|
||||
return "", nil, xerrors.Errorf("could not get API info: %w", err)
|
||||
return "", nil, xerrors.Errorf("could not get API info for %s: %w", t, err)
|
||||
}
|
||||
|
||||
addr, err := ainfo.DialArgs(version)
|
||||
@@ -243,7 +253,19 @@ func GetFullNodeAPIV1(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientCloser, e
|
||||
_, _ = fmt.Fprintln(ctx.App.Writer, "using full node API v1 endpoint:", addr)
|
||||
}
|
||||
|
||||
return client.NewFullNodeRPCV1(ctx.Context, addr, headers)
|
||||
v1API, closer, err := client.NewFullNodeRPCV1(ctx.Context, addr, headers)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
v, err := v1API.Version(ctx.Context)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !v.APIVersion.EqMajorMinor(api.FullAPIVersion1) {
|
||||
return nil, nil, xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", api.FullAPIVersion1, v.APIVersion)
|
||||
}
|
||||
return v1API, closer, nil
|
||||
}
|
||||
|
||||
type GetStorageMinerOptions struct {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ var WaitApiCmd = &cli.Command{
|
||||
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
_, err = api.ID(ctx)
|
||||
_, err = api.Version(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -253,10 +253,10 @@ var importBenchCmd = &cli.Command{
|
||||
}
|
||||
|
||||
metadataDs := datastore.NewMapDatastore()
|
||||
cs := store.NewChainStore(bs, bs, metadataDs, vm.Syscalls(verifier), nil)
|
||||
cs := store.NewChainStore(bs, bs, metadataDs, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
stm := stmgr.NewStateManager(cs)
|
||||
stm := stmgr.NewStateManager(cs, vm.Syscalls(verifier))
|
||||
|
||||
var carFile *os.File
|
||||
// open the CAR file if one is provided.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user