Compare commits
565
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26ed6af040 | ||
|
|
82bd7bd2ec | ||
|
|
cd0a43b7f4 | ||
|
|
b14632b750 | ||
|
|
ebcf77e830 | ||
|
|
344d30e960 | ||
|
|
efb13a0d9b | ||
|
|
0223582d41 | ||
|
|
973f61bc10 | ||
|
|
60768f4863 | ||
|
|
c60d13ee56 | ||
|
|
0f8fc119f3 | ||
|
|
e4d2e6e01d | ||
|
|
d55f10bed6 | ||
|
|
21de538d09 | ||
|
|
fe5b32026a | ||
|
|
91c10c2df5 | ||
|
|
c3420c0ceb | ||
|
|
7933cf094f | ||
|
|
4cd73f1560 | ||
|
|
8a175a7465 | ||
|
|
f7f229ae54 | ||
|
|
1323e07a2c | ||
|
|
2ad671649c | ||
|
|
d26ece10b8 | ||
|
|
4c8084dcb0 | ||
|
|
98d702fb5a | ||
|
|
17f61ac212 | ||
|
|
df67576b89 | ||
|
|
cdc2f86f5a | ||
|
|
67b3a55e30 | ||
|
|
3201e0eb8f | ||
|
|
8d2d74438b | ||
|
|
1f9446f91f | ||
|
|
4937ca1a96 | ||
|
|
264fe4edb9 | ||
|
|
cb7d99fcc7 | ||
|
|
7332a39f00 | ||
|
|
8f35a5c036 | ||
|
|
dea7042668 | ||
|
|
bd8f3f05be | ||
|
|
304d835739 | ||
|
|
cb8678e4c2 | ||
|
|
da34548a05 | ||
|
|
cd9af278b4 | ||
|
|
b1fe92f8ff | ||
|
|
8dd8892b81 | ||
|
|
79dba816c7 | ||
|
|
14bb4c9a0b | ||
|
|
f9f54819d4 | ||
|
|
d1555106a4 | ||
|
|
413c357361 | ||
|
|
d97eb10349 | ||
|
|
e8253d22c6 | ||
|
|
a4e954197c | ||
|
|
8f4911ac0d | ||
|
|
b0bea5f145 | ||
|
|
7c7e0d73d5 | ||
|
|
1fea550ce5 | ||
|
|
9b7b6146eb | ||
|
|
dab1107f5b | ||
|
|
fe912223bd | ||
|
|
12cd478e11 | ||
|
|
ae3691e0a2 | ||
|
|
e55b00f358 | ||
|
|
de3f4111f4 | ||
|
|
767c346cf8 | ||
|
|
6f4a762664 | ||
|
|
c02daca9e9 | ||
|
|
cca17f6078 | ||
|
|
c17fa4bc35 | ||
|
|
e803cf151f | ||
|
|
1268cfbfcd | ||
|
|
5ef929f130 | ||
|
|
5bd6a3cdad | ||
|
|
df4b068d0e | ||
|
|
0d34881a0c | ||
|
|
6eb49b717f | ||
|
|
099b982ea8 | ||
|
|
10c120bd3c | ||
|
|
7cd1330acd | ||
|
|
39bc816a79 | ||
|
|
81fb552e1d | ||
|
|
cfd126ee9f | ||
|
|
d6fa644974 | ||
|
|
d3dc560f53 | ||
|
|
25bc00eec8 | ||
|
|
3b12a9f425 | ||
|
|
b7c8f65af5 | ||
|
|
c6e0cb4ff2 | ||
|
|
f6eb530cba | ||
|
|
f4991e868e | ||
|
|
0ec2a10ebc | ||
|
|
be92dd9e63 | ||
|
|
e90ca96289 | ||
|
|
c23f1623a1 | ||
|
|
839d1121ce | ||
|
|
a98b0f18fc | ||
|
|
15670942c3 | ||
|
|
74016ab1cc | ||
|
|
bd474617ed | ||
|
|
087030fe37 | ||
|
|
2f70a91665 | ||
|
|
60ad339033 | ||
|
|
00187d4aa8 | ||
|
|
dfaabb4596 | ||
|
|
0edecbd043 | ||
|
|
4d6a0f7b8c | ||
|
|
5043247958 | ||
|
|
282c99bdbd | ||
|
|
9857e42206 | ||
|
|
6919ff3881 | ||
|
|
d9fad5fad0 | ||
|
|
757aa1039f | ||
|
|
b71b743420 | ||
|
|
8739b938db | ||
|
|
4a3081c77a | ||
|
|
b1818a1055 | ||
|
|
256be285ba | ||
|
|
4a6e9c920d | ||
|
|
d4cbd4fb55 | ||
|
|
15330396bb | ||
|
|
2bf42d5318 | ||
|
|
a179cadf0e | ||
|
|
405aba4d8f | ||
|
|
7b556252db | ||
|
|
7a80e356de | ||
|
|
c53cef1526 | ||
|
|
4a9155ba85 | ||
|
|
1a170e18ad | ||
|
|
f8c886a611 | ||
|
|
b5907c665b | ||
|
|
ba25806fbd | ||
|
|
d02fc08ca4 | ||
|
|
de390749fc | ||
|
|
3672f2cc44 | ||
|
|
14ad91c53f | ||
|
|
f55b18eabe | ||
|
|
c920257a33 | ||
|
|
0e2f697217 | ||
|
|
16243b97aa | ||
|
|
89b88c1e0d | ||
|
|
8cdf078999 | ||
|
|
70d88f226e | ||
|
|
937d7fcca9 | ||
|
|
c8822fc9b6 | ||
|
|
dd1661c0b1 | ||
|
|
e9417562e0 | ||
|
|
40f4266070 | ||
|
|
6d25f3d2ae | ||
|
|
1e78cd21ec | ||
|
|
17846aad2f | ||
|
|
bd0633ff90 | ||
|
|
9621dbb4f1 | ||
|
|
c55b9baf37 | ||
|
|
1227bf2893 | ||
|
|
550f3771ea | ||
|
|
f8b2022f82 | ||
|
|
5a08b881d6 | ||
|
|
8bcc201fc0 | ||
|
|
420c44ed2c | ||
|
|
b6500beaab | ||
|
|
d0c52535a6 | ||
|
|
4be8964062 | ||
|
|
feb85a272c | ||
|
|
fee84c4b44 | ||
|
|
b9f8831aaf | ||
|
|
7c3f622fae | ||
|
|
140671599c | ||
|
|
ed03202c1d | ||
|
|
0162a485d8 | ||
|
|
97087fe576 | ||
|
|
e3269770d8 | ||
|
|
0fee5dab8a | ||
|
|
1fc23fb466 | ||
|
|
306dfaa11f | ||
|
|
8fe8da6f4c | ||
|
|
4631cee564 | ||
|
|
8292d60196 | ||
|
|
f6ccab1c6c | ||
|
|
6aba3e3b94 | ||
|
|
863a6ed38c | ||
|
|
f1e5e9fe72 | ||
|
|
a57288a4b9 | ||
|
|
c5de617af6 | ||
|
|
bd964b4c3e | ||
|
|
5e256be81e | ||
|
|
04db9ea72d | ||
|
|
6f33706025 | ||
|
|
44e352cd8e | ||
|
|
1319d7072e | ||
|
|
f147072284 | ||
|
|
43bd7cb055 | ||
|
|
a3a3df9b30 | ||
|
|
d3effe52a5 | ||
|
|
0591bac768 | ||
|
|
db91d22a8a | ||
|
|
fecc1ee0ef | ||
|
|
3bebdb3882 | ||
|
|
73b9fe36e3 | ||
|
|
2c1ef3708e | ||
|
|
53cc1f18d0 | ||
|
|
e848c13ff1 | ||
|
|
8fe8a5df45 | ||
|
|
a572bef8b2 | ||
|
|
ed86ac14a1 | ||
|
|
101d07f704 | ||
|
|
8ad8a945fb | ||
|
|
e865ba0c64 | ||
|
|
1cc0f74744 | ||
|
|
efc1b24f4e | ||
|
|
078044153f | ||
|
|
9b4274638c | ||
|
|
1253a5600e | ||
|
|
bceb880ee2 | ||
|
|
15885ad535 | ||
|
|
ec7282ff09 | ||
|
|
738efe3f9a | ||
|
|
e444977891 | ||
|
|
5c33982f72 | ||
|
|
44747446a9 | ||
|
|
d7ec5e3618 | ||
|
|
9b5a0815fc | ||
|
|
deac7166b5 | ||
|
|
c8a3269c4b | ||
|
|
2dc9a1ee4e | ||
|
|
d20ebe93b9 | ||
|
|
6875527224 | ||
|
|
889dd3cb3f | ||
|
|
594ec8855c | ||
|
|
e2ecc35dff | ||
|
|
9dc75a7bc4 | ||
|
|
3d91633699 | ||
|
|
93e4eae94c | ||
|
|
6f0453c581 | ||
|
|
60d442e36a | ||
|
|
1ebad94da9 | ||
|
|
636810daa5 | ||
|
|
196bf39574 | ||
|
|
954d806367 | ||
|
|
7699f195f1 | ||
|
|
6981f776f4 | ||
|
|
1b7cdb9341 | ||
|
|
47a83b422e | ||
|
|
5e08d56630 | ||
|
|
9705b25bbd | ||
|
|
9d59635b42 | ||
|
|
42d5d8d784 | ||
|
|
486812e082 | ||
|
|
6825a485eb | ||
|
|
8091bb3117 | ||
|
|
8dcbd525da | ||
|
|
35e606d397 | ||
|
|
99fe63716b | ||
|
|
941c1947be | ||
|
|
feecee310d | ||
|
|
b01a1d457a | ||
|
|
2e9915ac28 | ||
|
|
be884e27be | ||
|
|
5253c0d959 | ||
|
|
4c60d7b5ce | ||
|
|
23b729a056 | ||
|
|
724306c110 | ||
|
|
4989b1cc90 | ||
|
|
5bffea6f54 | ||
|
|
1c4f8e83d7 | ||
|
|
ff8663faa0 | ||
|
|
f58881e966 | ||
|
|
d2f279c3de | ||
|
|
4d4bab12eb | ||
|
|
eb6191d0ff | ||
|
|
54dfeb1fd9 | ||
|
|
c2c64caefe | ||
|
|
90be8d801b | ||
|
|
430897c9ac | ||
|
|
c77ab47cb5 | ||
|
|
bc85e3ce50 | ||
|
|
76b1ec1de0 | ||
|
|
6abccc4d5e | ||
|
|
7a3a2f8db9 | ||
|
|
4e8ccb2158 | ||
|
|
1affd498c1 | ||
|
|
e250429f56 | ||
|
|
bc4cbdc895 | ||
|
|
a388bcfad6 | ||
|
|
e39c5dc372 | ||
|
|
c45c8f34a1 | ||
|
|
73d193bd9c | ||
|
|
a4e7117429 | ||
|
|
9fe32b7777 | ||
|
|
6025bceaa1 | ||
|
|
91d04ede0f | ||
|
|
237c8c4deb | ||
|
|
0ba911279a | ||
|
|
baef3c8dd2 | ||
|
|
867ca2f25d | ||
|
|
247a5e2c49 | ||
|
|
7e8c6e5070 | ||
|
|
0d914ac1d4 | ||
|
|
76db65b1af | ||
|
|
ff8c0af8c8 | ||
|
|
55c6b88537 | ||
|
|
0771c23fb0 | ||
|
|
1c6214b76d | ||
|
|
b7f18b4601 | ||
|
|
242a77b391 | ||
|
|
35cf69ae64 | ||
|
|
ebc8489ff1 | ||
|
|
f21c5cbbe2 | ||
|
|
01386a206c | ||
|
|
3858309368 | ||
|
|
782717948a | ||
|
|
108fe7823c | ||
|
|
12a0dd3d0a | ||
|
|
1f4d1dcc58 | ||
|
|
53ab17cf50 | ||
|
|
79ba4598d6 | ||
|
|
96193c2044 | ||
|
|
09e5cc90a4 | ||
|
|
edf1875e88 | ||
|
|
1479142047 | ||
|
|
d1c10a61dd | ||
|
|
8205149675 | ||
|
|
eaece306b6 | ||
|
|
be9d23b329 | ||
|
|
dd65e57d4b | ||
|
|
e658ab3287 | ||
|
|
c0e190344d | ||
|
|
1c03862854 | ||
|
|
2315db161b | ||
|
|
9344bc4e9b | ||
|
|
01272f850d | ||
|
|
b95b871943 | ||
|
|
a314cfd237 | ||
|
|
c0b316fd9c | ||
|
|
3e6323a503 | ||
|
|
d1000e38d7 | ||
|
|
044674487e | ||
|
|
0070d2716c | ||
|
|
9b403e26e5 | ||
|
|
4b3b35c9de | ||
|
|
c88d124954 | ||
|
|
233d8a9b72 | ||
|
|
52e064dabb | ||
|
|
1a7fb06dd9 | ||
|
|
6fcf57ed1f | ||
|
|
ca9448bc11 | ||
|
|
2049daa008 | ||
|
|
947d1e2902 | ||
|
|
5f3160cf5b | ||
|
|
64f24fd276 | ||
|
|
124bd0c765 | ||
|
|
4b61f1756e | ||
|
|
2633198e6c | ||
|
|
b84cc46c3d | ||
|
|
96f882860f | ||
|
|
cfe6f595b0 | ||
|
|
6b16d48bad | ||
|
|
9f6862a456 | ||
|
|
4c9717187f | ||
|
|
a0dffb44d3 | ||
|
|
8f3be78667 | ||
|
|
dfdcbd184d | ||
|
|
f05a40feed | ||
|
|
f809529699 | ||
|
|
a3145bae07 | ||
|
|
b14afba859 | ||
|
|
c33b3dfa55 | ||
|
|
c448d85cf5 | ||
|
|
bc495a5c8c | ||
|
|
18dac6d415 | ||
|
|
5a72662d26 | ||
|
|
b479988044 | ||
|
|
a2d24b5b33 | ||
|
|
9a355c4bc5 | ||
|
|
fe869c9c22 | ||
|
|
f5f23f7291 | ||
|
|
a712c109d8 | ||
|
|
e5c56da321 | ||
|
|
be5dc2c57f | ||
|
|
e4c1f090af | ||
|
|
7a14455ac8 | ||
|
|
04876c663e | ||
|
|
70071e273d | ||
|
|
fb3bcc4ce5 | ||
|
|
1483f1e59a | ||
|
|
10cdbadd82 | ||
|
|
8955b8d8a7 | ||
|
|
1c5cb50da3 | ||
|
|
bddd6dd8a8 | ||
|
|
650725d71e | ||
|
|
c243378cab | ||
|
|
e15065b142 | ||
|
|
71fa198eee | ||
|
|
ca1715616f | ||
|
|
b12bade989 | ||
|
|
28566b4d64 | ||
|
|
dfd1473384 | ||
|
|
3fe0aa5026 | ||
|
|
6a502090f4 | ||
|
|
3d40fb294e | ||
|
|
81a30cbf06 | ||
|
|
2c1d96bcaa | ||
|
|
45eadc1b3a | ||
|
|
b453b8da99 | ||
|
|
567261e2c7 | ||
|
|
12e97dbea7 | ||
|
|
ef28ebb14a | ||
|
|
8545c08f30 | ||
|
|
eaf3424938 | ||
|
|
a5f13a5b31 | ||
|
|
d8431ff611 | ||
|
|
4eec4a0141 | ||
|
|
6db6a90b1e | ||
|
|
a13d10e42d | ||
|
|
271ceb968a | ||
|
|
b8d9d7894f | ||
|
|
7d3bd146e6 | ||
|
|
8b35f480c4 | ||
|
|
d9656f5220 | ||
|
|
87351fa35c | ||
|
|
edb31e606a | ||
|
|
8806f27220 | ||
|
|
858f11992f | ||
|
|
35562bd2f9 | ||
|
|
ebad0ded3d | ||
|
|
60e43ccbb1 | ||
|
|
ddcbcdea48 | ||
|
|
3491e7b707 | ||
|
|
bdc782617f | ||
|
|
80a7ed8116 | ||
|
|
13b38815c2 | ||
|
|
9dfce400a7 | ||
|
|
4ff38aa856 | ||
|
|
e5873d5dea | ||
|
|
8fbbebbaf1 | ||
|
|
89bfe84f36 | ||
|
|
585b8cc51d | ||
|
|
306c098d30 | ||
|
|
6db37b72a8 | ||
|
|
80ee3be4d0 | ||
|
|
e48c525053 | ||
|
|
cf9dfdb972 | ||
|
|
6ca5308c82 | ||
|
|
68663060dc | ||
|
|
87b48c94a6 | ||
|
|
45d8cb08ba | ||
|
|
130ae3ccb3 | ||
|
|
4eaa05db52 | ||
|
|
a19023fada | ||
|
|
85caa48814 | ||
|
|
cdda66a154 | ||
|
|
f8f335df55 | ||
|
|
28b46ad08c | ||
|
|
43323b2188 | ||
|
|
17a84c9a2c | ||
|
|
7eb9bec13f | ||
|
|
2867b31d2b | ||
|
|
3c524ac0e0 | ||
|
|
1a70dd4fb4 | ||
|
|
15eddf0c96 | ||
|
|
bbcad52ce0 | ||
|
|
ded3a30f55 | ||
|
|
38e256cece | ||
|
|
b4e03d1759 | ||
|
|
efd2dff0ca | ||
|
|
44748775ff | ||
|
|
f729c6b7f5 | ||
|
|
22fafc7054 | ||
|
|
32a699d6a3 | ||
|
|
46f5b62a76 | ||
|
|
e09d291e5d | ||
|
|
97a97fe992 | ||
|
|
f4f5ef6f83 | ||
|
|
a1281273bc | ||
|
|
42216184e1 | ||
|
|
2c945d33ee | ||
|
|
1c1d23d142 | ||
|
|
3fc791b0e8 | ||
|
|
7d39542522 | ||
|
|
6c5ed3f07f | ||
|
|
a2278e26af | ||
|
|
b28b8b9649 | ||
|
|
f1ab1af617 | ||
|
|
91a43c477c | ||
|
|
a4ade158f4 | ||
|
|
c46e1574dd | ||
|
|
a876a0ba44 | ||
|
|
819180f739 | ||
|
|
476e7992e8 | ||
|
|
e27fc03f55 | ||
|
|
ed4bf9b8fe | ||
|
|
773714792f | ||
|
|
dcf2735836 | ||
|
|
77f81fc49b | ||
|
|
46fb0e74cd | ||
|
|
2967c4ec10 | ||
|
|
88ada66280 | ||
|
|
3cf2fd595f | ||
|
|
3153ab9ae3 | ||
|
|
c91774be3b | ||
|
|
c66f087f4c | ||
|
|
441d7ff790 | ||
|
|
bc24fdbd14 | ||
|
|
ab070f2ebe | ||
|
|
5314ba8c6d | ||
|
|
f96698b54d | ||
|
|
fc15888697 | ||
|
|
9b91628d85 | ||
|
|
001ba17d37 | ||
|
|
1dc69e397e | ||
|
|
d56da1b014 | ||
|
|
d33dd4f7bc | ||
|
|
63f026f7c3 | ||
|
|
3f0106cfe5 | ||
|
|
4bab784e40 | ||
|
|
916421b247 | ||
|
|
a41bf74bad | ||
|
|
ad3db0e83c | ||
|
|
a5e7fd8f5c | ||
|
|
5663b2d697 | ||
|
|
44b52941f7 | ||
|
|
58a85f378c | ||
|
|
f135ec8468 | ||
|
|
e6bbc03ca8 | ||
|
|
e39036dd49 | ||
|
|
26de0db757 | ||
|
|
9e2df907f8 | ||
|
|
3c72461969 | ||
|
|
dfd28ab0c4 | ||
|
|
784399738a | ||
|
|
bc9232544c | ||
|
|
591e32af48 | ||
|
|
a4fd356fcb | ||
|
|
6849d18b03 | ||
|
|
6dfc40abc1 | ||
|
|
2946561dec | ||
|
|
d7948fcbcd | ||
|
|
fb605f6d7f | ||
|
|
2a428f09e6 | ||
|
|
8a4b629f40 | ||
|
|
b984e94a87 | ||
|
|
05a233f84d | ||
|
|
35f6e10646 | ||
|
|
61c0b8c3db | ||
|
|
ca956ca57e | ||
|
|
6670d22fb5 | ||
|
|
2ca1d111c5 | ||
|
|
b20f558abb | ||
|
|
c2148ba106 | ||
|
|
e53aee26a3 | ||
|
|
c610bd818e | ||
|
|
5e445f5a48 | ||
|
|
e86a74156e | ||
|
|
64d150e215 | ||
|
|
bd0c6a4ccc | ||
|
|
af38c902f8 | ||
|
|
a153e1d586 | ||
|
|
fe52c47570 | ||
|
|
6b63fa379f | ||
|
|
485f13de12 | ||
|
|
7f3ba0e6eb | ||
|
|
f58e8bc9a3 | ||
|
|
cac848c106 | ||
|
|
e4daadbfcf |
@@ -13,3 +13,4 @@
|
||||
### Conformance testing.
|
||||
conformance/ @raulk
|
||||
extern/test-vectors @raulk
|
||||
cmd/tvx @raulk
|
||||
+251
@@ -1,5 +1,256 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 0.9.0 / 2020-10-07
|
||||
|
||||
This consensus-breaking release of Lotus upgrades the actors version to v2.0.0. This requires migrating actor state from v0 to v2. The changes that break consensus are:
|
||||
|
||||
- Introducing v2 actors and its migration (https://github.com/filecoin-project/lotus/pull/3936)
|
||||
- Runtime's Receiver() should only return ID addresses (https://github.com/filecoin-project/lotus/pull/3589)
|
||||
- Update miner eligibility checks for v2 actors (https://github.com/filecoin-project/lotus/pull/4188)
|
||||
- Add funds that have left FilReserve to circ supply (https://github.com/filecoin-project/lotus/pull/4160)
|
||||
- Set WinningPoStSectorSetLookback to finality post-v2 actors (https://github.com/filecoin-project/lotus/pull/4190)
|
||||
- fix: error when actor panics directly (https://github.com/filecoin-project/lotus/pull/3697)
|
||||
|
||||
## Changes
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Update go-bitfield (https://github.com/filecoin-project/lotus/pull/4171)
|
||||
- update the AMT implementation (https://github.com/filecoin-project/lotus/pull/4194)
|
||||
- Update to actors v0.2.1 (https://github.com/filecoin-project/lotus/pull/4199)
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Paych: fix voucher amount verification (https://github.com/filecoin-project/lotus/pull/3821)
|
||||
- Cap market provider messages (https://github.com/filecoin-project/lotus/pull/4141)
|
||||
- Run fork function after cron for null block safety (https://github.com/filecoin-project/lotus/pull/4114)
|
||||
- use bitswap sessions when fetching messages, and cancel them (https://github.com/filecoin-project/lotus/pull/4142)
|
||||
- relax pubsub IPColocationFactorThreshold to 5 (https://github.com/filecoin-project/lotus/pull/4183)
|
||||
- Support addresses with mainnet prefixes (https://github.com/filecoin-project/lotus/pull/4186)
|
||||
- fix: make message signer nonce generation transactional (https://github.com/filecoin-project/lotus/pull/4165)
|
||||
- build: Env var to keep test address output (https://github.com/filecoin-project/lotus/pull/4213)
|
||||
- make vm.EnableGasTracing public (https://github.com/filecoin-project/lotus/pull/4214)
|
||||
- introduce separate state-tree versions (https://github.com/filecoin-project/lotus/pull/4197)
|
||||
- reject explicit "calls" at the upgrade height (https://github.com/filecoin-project/lotus/pull/4231)
|
||||
- return an illegal actor error when we see an unsupported actor version (https://github.com/filecoin-project/lotus/pull/4232)
|
||||
- Set head should unmark blocks as valid (https://gist.github.com/travisperson/3c7cddd77a33979a519ccef4e6515f20)
|
||||
|
||||
#### Mining
|
||||
|
||||
- Increased ExpectedSealDuration and and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743)
|
||||
- Miner backup/restore commands (https://github.com/filecoin-project/lotus/pull/4133)
|
||||
- lotus-miner: add more help text to storage / attach (https://github.com/filecoin-project/lotus/pull/3961)
|
||||
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
|
||||
- feat(miner): add miner deadline diffing logic (https://github.com/filecoin-project/lotus/pull/4178)
|
||||
|
||||
#### UX
|
||||
|
||||
- Improve the UX for replacing messages (https://github.com/filecoin-project/lotus/pull/4134)
|
||||
- Add verified flag to interactive deal creation (https://github.com/filecoin-project/lotus/pull/4145)
|
||||
- Add command to (slowly) prune lotus chain datastore (https://github.com/filecoin-project/lotus/pull/3876)
|
||||
- Some helpers for verifreg work (https://github.com/filecoin-project/lotus/pull/4124)
|
||||
- Always use default 720h for setask duration and hide the duration param option (https://github.com/filecoin-project/lotus/pull/4077)
|
||||
- Convert ID addresses to key addresses before checking wallet (https://github.com/filecoin-project/lotus/pull/4122)
|
||||
- add a command to view block space utilization (https://github.com/filecoin-project/lotus/pull/4176)
|
||||
- allow usage inspection on a chain segment (https://github.com/filecoin-project/lotus/pull/4177)
|
||||
- Add mpool stats for base fee (https://github.com/filecoin-project/lotus/pull/4170)
|
||||
- Add verified status to api.DealInfo (https://github.com/filecoin-project/lotus/pull/4153)
|
||||
- Add a CLI command to set a miner's owner address (https://github.com/filecoin-project/lotus/pull/4189)
|
||||
|
||||
#### Tooling and validation
|
||||
|
||||
- Lotus-pcr: add recover-miners command (https://github.com/filecoin-project/lotus/pull/3714)
|
||||
- MpoolPushUntrusted API for gateway (https://github.com/filecoin-project/lotus/pull/3915)
|
||||
- Test lotus-miner info all (https://github.com/filecoin-project/lotus/pull/4166)
|
||||
- chain export: Error with unfinished exports (https://github.com/filecoin-project/lotus/pull/4179)
|
||||
- add printf in TestWindowPost (https://github.com/filecoin-project/lotus/pull/4043)
|
||||
- add trace wdpost (https://github.com/filecoin-project/lotus/pull/4020)
|
||||
- Fix noncefix (https://github.com/filecoin-project/lotus/pull/4202)
|
||||
- Lotus-pcr: Limit the fee cap of messages we will process, refund gas fees for windowed post and storage deals (https://github.com/filecoin-project/lotus/pull/4198)
|
||||
- Fix pond (https://github.com/filecoin-project/lotus/pull/4203)
|
||||
- allow manual setting of noncefix fee cap (https://github.com/filecoin-project/lotus/pull/4205)
|
||||
- implement command to get execution traces of any message (https://github.com/filecoin-project/lotus/pull/4200)
|
||||
- conformance: minor driver refactors (https://github.com/filecoin-project/lotus/pull/4211)
|
||||
- lotus-pcr: ignore all other messages (https://github.com/filecoin-project/lotus/pull/4218)
|
||||
- lotus-pcr: zero refund (https://github.com/filecoin-project/lotus/pull/4229)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had 5 or more commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| Stebalien | 84 | +3425/-2287 |
|
||||
| magik6k | 41 | +2121/-506 |
|
||||
| arajasek | 39 | +2467/-424 |
|
||||
| Kubuxu | 25 | +2344/-775 |
|
||||
| raulk | 21 | +287/-196 |
|
||||
| whyrusleeping | 13 | +727/-71 |
|
||||
| hsanjuan | 13 | +5886/-7956 |
|
||||
| dirkmc | 11 | +2634/-576 |
|
||||
| travisperson | 8 | +923/-202 |
|
||||
| ribasushi | 6 | +188/-128 |
|
||||
| zgfzgf | 5 | +21/-17 |
|
||||
|
||||
# 0.8.1 / 2020-09-30
|
||||
|
||||
This optional release of Lotus introduces a new version of markets which switches to CBOR-map encodings, and allows datastore migrations. The release also introduces several improvements to the mining process, a few performance optimizations, and a battery of UX additions and enhancements.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Markets 0.7.0 with updated data stores (https://github.com/filecoin-project/lotus/pull/4089)
|
||||
- Update ffi to code with blst fixes (https://github.com/filecoin-project/lotus/pull/3998)
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Fix GetPower with no miner address (https://github.com/filecoin-project/lotus/pull/4049)
|
||||
- Refactor: Move nonce generation out of mpool (https://github.com/filecoin-project/lotus/pull/3970)
|
||||
|
||||
#### Performance
|
||||
|
||||
- Implement caching syscalls for import-bench (https://github.com/filecoin-project/lotus/pull/3888)
|
||||
- Fetch tipset blocks in parallel (https://github.com/filecoin-project/lotus/pull/4074)
|
||||
- Optimize Tipset equals() (https://github.com/filecoin-project/lotus/pull/4056)
|
||||
- Make state transition in validation async (https://github.com/filecoin-project/lotus/pull/3868)
|
||||
|
||||
#### Mining
|
||||
|
||||
- Add trace window post (https://github.com/filecoin-project/lotus/pull/4020)
|
||||
- Use abstract types for Dont recompute post on revert (https://github.com/filecoin-project/lotus/pull/4022)
|
||||
- Fix injectNulls logic in test miner (https://github.com/filecoin-project/lotus/pull/4058)
|
||||
- Fix potential panic in FinalizeSector (https://github.com/filecoin-project/lotus/pull/4092)
|
||||
- Don't recompute post on revert (https://github.com/filecoin-project/lotus/pull/3924)
|
||||
- Fix some failed precommit handling (https://github.com/filecoin-project/lotus/pull/3445)
|
||||
- Add --no-swap flag for worker (https://github.com/filecoin-project/lotus/pull/4107)
|
||||
- Allow some single-thread tasks to run in parallel with PC2/C2 (https://github.com/filecoin-project/lotus/pull/4116)
|
||||
|
||||
#### UX
|
||||
|
||||
- Add an envvar to set address network version (https://github.com/filecoin-project/lotus/pull/4028)
|
||||
- Add logging to chain export (https://github.com/filecoin-project/lotus/pull/4030)
|
||||
- Add JSON output to state compute (https://github.com/filecoin-project/lotus/pull/4038)
|
||||
- Wallet list CLI: Print balances/nonces (https://github.com/filecoin-project/lotus/pull/4088)
|
||||
- Added an option to show or not show sector info for `lotus-miner info` (https://github.com/filecoin-project/lotus/pull/4003)
|
||||
- Add a command to import an ipld object into the chainstore (https://github.com/filecoin-project/lotus/pull/3434)
|
||||
- Improve the lotus-shed dealtracker (https://github.com/filecoin-project/lotus/pull/4051)
|
||||
- Docs review and re-organization (https://github.com/filecoin-project/lotus/pull/3431)
|
||||
- Fix wallet list (https://github.com/filecoin-project/lotus/pull/4104)
|
||||
- Add an endpoint to validate whether a string is a well-formed address (https://github.com/filecoin-project/lotus/pull/4106)
|
||||
- Add an option to set config path (https://github.com/filecoin-project/lotus/pull/4103)
|
||||
- Add printf in TestWindowPost (https://github.com/filecoin-project/lotus/pull/4043)
|
||||
- Improve miner sectors list UX (https://github.com/filecoin-project/lotus/pull/4108)
|
||||
|
||||
#### Tooling
|
||||
|
||||
- Move policy change to seal bench (https://github.com/filecoin-project/lotus/pull/4032)
|
||||
- Add back network power to stats (https://github.com/filecoin-project/lotus/pull/4050)
|
||||
- Conformance: Record and feed circulating supply (https://github.com/filecoin-project/lotus/pull/4078)
|
||||
- Snapshot import progress bar, add HTTP support (https://github.com/filecoin-project/lotus/pull/4070)
|
||||
- Add lotus shed util to validate a tipset (https://github.com/filecoin-project/lotus/pull/4065)
|
||||
- tvx: a test vector extraction and execution tool (https://github.com/filecoin-project/lotus/pull/4064)
|
||||
|
||||
#### Bootstrap
|
||||
|
||||
- Add new bootstrappers (https://github.com/filecoin-project/lotus/pull/4007)
|
||||
- Add Glif node to bootstrap peers (https://github.com/filecoin-project/lotus/pull/4004)
|
||||
- Add one more node located in China (https://github.com/filecoin-project/lotus/pull/4041)
|
||||
- Add ipfsmain bootstrapper (https://github.com/filecoin-project/lotus/pull/4067)
|
||||
|
||||
# 0.8.0 / 2020-09-26
|
||||
|
||||
This consensus-breaking release of Lotus introduces an upgrade to the network. The changes that break consensus are:
|
||||
|
||||
- Upgrading to specs-actors v0.9.11, which reduces WindowPoSt faults per [FIP 0002](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0002.md) to reduce cost for honest miners with occasional faults (see https://github.com/filecoin-project/specs-actors/pull/1181)
|
||||
- Revisions to some cryptoeconomics and network params
|
||||
|
||||
This release also updates go-fil-markets to fix an incompatibility issue between v0.7.2 and earlier versions.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Dependencies
|
||||
|
||||
- Update spec actors to 0.9.11 (https://github.com/filecoin-project/lotus/pull/4039)
|
||||
- Update markets to 0.6.3 (https://github.com/filecoin-project/lotus/pull/4013)
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Network upgrade (https://github.com/filecoin-project/lotus/pull/4039)
|
||||
- Fix AddSupportedProofTypes (https://github.com/filecoin-project/lotus/pull/4033)
|
||||
- Return an error when we fail to find a sector when checking sector expiration (https://github.com/filecoin-project/lotus/pull/4026)
|
||||
- Batch blockstore copies after block validation (https://github.com/filecoin-project/lotus/pull/3980)
|
||||
- Remove a misleading miner actor abstraction (https://github.com/filecoin-project/lotus/pull/3977)
|
||||
- Fix out-of-bounds when loading all sector infos (https://github.com/filecoin-project/lotus/pull/3976)
|
||||
- Fix break condition in the miner (https://github.com/filecoin-project/lotus/pull/3953)
|
||||
|
||||
#### UX
|
||||
|
||||
- Correct helptext around miners setting ask (https://github.com/filecoin-project/lotus/pull/4009)
|
||||
- Make sync wait nicer (https://github.com/filecoin-project/lotus/pull/3991)
|
||||
|
||||
#### Tooling and validation
|
||||
|
||||
- Small adjustments following network upgradability changes (https://github.com/filecoin-project/lotus/pull/3996)
|
||||
- Add some more big pictures stats to stateroot stat (https://github.com/filecoin-project/lotus/pull/3995)
|
||||
- Add some actors policy setters for testing (https://github.com/filecoin-project/lotus/pull/3975)
|
||||
|
||||
## Contributors
|
||||
|
||||
The following contributors had 5 or more commits go into this release.
|
||||
We are grateful for every contribution!
|
||||
|
||||
| Contributor | Commits | Lines ± |
|
||||
|--------------------|---------|---------------|
|
||||
| arajasek | 66 | +3140/-1261 |
|
||||
| Stebalien | 64 | +3797/-3434 |
|
||||
| magik6k | 48 | +1892/-976 |
|
||||
| raulk | 40 | +2412/-1549 |
|
||||
| vyzo | 22 | +287/-196 |
|
||||
| alanshaw | 15 | +761/-146 |
|
||||
| whyrusleeping | 15 | +736/-52 |
|
||||
| hannahhoward | 14 | +1237/-837 |
|
||||
| anton | 6 | +32/-8 |
|
||||
| travisperson | 5 | +502/-6 |
|
||||
| Frank | 5 | +78/-39 |
|
||||
| Jennifer | 5 | +148/-41 |
|
||||
|
||||
# 0.7.2 / 2020-09-23
|
||||
|
||||
This optional release of Lotus introduces a major refactor around how a Lotus node interacts with code from the specs-actors repo. We now use interfaces to read the state of actors, which is required to be able to reason about different versions of actors code at the same time.
|
||||
|
||||
Additionally, this release introduces various improvements to the sync process, as well as changes to better the overall UX experience.
|
||||
|
||||
## Changes
|
||||
|
||||
#### Core Lotus
|
||||
|
||||
- Network upgrade support (https://github.com/filecoin-project/lotus/pull/3781)
|
||||
- Upgrade markets to `v0.6.2` (https://github.com/filecoin-project/lotus/pull/3974)
|
||||
- Validate chain sync response indices when fetching messages (https://github.com/filecoin-project/lotus/pull/3939)
|
||||
- Add height diff to sync wait (https://github.com/filecoin-project/lotus/pull/3926)
|
||||
- Replace Requires with Wants (https://github.com/filecoin-project/lotus/pull/3898)
|
||||
- Update state diffing for market actor (https://github.com/filecoin-project/lotus/pull/3889)
|
||||
- Parallel fetch for sync (https://github.com/filecoin-project/lotus/pull/3887)
|
||||
- Fix SectorState (https://github.com/filecoin-project/lotus/pull/3881)
|
||||
|
||||
#### User Experience
|
||||
|
||||
- Add basic deal stats api server for spacerace slingshot (https://github.com/filecoin-project/lotus/pull/3963)
|
||||
- When doing `sectors update-state`, show a list of existing states if user inputs an invalid one (https://github.com/filecoin-project/lotus/pull/3944)
|
||||
- Fix `lotus-miner storage find` error (https://github.com/filecoin-project/lotus/pull/3927)
|
||||
- Log shutdown method for lotus daemon and miner (https://github.com/filecoin-project/lotus/pull/3925)
|
||||
- Update build and setup instruction link (https://github.com/filecoin-project/lotus/pull/3919)
|
||||
- Add an option to hide removed sectors from `sectors list` output (https://github.com/filecoin-project/lotus/pull/3903)
|
||||
|
||||
#### Testing and validation
|
||||
|
||||
- Add init.State#Remove() for testing (https://github.com/filecoin-project/lotus/pull/3971)
|
||||
- lotus-shed: add consensus check command (https://github.com/filecoin-project/lotus/pull/3933)
|
||||
- Add keyinfo verify and jwt token command to lotus-shed (https://github.com/filecoin-project/lotus/pull/3914)
|
||||
- Fix conformance gen (https://github.com/filecoin-project/lotus/pull/3892)
|
||||
|
||||
# 0.7.1 / 2020-09-17
|
||||
|
||||
This optional release of Lotus introduces some critical fixes to the window PoSt process. It also upgrades some core dependencies, and introduces many improvements to the mining process, deal-making cycle, and overall User Experience.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<a href="https://lotu.sh/" title="Lotus Docs">
|
||||
<a href="https://docs.filecoin.io/" title="Filecoin Docs">
|
||||
<img src="documentation/images/lotus_logo_h.png" alt="Project Lotus Logo" width="244" />
|
||||
</a>
|
||||
</p>
|
||||
@@ -18,7 +18,7 @@ Lotus is an implementation of the Filecoin Distributed Storage Network. For more
|
||||
|
||||
## Building & Documentation
|
||||
|
||||
For instructions on how to build lotus from source, please visit [Lotus build and setup instruction](https://docs.filecoin.io/get-started/lotus/installation/#minimal-requirements) or read the source [here](https://github.com/filecoin-project/lotus/tree/master/documentation).
|
||||
For instructions on how to build, install and setup lotus, please visit [https://docs.filecoin.io/get-started/lotus](https://docs.filecoin.io/get-started/lotus/).
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
+53
-12
@@ -21,9 +21,9 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
@@ -76,6 +76,9 @@ type FullNode interface {
|
||||
// blockstore and returns raw bytes.
|
||||
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
||||
|
||||
// ChainDeleteObj deletes node referenced by the given CID
|
||||
ChainDeleteObj(context.Context, cid.Cid) error
|
||||
|
||||
// ChainHasObj checks if a given CID exists in the chain blockstore.
|
||||
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
||||
|
||||
@@ -173,6 +176,9 @@ type FullNode interface {
|
||||
// the reason.
|
||||
SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error)
|
||||
|
||||
// SyncValidateTipset indicates whether the provided tipset is valid or not
|
||||
SyncValidateTipset(ctx context.Context, tsk types.TipSetKey) (bool, error)
|
||||
|
||||
// MethodGroup: Mpool
|
||||
// The Mpool methods are for interacting with the message pool. The message pool
|
||||
// manages all incoming and outgoing 'messages' going over the network.
|
||||
@@ -186,6 +192,9 @@ type FullNode interface {
|
||||
// MpoolPush pushes a signed message to mempool.
|
||||
MpoolPush(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||
|
||||
// MpoolPushUntrusted pushes a signed message to mempool from untrusted sources.
|
||||
MpoolPushUntrusted(context.Context, *types.SignedMessage) (cid.Cid, error)
|
||||
|
||||
// MpoolPushMessage atomically assigns a nonce, signs, and pushes a message
|
||||
// to mempool.
|
||||
// maxFee is only used when GasFeeCap/GasPremium fields aren't specified
|
||||
@@ -241,6 +250,8 @@ type FullNode interface {
|
||||
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||
// WalletDelete deletes an address from the wallet.
|
||||
WalletDelete(context.Context, address.Address) error
|
||||
// WalletValidateAddress validates whether a given string can be decoded as a well-formed address
|
||||
WalletValidateAddress(context.Context, string) (address.Address, error)
|
||||
|
||||
// Other
|
||||
|
||||
@@ -272,7 +283,7 @@ type FullNode interface {
|
||||
// of status updates.
|
||||
ClientRetrieveWithEvents(ctx context.Context, order RetrievalOrder, ref *FileRef) (<-chan marketevents.RetrievalEvent, error)
|
||||
// ClientQueryAsk returns a signed StorageAsk from the specified miner.
|
||||
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error)
|
||||
ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.StorageAsk, error)
|
||||
// ClientCalcCommP calculates the CommP for a specified file
|
||||
ClientCalcCommP(ctx context.Context, inpath string) (*CommPRet, error)
|
||||
// ClientGenCar generates a CAR file for the specified file.
|
||||
@@ -382,10 +393,16 @@ type FullNode interface {
|
||||
// StateCompute is a flexible command that applies the given messages on the given tipset.
|
||||
// The messages are run as though the VM were at the provided height.
|
||||
StateCompute(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*ComputeStateOutput, error)
|
||||
// StateVerifierStatus returns the data cap for the given address.
|
||||
// Returns nil if there is no entry in the data cap table for the
|
||||
// address.
|
||||
StateVerifierStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
|
||||
// StateVerifiedClientStatus returns the data cap for the given address.
|
||||
// Returns nil if there is no entry in the data cap table for the
|
||||
// address.
|
||||
StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error)
|
||||
// StateVerifiedClientStatus returns the address of the Verified Registry's root key
|
||||
StateVerifiedRegistryRootKey(ctx context.Context, tsk types.TipSetKey) (address.Address, error)
|
||||
// StateDealProviderCollateralBounds returns the min and max collateral a storage provider
|
||||
// can issue. It takes the deal size and verified status as parameters.
|
||||
StateDealProviderCollateralBounds(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (DealCollateralBounds, error)
|
||||
@@ -401,6 +418,9 @@ type FullNode interface {
|
||||
|
||||
// MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent
|
||||
MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error)
|
||||
// MsigGetLockedBalance returns the locked balance of an msig at a vien epoch.
|
||||
// The return may be greater than the multisig actor's actual balance.
|
||||
MsigGetVestingSchedule(context.Context, address.Address, types.TipSetKey) (MsigVesting, error)
|
||||
// MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.
|
||||
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error)
|
||||
@@ -467,6 +487,12 @@ type FullNode interface {
|
||||
PaychVoucherAdd(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error)
|
||||
PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error)
|
||||
PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error)
|
||||
|
||||
// CreateBackup creates node backup onder the specified file name. The
|
||||
// method requires that the lotus daemon is running with the
|
||||
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||
// the path specified when calling CreateBackup is within the base path
|
||||
CreateBackup(ctx context.Context, fpath string) error
|
||||
}
|
||||
|
||||
type FileRef struct {
|
||||
@@ -513,6 +539,7 @@ type DealInfo struct {
|
||||
DealID abi.DealID
|
||||
|
||||
CreationTime time.Time
|
||||
Verified bool
|
||||
}
|
||||
|
||||
type MsgLookup struct {
|
||||
@@ -722,6 +749,8 @@ type ActiveSync struct {
|
||||
|
||||
type SyncState struct {
|
||||
ActiveSyncs []ActiveSync
|
||||
|
||||
VMApplied uint64
|
||||
}
|
||||
|
||||
type SyncStateStage int
|
||||
@@ -786,14 +815,14 @@ type CirculatingSupply struct {
|
||||
}
|
||||
|
||||
type MiningBaseInfo struct {
|
||||
MinerPower types.BigInt
|
||||
NetworkPower types.BigInt
|
||||
Sectors []proof.SectorInfo
|
||||
WorkerKey address.Address
|
||||
SectorSize abi.SectorSize
|
||||
PrevBeaconEntry types.BeaconEntry
|
||||
BeaconEntries []types.BeaconEntry
|
||||
HasMinPower bool
|
||||
MinerPower types.BigInt
|
||||
NetworkPower types.BigInt
|
||||
Sectors []builtin.SectorInfo
|
||||
WorkerKey address.Address
|
||||
SectorSize abi.SectorSize
|
||||
PrevBeaconEntry types.BeaconEntry
|
||||
BeaconEntries []types.BeaconEntry
|
||||
EligibleForMining bool
|
||||
}
|
||||
|
||||
type BlockTemplate struct {
|
||||
@@ -805,7 +834,7 @@ type BlockTemplate struct {
|
||||
Messages []*types.SignedMessage
|
||||
Epoch abi.ChainEpoch
|
||||
Timestamp uint64
|
||||
WinningPoStProof []proof.PoStProof
|
||||
WinningPoStProof []builtin.PoStProof
|
||||
}
|
||||
|
||||
type DataSize struct {
|
||||
@@ -845,3 +874,15 @@ type Fault struct {
|
||||
Miner address.Address
|
||||
Epoch abi.ChainEpoch
|
||||
}
|
||||
|
||||
var EmptyVesting = MsigVesting{
|
||||
InitialBalance: types.EmptyInt,
|
||||
StartEpoch: -1,
|
||||
UnlockDuration: -1,
|
||||
}
|
||||
|
||||
type MsigVesting struct {
|
||||
InitialBalance abi.TokenAmount
|
||||
StartEpoch abi.ChainEpoch
|
||||
UnlockDuration abi.ChainEpoch
|
||||
}
|
||||
|
||||
@@ -101,6 +101,12 @@ type StorageMiner interface {
|
||||
PiecesListCidInfos(ctx context.Context) ([]cid.Cid, error)
|
||||
PiecesGetPieceInfo(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error)
|
||||
PiecesGetCIDInfo(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error)
|
||||
|
||||
// CreateBackup creates node backup onder the specified file name. The
|
||||
// method requires that the lotus-miner is running with the
|
||||
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||
// the path specified when calling CreateBackup is within the base path
|
||||
CreateBackup(ctx context.Context, fpath string) error
|
||||
}
|
||||
|
||||
type SealRes struct {
|
||||
|
||||
+64
-16
@@ -29,12 +29,12 @@ import (
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/stores"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/storiface"
|
||||
marketevents "github.com/filecoin-project/lotus/markets/loggers"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-storage/storage"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
@@ -87,6 +87,7 @@ type FullNodeStruct struct {
|
||||
ChainGetParentMessages func(context.Context, cid.Cid) ([]api.Message, error) `perm:"read"`
|
||||
ChainGetTipSetByHeight func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) `perm:"read"`
|
||||
ChainReadObj func(context.Context, cid.Cid) ([]byte, error) `perm:"read"`
|
||||
ChainDeleteObj func(context.Context, cid.Cid) error `perm:"admin"`
|
||||
ChainHasObj func(context.Context, cid.Cid) (bool, error) `perm:"read"`
|
||||
ChainStatObj func(context.Context, cid.Cid, cid.Cid) (api.ObjStat, error) `perm:"read"`
|
||||
ChainSetHead func(context.Context, types.TipSetKey) error `perm:"admin"`
|
||||
@@ -111,6 +112,7 @@ type FullNodeStruct struct {
|
||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"`
|
||||
SyncValidateTipset func(ctx context.Context, tsk types.TipSetKey) (bool, error) `perm:"read"`
|
||||
|
||||
MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
||||
MpoolSetConfig func(context.Context, *types.MpoolConfig) error `perm:"write"`
|
||||
@@ -120,7 +122,9 @@ type FullNodeStruct struct {
|
||||
MpoolPending func(context.Context, types.TipSetKey) ([]*types.SignedMessage, error) `perm:"read"`
|
||||
MpoolClear func(context.Context, bool) error `perm:"write"`
|
||||
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPush func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
MpoolPushUntrusted func(context.Context, *types.SignedMessage) (cid.Cid, error) `perm:"write"`
|
||||
|
||||
MpoolPushMessage func(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) `perm:"sign"`
|
||||
MpoolGetNonce func(context.Context, address.Address) (uint64, error) `perm:"read"`
|
||||
MpoolSub func(context.Context) (<-chan api.MpoolUpdate, error) `perm:"read"`
|
||||
@@ -128,18 +132,19 @@ type FullNodeStruct struct {
|
||||
MinerGetBaseInfo func(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*api.MiningBaseInfo, error) `perm:"read"`
|
||||
MinerCreateBlock func(context.Context, *api.BlockTemplate) (*types.BlockMsg, error) `perm:"write"`
|
||||
|
||||
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
||||
WalletSign func(context.Context, address.Address, []byte) (*crypto.Signature, error) `perm:"sign"`
|
||||
WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
WalletVerify func(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) `perm:"read"`
|
||||
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
|
||||
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
|
||||
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||
WalletNew func(context.Context, crypto.SigType) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
WalletBalance func(context.Context, address.Address) (types.BigInt, error) `perm:"read"`
|
||||
WalletSign func(context.Context, address.Address, []byte) (*crypto.Signature, error) `perm:"sign"`
|
||||
WalletSignMessage func(context.Context, address.Address, *types.Message) (*types.SignedMessage, error) `perm:"sign"`
|
||||
WalletVerify func(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) `perm:"read"`
|
||||
WalletDefaultAddress func(context.Context) (address.Address, error) `perm:"write"`
|
||||
WalletSetDefault func(context.Context, address.Address) error `perm:"admin"`
|
||||
WalletExport func(context.Context, address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||
WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"`
|
||||
WalletDelete func(context.Context, address.Address) error `perm:"write"`
|
||||
WalletValidateAddress func(context.Context, string) (address.Address, error) `perm:"read"`
|
||||
|
||||
ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"`
|
||||
ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"`
|
||||
@@ -153,7 +158,7 @@ type FullNodeStruct struct {
|
||||
ClientGetDealUpdates func(ctx context.Context) (<-chan api.DealInfo, error) `perm:"read"`
|
||||
ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"`
|
||||
ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"`
|
||||
ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.StorageAsk, error) `perm:"read"`
|
||||
ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"`
|
||||
ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"`
|
||||
ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"`
|
||||
@@ -199,12 +204,15 @@ type FullNodeStruct struct {
|
||||
StateMinerSectorCount func(context.Context, address.Address, types.TipSetKey) (api.MinerSectors, error) `perm:"read"`
|
||||
StateListMessages func(ctx context.Context, match *types.Message, tsk types.TipSetKey, toht abi.ChainEpoch) ([]cid.Cid, error) `perm:"read"`
|
||||
StateCompute func(context.Context, abi.ChainEpoch, []*types.Message, types.TipSetKey) (*api.ComputeStateOutput, error) `perm:"read"`
|
||||
StateVerifierStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
|
||||
StateVerifiedClientStatus func(context.Context, address.Address, types.TipSetKey) (*abi.StoragePower, error) `perm:"read"`
|
||||
StateVerifiedRegistryRootKey func(ctx context.Context, tsk types.TipSetKey) (address.Address, error) `perm:"read"`
|
||||
StateDealProviderCollateralBounds func(context.Context, abi.PaddedPieceSize, bool, types.TipSetKey) (api.DealCollateralBounds, error) `perm:"read"`
|
||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"`
|
||||
StateNetworkVersion func(context.Context, types.TipSetKey) (stnetwork.Version, error) `perm:"read"`
|
||||
|
||||
MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigGetVestingSchedule func(context.Context, address.Address, types.TipSetKey) (api.MsigVesting, error) `perm:"read"`
|
||||
MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -236,6 +244,8 @@ type FullNodeStruct struct {
|
||||
PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"`
|
||||
PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"`
|
||||
PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
CreateBackup func(ctx context.Context, fpath string) error `perm:"admin"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +326,8 @@ type StorageMinerStruct struct {
|
||||
PiecesListCidInfos func(ctx context.Context) ([]cid.Cid, error) `perm:"read"`
|
||||
PiecesGetPieceInfo func(ctx context.Context, pieceCid cid.Cid) (*piecestore.PieceInfo, error) `perm:"read"`
|
||||
PiecesGetCIDInfo func(ctx context.Context, payloadCid cid.Cid) (*piecestore.CIDInfo, error) `perm:"read"`
|
||||
|
||||
CreateBackup func(ctx context.Context, fpath string) error `perm:"admin"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,7 +495,7 @@ func (c *FullNodeStruct) ClientRetrieveWithEvents(ctx context.Context, order api
|
||||
return c.Internal.ClientRetrieveWithEvents(ctx, order, ref)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) {
|
||||
func (c *FullNodeStruct) ClientQueryAsk(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.StorageAsk, error) {
|
||||
return c.Internal.ClientQueryAsk(ctx, p, miner)
|
||||
}
|
||||
func (c *FullNodeStruct) ClientCalcCommP(ctx context.Context, inpath string) (*api.CommPRet, error) {
|
||||
@@ -550,6 +562,10 @@ func (c *FullNodeStruct) MpoolPush(ctx context.Context, smsg *types.SignedMessag
|
||||
return c.Internal.MpoolPush(ctx, smsg)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPushUntrusted(ctx context.Context, smsg *types.SignedMessage) (cid.Cid, error) {
|
||||
return c.Internal.MpoolPushUntrusted(ctx, smsg)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) {
|
||||
return c.Internal.MpoolPushMessage(ctx, msg, spec)
|
||||
}
|
||||
@@ -630,6 +646,10 @@ func (c *FullNodeStruct) WalletDelete(ctx context.Context, addr address.Address)
|
||||
return c.Internal.WalletDelete(ctx, addr)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) WalletValidateAddress(ctx context.Context, str string) (address.Address, error) {
|
||||
return c.Internal.WalletValidateAddress(ctx, str)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
|
||||
return c.Internal.MpoolGetNonce(ctx, addr)
|
||||
}
|
||||
@@ -662,6 +682,10 @@ func (c *FullNodeStruct) ChainReadObj(ctx context.Context, obj cid.Cid) ([]byte,
|
||||
return c.Internal.ChainReadObj(ctx, obj)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainDeleteObj(ctx context.Context, obj cid.Cid) error {
|
||||
return c.Internal.ChainDeleteObj(ctx, obj)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ChainHasObj(ctx context.Context, o cid.Cid) (bool, error) {
|
||||
return c.Internal.ChainHasObj(ctx, o)
|
||||
}
|
||||
@@ -730,6 +754,10 @@ func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string
|
||||
return c.Internal.SyncCheckBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncValidateTipset(ctx context.Context, tsk types.TipSetKey) (bool, error) {
|
||||
return c.Internal.SyncValidateTipset(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
|
||||
return c.Internal.StateNetworkName(ctx)
|
||||
}
|
||||
@@ -878,10 +906,18 @@ func (c *FullNodeStruct) StateCompute(ctx context.Context, height abi.ChainEpoch
|
||||
return c.Internal.StateCompute(ctx, height, msgs, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVerifierStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) {
|
||||
return c.Internal.StateVerifierStatus(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*abi.StoragePower, error) {
|
||||
return c.Internal.StateVerifiedClientStatus(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVerifiedRegistryRootKey(ctx context.Context, tsk types.TipSetKey) (address.Address, error) {
|
||||
return c.Internal.StateVerifiedRegistryRootKey(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) {
|
||||
return c.Internal.StateDealProviderCollateralBounds(ctx, size, verified, tsk)
|
||||
}
|
||||
@@ -898,6 +934,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address.
|
||||
return c.Internal.MsigGetAvailableBalance(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVestingSchedule(ctx context.Context, a address.Address, tsk types.TipSetKey) (api.MsigVesting, error) {
|
||||
return c.Internal.MsigGetVestingSchedule(ctx, a, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) {
|
||||
return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk)
|
||||
}
|
||||
@@ -1010,6 +1050,10 @@ func (c *FullNodeStruct) PaychVoucherSubmit(ctx context.Context, ch address.Addr
|
||||
return c.Internal.PaychVoucherSubmit(ctx, ch, sv, secret, proof)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) CreateBackup(ctx context.Context, fpath string) error {
|
||||
return c.Internal.CreateBackup(ctx, fpath)
|
||||
}
|
||||
|
||||
// StorageMinerStruct
|
||||
|
||||
func (c *StorageMinerStruct) ActorAddress(ctx context.Context) (address.Address, error) {
|
||||
@@ -1250,6 +1294,10 @@ func (c *StorageMinerStruct) PiecesGetCIDInfo(ctx context.Context, payloadCid ci
|
||||
return c.Internal.PiecesGetCIDInfo(ctx, payloadCid)
|
||||
}
|
||||
|
||||
func (c *StorageMinerStruct) CreateBackup(ctx context.Context, fpath string) error {
|
||||
return c.Internal.CreateBackup(ctx, fpath)
|
||||
}
|
||||
|
||||
// WorkerStruct
|
||||
|
||||
func (w *WorkerStruct) Version(ctx context.Context) (build.Version, error) {
|
||||
|
||||
+38
-1
@@ -12,15 +12,36 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
)
|
||||
|
||||
func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
for _, height := range []abi.ChainEpoch{
|
||||
1, // before
|
||||
162, // while sealing
|
||||
520, // after upgrade deal
|
||||
5000, // after
|
||||
} {
|
||||
height := height // make linters happy by copying
|
||||
t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) {
|
||||
testCCUpgrade(t, b, blocktime, height)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, upgradeHeight abi.ChainEpoch) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}))
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -94,6 +115,22 @@ func TestCCUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
require.Less(t, 50000, int(exp.OnTime))
|
||||
}
|
||||
|
||||
dlInfo, err := client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Sector should expire.
|
||||
for {
|
||||
// Wait for the sector to expire.
|
||||
status, err := miner.SectorsStatus(ctx, CC, true)
|
||||
require.NoError(t, err)
|
||||
if status.OnTime == 0 && status.Early == 0 {
|
||||
break
|
||||
}
|
||||
t.Log("waiting for sector to expire")
|
||||
// wait one deadline per loop.
|
||||
time.Sleep(time.Duration(dlInfo.WPoStChallengeWindow) * blocktime)
|
||||
}
|
||||
|
||||
fmt.Println("shutting down mining")
|
||||
atomic.AddInt64(&mine, -1)
|
||||
<-done
|
||||
|
||||
+4
-1
@@ -402,9 +402,12 @@ func testRetrieval(t *testing.T, ctx context.Context, client *impl.FullNodeAPI,
|
||||
IsCAR: carExport,
|
||||
}
|
||||
updates, err := client.ClientRetrieveWithEvents(ctx, offers[0].Order(caddr), ref)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for update := range updates {
|
||||
if update.Err != "" {
|
||||
t.Fatalf("%v", err)
|
||||
t.Fatalf("retrieval failed: %s", update.Err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+67
-9
@@ -8,17 +8,21 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/api/apibstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -67,7 +71,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
channelAmt := int64(100000)
|
||||
channelAmt := int64(7000)
|
||||
channelInfo, err := paymentCreator.PaychGet(ctx, createrAddr, receiverAddr, abi.NewTokenAmount(channelAmt))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -133,17 +137,26 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Fatal("Unable to settle payment channel")
|
||||
}
|
||||
|
||||
creatorStore := adt.WrapStore(ctx, cbor.NewCborStore(apibstore.NewAPIBlockstore(paymentCreator)))
|
||||
|
||||
// wait for the receiver to submit their vouchers
|
||||
ev := events.NewEvents(ctx, paymentCreator)
|
||||
preds := state.NewStatePredicates(paymentCreator)
|
||||
finished := make(chan struct{})
|
||||
err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) {
|
||||
act, err := paymentCreator.StateReadState(ctx, channel, ts.Key())
|
||||
act, err := paymentCreator.StateGetActor(ctx, channel, ts.Key())
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
state := act.State.(paych.State)
|
||||
if state.ToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
||||
state, err := paych.Load(creatorStore, act)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
toSend, err := state.ToSend()
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if toSend.GreaterThanEqual(abi.NewTokenAmount(6000)) {
|
||||
return true, false, nil
|
||||
}
|
||||
return false, true, nil
|
||||
@@ -156,7 +169,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
return true, nil
|
||||
}, func(ctx context.Context, ts *types.TipSet) error {
|
||||
return nil
|
||||
}, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
||||
}, int(build.MessageConfidence)+1, build.Finality, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
|
||||
return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key())
|
||||
})
|
||||
if err != nil {
|
||||
@@ -169,8 +182,53 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Fatal("Timed out waiting for receiver to submit vouchers")
|
||||
}
|
||||
|
||||
// Create a new voucher now that some vouchers have already been submitted
|
||||
vouchRes, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(1000), 3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if vouchRes.Voucher == nil {
|
||||
t.Fatal(fmt.Errorf("Not enough funds to create voucher: missing %d", vouchRes.Shortfall))
|
||||
}
|
||||
vdelta, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouchRes.Voucher, nil, abi.NewTokenAmount(1000))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !vdelta.Equals(abi.NewTokenAmount(1000)) {
|
||||
t.Fatal("voucher didn't have the right amount")
|
||||
}
|
||||
|
||||
// Create a new voucher whose value would exceed the channel balance
|
||||
excessAmt := abi.NewTokenAmount(1000)
|
||||
vouchRes, err = paymentCreator.PaychVoucherCreate(ctx, channel, excessAmt, 4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if vouchRes.Voucher != nil {
|
||||
t.Fatal("Expected not to be able to create voucher whose value would exceed channel balance")
|
||||
}
|
||||
if !vouchRes.Shortfall.Equals(excessAmt) {
|
||||
t.Fatal(fmt.Errorf("Expected voucher shortfall of %d, got %d", excessAmt, vouchRes.Shortfall))
|
||||
}
|
||||
|
||||
// Add a voucher whose value would exceed the channel balance
|
||||
vouch := &paych.SignedVoucher{ChannelAddr: channel, Amount: excessAmt, Lane: 4, Nonce: 1}
|
||||
vb, err := vouch.SigningBytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig, err := paymentCreator.WalletSign(ctx, createrAddr, vb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
vouch.Signature = sig
|
||||
_, err = paymentReceiver.PaychVoucherAdd(ctx, channel, vouch, nil, abi.NewTokenAmount(1000))
|
||||
if err == nil {
|
||||
t.Fatal(fmt.Errorf("Expected shortfall error of %d", excessAmt))
|
||||
}
|
||||
|
||||
// wait for the settlement period to pass before collecting
|
||||
waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych.SettleDelay)
|
||||
waitForBlocks(ctx, t, bm, paymentReceiver, receiverAddr, paych0.SettleDelay)
|
||||
|
||||
creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr)
|
||||
if err != nil {
|
||||
@@ -226,7 +284,7 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *BlockMiner, paymentRec
|
||||
|
||||
// Add a real block
|
||||
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.BurntFundsActorAddr,
|
||||
To: builtin0.BurntFundsActorAddr,
|
||||
From: receiverAddr,
|
||||
Value: types.NewInt(0),
|
||||
}, nil)
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
@@ -44,7 +45,7 @@ type StorageMiner struct {
|
||||
//
|
||||
// storage array defines storage nodes, numbers in the array specify full node
|
||||
// index the storage node 'belongs' to
|
||||
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner) ([]TestNode, []TestStorageNode)
|
||||
type APIBuilder func(t *testing.T, nFull int, storage []StorageMiner, opts ...node.Option) ([]TestNode, []TestStorageNode)
|
||||
type testSuite struct {
|
||||
makeNodes APIBuilder
|
||||
}
|
||||
|
||||
+47
-24
@@ -15,9 +15,11 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/mock"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
bminer "github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
@@ -114,8 +116,29 @@ func pledgeSectors(t *testing.T, ctx context.Context, miner TestStorageNode, n,
|
||||
}
|
||||
|
||||
func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
for _, height := range []abi.ChainEpoch{
|
||||
1, // before
|
||||
162, // while sealing
|
||||
5000, // while proving
|
||||
} {
|
||||
height := height // copy to satisfy lints
|
||||
t.Run(fmt.Sprintf("upgrade-%d", height), func(t *testing.T) {
|
||||
testWindowPostUpgrade(t, b, blocktime, nSectors, height)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
func testWindowPostUpgrade(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int,
|
||||
upgradeHeight abi.ChainEpoch) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n, sn := b(t, 1, OneMiner, node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}))
|
||||
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -129,17 +152,24 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
}
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
for ctx.Err() == nil {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, MineNext); err != nil {
|
||||
if ctx.Err() != nil {
|
||||
// context was canceled, ignore the error.
|
||||
return
|
||||
}
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
cancel()
|
||||
<-done
|
||||
}()
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||
|
||||
@@ -153,18 +183,16 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Running one proving period\n")
|
||||
fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2)
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 {
|
||||
if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 {
|
||||
fmt.Printf("Now head.Height = %d\n", head.Height())
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
@@ -186,7 +214,6 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
require.Greater(t, len(parts), 0)
|
||||
|
||||
secs := parts[0].AllSectors
|
||||
require.NoError(t, err)
|
||||
n, err := secs.Count()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), n)
|
||||
@@ -210,7 +237,6 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
require.Greater(t, len(parts), 0)
|
||||
|
||||
secs := parts[0].AllSectors
|
||||
require.NoError(t, err)
|
||||
n, err := secs.Count()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), n)
|
||||
@@ -236,18 +262,17 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Go through another PP, wait for sectors to become faulty\n")
|
||||
fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2)
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+(di.WPoStProvingPeriod)+2 {
|
||||
fmt.Printf("Now head.Height = %d\n", head.Height())
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
@@ -267,17 +292,17 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("End for head.Height > %d\n", di.PeriodStart+di.WPoStProvingPeriod+2)
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > di.PeriodStart+di.WPoStProvingPeriod+2 {
|
||||
fmt.Printf("Now head.Height = %d\n", head.Height())
|
||||
break
|
||||
}
|
||||
|
||||
if head.Height()%100 == 0 {
|
||||
fmt.Printf("@%d\n", head.Height())
|
||||
}
|
||||
build.Clock.Sleep(blocktime)
|
||||
}
|
||||
|
||||
@@ -294,18 +319,19 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
pledgeSectors(t, ctx, miner, 1, nSectors, nil)
|
||||
|
||||
{
|
||||
// wait a bit more
|
||||
|
||||
head, err := client.ChainHead(ctx)
|
||||
// Wait until proven.
|
||||
di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
waitUntil := head.Height() + 10
|
||||
waitUntil := di.PeriodStart + di.WPoStProvingPeriod + 2
|
||||
fmt.Printf("End for head.Height > %d\n", waitUntil)
|
||||
|
||||
for {
|
||||
head, err := client.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
if head.Height() > waitUntil {
|
||||
fmt.Printf("Now head.Height = %d\n", head.Height())
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -318,7 +344,4 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector
|
||||
|
||||
sectors = p.MinerPower.RawBytePower.Uint64() / uint64(ssz)
|
||||
require.Equal(t, nSectors+GenesisPreseals-2+1, int(sectors)) // -2 not recovered sectors + 1 just pledged
|
||||
|
||||
mine = false
|
||||
<-done
|
||||
}
|
||||
|
||||
@@ -4,3 +4,9 @@
|
||||
/dns4/bootstrap-4.testnet.fildev.network/tcp/1347/p2p/12D3KooWPkL9LrKRQgHtq7kn9ecNhGU9QaziG8R5tX8v9v7t3h34
|
||||
/dns4/bootstrap-3.testnet.fildev.network/tcp/1347/p2p/12D3KooWKYSsbpgZ3HAjax5M1BXCwXLa6gVkUARciz7uN3FNtr7T
|
||||
/dns4/bootstrap-5.testnet.fildev.network/tcp/1347/p2p/12D3KooWQYzqnLASJAabyMpPb1GcWZvNSe7JDcRuhdRqonFoiK9W
|
||||
/dns4/lotus-bootstrap.forceup.cn/tcp/41778/p2p/12D3KooWFQsv3nRMUevZNWWsY1Wu6NUzUbawnWU5NcRhgKuJA37C
|
||||
/dns4/bootstrap-0.starpool.in/tcp/12757/p2p/12D3KooWGHpBMeZbestVEWkfdnC9u7p6uFHXL1n7m1ZBqsEmiUzz
|
||||
/dns4/bootstrap-1.starpool.in/tcp/12757/p2p/12D3KooWQZrGH1PxSNZPum99M1zNvjNFM33d1AAu5DcvdHptuU7u
|
||||
/dns4/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt
|
||||
/dns4/bootstrap-0.ipfsmain.cn/tcp/34721/p2p/12D3KooWQnwEGNqcM2nAcPtRR9rAX8Hrg4k9kJLCHoTR5chJfz6d
|
||||
/dns4/bootstrap-1.ipfsmain.cn/tcp/34723/p2p/12D3KooWMKxMkD5DMpSWsW7dBddKxKT7L2GgbNuckz9otxvkvByP
|
||||
|
||||
+17
-8
@@ -3,28 +3,37 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
)
|
||||
|
||||
const UpgradeBreezeHeight = -1
|
||||
const BreezeGasTampingDuration = 0
|
||||
|
||||
const UpgradeSmokeHeight = -1
|
||||
const UpgradeIgnitionHeight = -2
|
||||
const UpgradeRefuelHeight = -3
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-4)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
func init() {
|
||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||
UpgradeActorsV2Height = math.MaxInt64
|
||||
UpgradeLiftoffHeight = 11
|
||||
}
|
||||
verifreg0.MinVerifiedDealSize = big.NewInt(256)
|
||||
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package build
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/protocol"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -39,8 +41,12 @@ func DhtProtocolName(netName dtypes.NetworkName) protocol.ID {
|
||||
|
||||
func UseNewestNetwork() bool {
|
||||
// TODO: Put these in a container we can iterate over
|
||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 {
|
||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 && UpgradeActorsV2Height <= 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func SetAddressNetwork(n address.Network) {
|
||||
address.CurrentNetwork = n
|
||||
}
|
||||
|
||||
+24
-12
@@ -4,12 +4,15 @@ package build
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
)
|
||||
|
||||
// /////
|
||||
@@ -22,8 +25,8 @@ const UnixfsLinksPerLevel = 1024
|
||||
// Consensus / Network
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version2
|
||||
const ActorUpgradeNetworkVersion = network.Version3
|
||||
const NewestNetworkVersion = network.Version4
|
||||
const ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
// Epochs
|
||||
const ForkLengthThreshold = Finality
|
||||
@@ -32,7 +35,7 @@ const ForkLengthThreshold = Finality
|
||||
var BlocksPerEpoch = uint64(builtin.ExpectedLeadersPerEpoch)
|
||||
|
||||
// Epochs
|
||||
const Finality = miner0.ChainFinality
|
||||
const Finality = policy.ChainFinality
|
||||
const MessageConfidence = uint64(5)
|
||||
|
||||
// constants for Weight calculation
|
||||
@@ -44,13 +47,8 @@ const WRatioDen = uint64(2)
|
||||
// Proofs
|
||||
|
||||
// Epochs
|
||||
const SealRandomnessLookback = Finality
|
||||
|
||||
// Epochs
|
||||
const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000 // TODO: Get from spec specs-actors
|
||||
|
||||
// Maximum lookback that randomness can be sourced from for a seal proof submission
|
||||
const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from specs-actors
|
||||
// TODO: unused
|
||||
const SealRandomnessLookback = policy.SealRandomnessLookback
|
||||
|
||||
// /////
|
||||
// Mining
|
||||
@@ -58,23 +56,37 @@ const MaxSealLookback = SealRandomnessLookbackLimit + 2000 // TODO: Get from spe
|
||||
// Epochs
|
||||
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
|
||||
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
// /////
|
||||
// Address
|
||||
|
||||
const AddressMainnetEnvVar = "_mainnet_"
|
||||
|
||||
// /////
|
||||
// Devnet settings
|
||||
|
||||
var Devnet = true
|
||||
|
||||
const FilBase = uint64(2_000_000_000)
|
||||
const FilAllocStorageMining = uint64(1_100_000_000)
|
||||
|
||||
const FilecoinPrecision = uint64(1_000_000_000_000_000_000)
|
||||
const FilReserved = uint64(300_000_000)
|
||||
|
||||
var InitialRewardBalance *big.Int
|
||||
var InitialFilReserved *big.Int
|
||||
|
||||
// TODO: Move other important consts here
|
||||
|
||||
func init() {
|
||||
InitialRewardBalance = big.NewInt(int64(FilAllocStorageMining))
|
||||
InitialRewardBalance = InitialRewardBalance.Mul(InitialRewardBalance, big.NewInt(int64(FilecoinPrecision)))
|
||||
|
||||
InitialFilReserved = big.NewInt(int64(FilReserved))
|
||||
InitialFilReserved = InitialFilReserved.Mul(InitialFilReserved, big.NewInt(int64(FilecoinPrecision)))
|
||||
|
||||
if os.Getenv("LOTUS_ADDRESS_TYPE") == AddressMainnetEnvVar {
|
||||
SetAddressNetwork(address.Mainnet)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync
|
||||
|
||||
+22
-10
@@ -13,7 +13,8 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,7 +33,7 @@ var (
|
||||
|
||||
AllowableClockDriftSecs = uint64(1)
|
||||
|
||||
Finality = miner0.ChainFinality
|
||||
Finality = policy.ChainFinality
|
||||
ForkLengthThreshold = Finality
|
||||
|
||||
SlashablePowerDelay = 20
|
||||
@@ -47,15 +48,13 @@ var (
|
||||
BlsSignatureCacheSize = 40000
|
||||
VerifSigCacheSize = 32000
|
||||
|
||||
SealRandomnessLookback = Finality
|
||||
SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
|
||||
MaxSealLookback = SealRandomnessLookbackLimit + 2000
|
||||
SealRandomnessLookback = policy.SealRandomnessLookback
|
||||
|
||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
|
||||
FilBase uint64 = 2_000_000_000
|
||||
FilAllocStorageMining uint64 = 1_400_000_000
|
||||
FilReserved uint64 = 300_000_000
|
||||
|
||||
FilecoinPrecision uint64 = 1_000_000_000_000_000_000
|
||||
|
||||
@@ -64,6 +63,13 @@ var (
|
||||
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||
return v
|
||||
}()
|
||||
|
||||
InitialFilReserved = func() *big.Int {
|
||||
v := big.NewInt(int64(FilReserved))
|
||||
v = v.Mul(v, big.NewInt(int64(FilecoinPrecision)))
|
||||
return v
|
||||
}()
|
||||
|
||||
// Actor consts
|
||||
// TODO: Pull from actors when its made not private
|
||||
MinDealDuration = abi.ChainEpoch(180 * builtin.EpochsInDay)
|
||||
@@ -74,12 +80,18 @@ var (
|
||||
UpgradeBreezeHeight abi.ChainEpoch = -1
|
||||
BreezeGasTampingDuration abi.ChainEpoch = 0
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -4
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
NewestNetworkVersion = network.Version2
|
||||
ActorUpgradeNetworkVersion = network.Version3
|
||||
NewestNetworkVersion = network.Version4
|
||||
ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
Devnet = true
|
||||
)
|
||||
|
||||
+32
-9
@@ -5,11 +5,14 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
@@ -22,14 +25,34 @@ const BreezeGasTampingDuration = 120
|
||||
|
||||
const UpgradeSmokeHeight = 51000
|
||||
|
||||
const UpgradeIgnitionHeight = 94000
|
||||
const UpgradeRefuelHeight = 130800
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||
|
||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||
// Miners, clients, developers, custodians all need time to prepare.
|
||||
// We still have upgrades and state changes to do, but can happen after signaling timing here.
|
||||
const UpgradeLiftoffHeight = 148888
|
||||
|
||||
func init() {
|
||||
power0.ConsensusMinerMinPower = big.NewInt(10 << 40)
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1: {},
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1: {},
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40))
|
||||
policy.SetSupportedProofTypes(
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||
)
|
||||
|
||||
if os.Getenv("LOTUS_USE_TEST_ADDRESSES") != "1" {
|
||||
SetAddressNetwork(address.Mainnet)
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||
UpgradeActorsV2Height = math.MaxInt64
|
||||
}
|
||||
|
||||
Devnet = false
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(builtin.EpochDurationSeconds)
|
||||
const BlockDelaySecs = uint64(builtin0.EpochDurationSeconds)
|
||||
|
||||
const PropagationDelaySecs = uint64(6)
|
||||
|
||||
+4
-4
@@ -29,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.7.1"
|
||||
const BuildVersion = "0.9.0"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -83,9 +83,9 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 15, 0)
|
||||
MinerAPIVersion = newVer(0, 14, 0)
|
||||
WorkerAPIVersion = newVer(0, 14, 0)
|
||||
FullAPIVersion = newVer(0, 16, 0)
|
||||
MinerAPIVersion = newVer(0, 15, 0)
|
||||
WorkerAPIVersion = newVer(0, 15, 0)
|
||||
)
|
||||
|
||||
//nolint:varcheck,deadcode
|
||||
|
||||
+26
-7
@@ -7,8 +7,11 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
type Map interface {
|
||||
@@ -21,18 +24,22 @@ type Map interface {
|
||||
ForEach(v cbor.Unmarshaler, fn func(key string) error) error
|
||||
}
|
||||
|
||||
func AsMap(store Store, root cid.Cid, version builtin.Version) (Map, error) {
|
||||
func AsMap(store Store, root cid.Cid, version actors.Version) (Map, error) {
|
||||
switch version {
|
||||
case builtin.Version0:
|
||||
case actors.Version0:
|
||||
return adt0.AsMap(store, root)
|
||||
case actors.Version2:
|
||||
return adt2.AsMap(store, root)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||
}
|
||||
|
||||
func NewMap(store Store, version builtin.Version) (Map, error) {
|
||||
func NewMap(store Store, version actors.Version) (Map, error) {
|
||||
switch version {
|
||||
case builtin.Version0:
|
||||
case actors.Version0:
|
||||
return adt0.MakeEmptyMap(store), nil
|
||||
case actors.Version2:
|
||||
return adt2.MakeEmptyMap(store), nil
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||
}
|
||||
@@ -49,9 +56,21 @@ type Array interface {
|
||||
}
|
||||
|
||||
func AsArray(store Store, root cid.Cid, version network.Version) (Array, error) {
|
||||
switch builtin.VersionForNetwork(version) {
|
||||
case builtin.Version0:
|
||||
switch actors.VersionForNetwork(version) {
|
||||
case actors.Version0:
|
||||
return adt0.AsArray(store, root)
|
||||
case actors.Version2:
|
||||
return adt2.AsArray(store, root)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||
}
|
||||
|
||||
func NewArray(store Store, version actors.Version) (Array, error) {
|
||||
switch version {
|
||||
case actors.Version0:
|
||||
return adt0.MakeEmptyArray(store), nil
|
||||
case actors.Version2:
|
||||
return adt2.MakeEmptyArray(store), nil
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown network version: %d", version)
|
||||
}
|
||||
|
||||
@@ -5,21 +5,31 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.AccountActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.AccountActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.AccountActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
@@ -2,14 +2,26 @@ package account
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
|
||||
account0 "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
account.State
|
||||
account0.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package account
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
account2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/account"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
account2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) PubkeyAddress() (address.Address, error) {
|
||||
return s.Address, nil
|
||||
}
|
||||
@@ -1,32 +1,100 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
)
|
||||
|
||||
type Version int
|
||||
|
||||
const (
|
||||
Version0 = iota
|
||||
)
|
||||
|
||||
// Converts a network version into a specs-actors version.
|
||||
func VersionForNetwork(version network.Version) Version {
|
||||
switch version {
|
||||
case network.Version0, network.Version1, network.Version2:
|
||||
return Version0
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||
}
|
||||
}
|
||||
var SystemActorAddr = builtin0.SystemActorAddr
|
||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||
var ReserveAddress = makeAddress("t090")
|
||||
var RootVerifierAddress = makeAddress("t080")
|
||||
|
||||
// TODO: Why does actors have 2 different versions of this?
|
||||
type SectorInfo = proof0.SectorInfo
|
||||
type PoStProof = proof0.PoStProof
|
||||
type FilterEstimate = smoothing0.FilterEstimate
|
||||
|
||||
func FromV0FilterEstimate(v0 smoothing0.FilterEstimate) FilterEstimate {
|
||||
return (FilterEstimate)(v0)
|
||||
}
|
||||
|
||||
// Doesn't change between actors v0 and v1
|
||||
func QAPowerForWeight(size abi.SectorSize, duration abi.ChainEpoch, dealWeight, verifiedWeight abi.DealWeight) abi.StoragePower {
|
||||
return miner0.QAPowerForWeight(size, duration, dealWeight, verifiedWeight)
|
||||
}
|
||||
|
||||
func FromV2FilterEstimate(v1 smoothing2.FilterEstimate) FilterEstimate {
|
||||
return (FilterEstimate)(v1)
|
||||
}
|
||||
|
||||
type ActorStateLoader func(store adt.Store, root cid.Cid) (cbor.Marshaler, error)
|
||||
|
||||
var ActorStateLoaders = make(map[cid.Cid]ActorStateLoader)
|
||||
|
||||
func RegisterActorState(code cid.Cid, loader ActorStateLoader) {
|
||||
ActorStateLoaders[code] = loader
|
||||
}
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (cbor.Marshaler, error) {
|
||||
loader, found := ActorStateLoaders[act.Code]
|
||||
if !found {
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
return loader(store, act.Head)
|
||||
}
|
||||
|
||||
func ActorNameByCode(c cid.Cid) string {
|
||||
switch {
|
||||
case builtin0.IsBuiltinActor(c):
|
||||
return builtin0.ActorNameByCode(c)
|
||||
case builtin2.IsBuiltinActor(c):
|
||||
return builtin2.ActorNameByCode(c)
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
func IsBuiltinActor(c cid.Cid) bool {
|
||||
return builtin0.IsBuiltinActor(c) || builtin2.IsBuiltinActor(c)
|
||||
}
|
||||
|
||||
func IsAccountActor(c cid.Cid) bool {
|
||||
return c == builtin0.AccountActorCodeID || c == builtin2.AccountActorCodeID
|
||||
}
|
||||
|
||||
func IsStorageMinerActor(c cid.Cid) bool {
|
||||
return c == builtin0.StorageMinerActorCodeID || c == builtin2.StorageMinerActorCodeID
|
||||
}
|
||||
|
||||
func IsMultisigActor(c cid.Cid) bool {
|
||||
return c == builtin0.MultisigActorCodeID || c == builtin2.MultisigActorCodeID
|
||||
|
||||
}
|
||||
|
||||
func IsPaymentChannelActor(c cid.Cid) bool {
|
||||
return c == builtin0.PaymentChannelActorCodeID || c == builtin2.PaymentChannelActorCodeID
|
||||
}
|
||||
|
||||
func makeAddress(addr string) address.Address {
|
||||
ret, err := address.NewFromString(addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -6,24 +6,34 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.InitActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
var Address = builtin0.InitActorAddr
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.InitActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.InitActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
@@ -36,4 +46,12 @@ type State interface {
|
||||
NetworkName() (dtypes.NetworkName, error)
|
||||
|
||||
ForEachActor(func(id abi.ActorID, address address.Address) error) error
|
||||
|
||||
// Remove exists to support tooling that manipulates state for testing.
|
||||
// It should not be used in production code, as init actor entries are
|
||||
// immutable.
|
||||
Remove(addrs ...address.Address) error
|
||||
|
||||
// Sets the network's name. This should only be used on upgrade/fork.
|
||||
SetNetworkName(name string) error
|
||||
}
|
||||
|
||||
@@ -3,20 +3,30 @@ package init
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
init_.State
|
||||
init0.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
@@ -46,3 +56,26 @@ func (s *state0) ForEachActor(cb func(id abi.ActorID, address address.Address) e
|
||||
func (s *state0) NetworkName() (dtypes.NetworkName, error) {
|
||||
return dtypes.NetworkName(s.State.NetworkName), nil
|
||||
}
|
||||
|
||||
func (s *state0) SetNetworkName(name string) error {
|
||||
s.State.NetworkName = name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *state0) Remove(addrs ...address.Address) (err error) {
|
||||
m, err := adt0.AsMap(s.store, s.State.AddressMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if err = m.Delete(abi.AddrKey(addr)); err != nil {
|
||||
return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err)
|
||||
}
|
||||
}
|
||||
amr, err := m.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get address map root: %w", err)
|
||||
}
|
||||
s.State.AddressMap = amr
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
init2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) ResolveAddress(address address.Address) (address.Address, bool, error) {
|
||||
return s.State.ResolveAddress(s.store, address)
|
||||
}
|
||||
|
||||
func (s *state2) MapAddressToNewID(address address.Address) (address.Address, error) {
|
||||
return s.State.MapAddressToNewID(s.store, address)
|
||||
}
|
||||
|
||||
func (s *state2) ForEachActor(cb func(id abi.ActorID, address address.Address) error) error {
|
||||
addrs, err := adt2.AsMap(s.store, s.State.AddressMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var actorID cbg.CborInt
|
||||
return addrs.ForEach(&actorID, func(key string) error {
|
||||
addr, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(abi.ActorID(actorID), addr)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *state2) NetworkName() (dtypes.NetworkName, error) {
|
||||
return dtypes.NetworkName(s.State.NetworkName), nil
|
||||
}
|
||||
|
||||
func (s *state2) SetNetworkName(name string) error {
|
||||
s.State.NetworkName = name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *state2) Remove(addrs ...address.Address) (err error) {
|
||||
m, err := adt2.AsMap(s.store, s.State.AddressMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if err = m.Delete(abi.AddrKey(addr)); err != nil {
|
||||
return xerrors.Errorf("failed to delete entry for address: %s; err: %w", addr, err)
|
||||
}
|
||||
}
|
||||
amr, err := m.Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get address map root: %w", err)
|
||||
}
|
||||
s.State.AddressMap = amr
|
||||
return nil
|
||||
}
|
||||
@@ -6,38 +6,48 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.StorageMarketActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
var Address = builtin0.StorageMarketActorAddr
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||
switch act.Code {
|
||||
case builtin0.StorageMarketActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.StorageMarketActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
type State interface {
|
||||
cbor.Marshaler
|
||||
BalancesChanged(State) bool
|
||||
BalancesChanged(State) (bool, error)
|
||||
EscrowTable() (BalanceTable, error)
|
||||
LockedTable() (BalanceTable, error)
|
||||
TotalLocked() (abi.TokenAmount, error)
|
||||
StatesChanged(State) bool
|
||||
StatesChanged(State) (bool, error)
|
||||
States() (DealStates, error)
|
||||
ProposalsChanged(State) bool
|
||||
ProposalsChanged(State) (bool, error)
|
||||
Proposals() (DealProposals, error)
|
||||
VerifyDealsForActivation(
|
||||
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
||||
@@ -50,6 +60,7 @@ type BalanceTable interface {
|
||||
}
|
||||
|
||||
type DealStates interface {
|
||||
ForEach(cb func(id abi.DealID, ds DealState) error) error
|
||||
Get(id abi.DealID) (*DealState, bool, error)
|
||||
|
||||
array() adt.Array
|
||||
@@ -64,6 +75,12 @@ type DealProposals interface {
|
||||
decode(*cbg.Deferred) (*DealProposal, error)
|
||||
}
|
||||
|
||||
type PublishStorageDealsParams = market0.PublishStorageDealsParams
|
||||
type PublishStorageDealsReturn = market0.PublishStorageDealsReturn
|
||||
type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams
|
||||
|
||||
type ClientDealProposal = market0.ClientDealProposal
|
||||
|
||||
type DealState struct {
|
||||
SectorStartEpoch abi.ChainEpoch // -1 if not yet included in proven sector
|
||||
LastUpdatedEpoch abi.ChainEpoch // -1 if deal state never updated
|
||||
|
||||
@@ -5,17 +5,29 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
market.State
|
||||
market0.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
@@ -25,24 +37,24 @@ func (s *state0) TotalLocked() (abi.TokenAmount, error) {
|
||||
return fml, nil
|
||||
}
|
||||
|
||||
func (s *state0) BalancesChanged(otherState State) bool {
|
||||
func (s *state0) BalancesChanged(otherState State) (bool, error) {
|
||||
otherState0, ok := otherState.(*state0)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.EscrowTable.Equals(otherState0.State.EscrowTable) || !s.State.LockedTable.Equals(otherState0.State.LockedTable)
|
||||
return !s.State.EscrowTable.Equals(otherState0.State.EscrowTable) || !s.State.LockedTable.Equals(otherState0.State.LockedTable), nil
|
||||
}
|
||||
|
||||
func (s *state0) StatesChanged(otherState State) bool {
|
||||
func (s *state0) StatesChanged(otherState State) (bool, error) {
|
||||
otherState0, ok := otherState.(*state0)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.States.Equals(otherState0.State.States)
|
||||
return !s.State.States.Equals(otherState0.State.States), nil
|
||||
}
|
||||
|
||||
func (s *state0) States() (DealStates, error) {
|
||||
@@ -53,14 +65,14 @@ func (s *state0) States() (DealStates, error) {
|
||||
return &dealStates0{stateArray}, nil
|
||||
}
|
||||
|
||||
func (s *state0) ProposalsChanged(otherState State) bool {
|
||||
func (s *state0) ProposalsChanged(otherState State) (bool, error) {
|
||||
otherState0, ok := otherState.(*state0)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.Proposals.Equals(otherState0.State.Proposals)
|
||||
return !s.State.Proposals.Equals(otherState0.State.Proposals), nil
|
||||
}
|
||||
|
||||
func (s *state0) Proposals() (DealProposals, error) {
|
||||
@@ -90,7 +102,7 @@ func (s *state0) LockedTable() (BalanceTable, error) {
|
||||
func (s *state0) VerifyDealsForActivation(
|
||||
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
||||
) (weight, verifiedWeight abi.DealWeight, err error) {
|
||||
return market.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
||||
return market0.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
||||
}
|
||||
|
||||
type balanceTable0 struct {
|
||||
@@ -114,7 +126,7 @@ type dealStates0 struct {
|
||||
}
|
||||
|
||||
func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) {
|
||||
var deal0 market.DealState
|
||||
var deal0 market0.DealState
|
||||
found, err := s.Array.Get(uint64(dealID), &deal0)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@@ -126,8 +138,15 @@ func (s *dealStates0) Get(dealID abi.DealID) (*DealState, bool, error) {
|
||||
return &deal, true, nil
|
||||
}
|
||||
|
||||
func (s *dealStates0) ForEach(cb func(dealID abi.DealID, ds DealState) error) error {
|
||||
var ds0 market0.DealState
|
||||
return s.Array.ForEach(&ds0, func(idx int64) error {
|
||||
return cb(abi.DealID(idx), fromV0DealState(ds0))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *dealStates0) decode(val *cbg.Deferred) (*DealState, error) {
|
||||
var ds0 market.DealState
|
||||
var ds0 market0.DealState
|
||||
if err := ds0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -139,7 +158,7 @@ func (s *dealStates0) array() adt.Array {
|
||||
return s.Array
|
||||
}
|
||||
|
||||
func fromV0DealState(v0 market.DealState) DealState {
|
||||
func fromV0DealState(v0 market0.DealState) DealState {
|
||||
return (DealState)(v0)
|
||||
}
|
||||
|
||||
@@ -148,7 +167,7 @@ type dealProposals0 struct {
|
||||
}
|
||||
|
||||
func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
||||
var proposal0 market.DealProposal
|
||||
var proposal0 market0.DealProposal
|
||||
found, err := s.Array.Get(uint64(dealID), &proposal0)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@@ -161,14 +180,14 @@ func (s *dealProposals0) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
||||
}
|
||||
|
||||
func (s *dealProposals0) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error {
|
||||
var dp0 market.DealProposal
|
||||
var dp0 market0.DealProposal
|
||||
return s.Array.ForEach(&dp0, func(idx int64) error {
|
||||
return cb(abi.DealID(idx), fromV0DealProposal(dp0))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *dealProposals0) decode(val *cbg.Deferred) (*DealProposal, error) {
|
||||
var dp0 market.DealProposal
|
||||
var dp0 market0.DealProposal
|
||||
if err := dp0.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -180,6 +199,6 @@ func (s *dealProposals0) array() adt.Array {
|
||||
return s.Array
|
||||
}
|
||||
|
||||
func fromV0DealProposal(v0 market.DealProposal) DealProposal {
|
||||
func fromV0DealProposal(v0 market0.DealProposal) DealProposal {
|
||||
return (DealProposal)(v0)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
market2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) TotalLocked() (abi.TokenAmount, error) {
|
||||
fml := types.BigAdd(s.TotalClientLockedCollateral, s.TotalProviderLockedCollateral)
|
||||
fml = types.BigAdd(fml, s.TotalClientStorageFee)
|
||||
return fml, nil
|
||||
}
|
||||
|
||||
func (s *state2) BalancesChanged(otherState State) (bool, error) {
|
||||
otherState2, ok := otherState.(*state2)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.EscrowTable.Equals(otherState2.State.EscrowTable) || !s.State.LockedTable.Equals(otherState2.State.LockedTable), nil
|
||||
}
|
||||
|
||||
func (s *state2) StatesChanged(otherState State) (bool, error) {
|
||||
otherState2, ok := otherState.(*state2)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.States.Equals(otherState2.State.States), nil
|
||||
}
|
||||
|
||||
func (s *state2) States() (DealStates, error) {
|
||||
stateArray, err := adt2.AsArray(s.store, s.State.States)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dealStates2{stateArray}, nil
|
||||
}
|
||||
|
||||
func (s *state2) ProposalsChanged(otherState State) (bool, error) {
|
||||
otherState2, ok := otherState.(*state2)
|
||||
if !ok {
|
||||
// there's no way to compare different versions of the state, so let's
|
||||
// just say that means the state of balances has changed
|
||||
return true, nil
|
||||
}
|
||||
return !s.State.Proposals.Equals(otherState2.State.Proposals), nil
|
||||
}
|
||||
|
||||
func (s *state2) Proposals() (DealProposals, error) {
|
||||
proposalArray, err := adt2.AsArray(s.store, s.State.Proposals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dealProposals2{proposalArray}, nil
|
||||
}
|
||||
|
||||
func (s *state2) EscrowTable() (BalanceTable, error) {
|
||||
bt, err := adt2.AsBalanceTable(s.store, s.State.EscrowTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &balanceTable2{bt}, nil
|
||||
}
|
||||
|
||||
func (s *state2) LockedTable() (BalanceTable, error) {
|
||||
bt, err := adt2.AsBalanceTable(s.store, s.State.LockedTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &balanceTable2{bt}, nil
|
||||
}
|
||||
|
||||
func (s *state2) VerifyDealsForActivation(
|
||||
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,
|
||||
) (weight, verifiedWeight abi.DealWeight, err error) {
|
||||
w, vw, _, err := market2.ValidateDealsForActivation(&s.State, s.store, deals, minerAddr, sectorExpiry, currEpoch)
|
||||
return w, vw, err
|
||||
}
|
||||
|
||||
type balanceTable2 struct {
|
||||
*adt2.BalanceTable
|
||||
}
|
||||
|
||||
func (bt *balanceTable2) ForEach(cb func(address.Address, abi.TokenAmount) error) error {
|
||||
asMap := (*adt2.Map)(bt.BalanceTable)
|
||||
var ta abi.TokenAmount
|
||||
return asMap.ForEach(&ta, func(key string) error {
|
||||
a, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, ta)
|
||||
})
|
||||
}
|
||||
|
||||
type dealStates2 struct {
|
||||
adt.Array
|
||||
}
|
||||
|
||||
func (s *dealStates2) Get(dealID abi.DealID) (*DealState, bool, error) {
|
||||
var deal2 market2.DealState
|
||||
found, err := s.Array.Get(uint64(dealID), &deal2)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if !found {
|
||||
return nil, false, nil
|
||||
}
|
||||
deal := fromV2DealState(deal2)
|
||||
return &deal, true, nil
|
||||
}
|
||||
|
||||
func (s *dealStates2) ForEach(cb func(dealID abi.DealID, ds DealState) error) error {
|
||||
var ds1 market2.DealState
|
||||
return s.Array.ForEach(&ds1, func(idx int64) error {
|
||||
return cb(abi.DealID(idx), fromV2DealState(ds1))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *dealStates2) decode(val *cbg.Deferred) (*DealState, error) {
|
||||
var ds1 market2.DealState
|
||||
if err := ds1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds := fromV2DealState(ds1)
|
||||
return &ds, nil
|
||||
}
|
||||
|
||||
func (s *dealStates2) array() adt.Array {
|
||||
return s.Array
|
||||
}
|
||||
|
||||
func fromV2DealState(v1 market2.DealState) DealState {
|
||||
return (DealState)(v1)
|
||||
}
|
||||
|
||||
type dealProposals2 struct {
|
||||
adt.Array
|
||||
}
|
||||
|
||||
func (s *dealProposals2) Get(dealID abi.DealID) (*DealProposal, bool, error) {
|
||||
var proposal2 market2.DealProposal
|
||||
found, err := s.Array.Get(uint64(dealID), &proposal2)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if !found {
|
||||
return nil, false, nil
|
||||
}
|
||||
proposal := fromV2DealProposal(proposal2)
|
||||
return &proposal, true, nil
|
||||
}
|
||||
|
||||
func (s *dealProposals2) ForEach(cb func(dealID abi.DealID, dp DealProposal) error) error {
|
||||
var dp1 market2.DealProposal
|
||||
return s.Array.ForEach(&dp1, func(idx int64) error {
|
||||
return cb(abi.DealID(idx), fromV2DealProposal(dp1))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *dealProposals2) decode(val *cbg.Deferred) (*DealProposal, error) {
|
||||
var dp1 market2.DealProposal
|
||||
if err := dp1.UnmarshalCBOR(bytes.NewReader(val.Raw)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dp := fromV2DealProposal(dp1)
|
||||
return &dp, nil
|
||||
}
|
||||
|
||||
func (s *dealProposals2) array() adt.Array {
|
||||
return s.Array
|
||||
}
|
||||
|
||||
func fromV2DealProposal(v1 market2.DealProposal) DealProposal {
|
||||
return (DealProposal)(v1)
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
|
||||
|
||||
package miner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
|
||||
var lengthBufSectorOnChainInfo = []byte{139}
|
||||
|
||||
func (t *SectorOnChainInfo) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufSectorOnChainInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.SectorNumber (abi.SectorNumber) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.SectorNumber)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.SealProof (abi.RegisteredSealProof) (int64)
|
||||
if t.SealProof >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.SealProof)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.SealProof-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.SealedCID (cid.Cid) (struct)
|
||||
|
||||
if err := cbg.WriteCidBuf(scratch, w, t.SealedCID); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.SealedCID: %w", err)
|
||||
}
|
||||
|
||||
// t.DealIDs ([]abi.DealID) (slice)
|
||||
if len(t.DealIDs) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.DealIDs was too long")
|
||||
}
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.DealIDs))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.DealIDs {
|
||||
if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, uint64(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Activation (abi.ChainEpoch) (int64)
|
||||
if t.Activation >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Activation)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Activation-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Expiration (abi.ChainEpoch) (int64)
|
||||
if t.Expiration >= 0 {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Expiration)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Expiration-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.DealWeight (big.Int) (struct)
|
||||
if err := t.DealWeight.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.VerifiedDealWeight (big.Int) (struct)
|
||||
if err := t.VerifiedDealWeight.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.InitialPledge (big.Int) (struct)
|
||||
if err := t.InitialPledge.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ExpectedDayReward (big.Int) (struct)
|
||||
if err := t.ExpectedDayReward.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ExpectedStoragePledge (big.Int) (struct)
|
||||
if err := t.ExpectedStoragePledge.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *SectorOnChainInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = SectorOnChainInfo{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 11 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.SectorNumber (abi.SectorNumber) (uint64)
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.SectorNumber = abi.SectorNumber(extra)
|
||||
|
||||
}
|
||||
// t.SealProof (abi.RegisteredSealProof) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.SealProof = abi.RegisteredSealProof(extraI)
|
||||
}
|
||||
// t.SealedCID (cid.Cid) (struct)
|
||||
|
||||
{
|
||||
|
||||
c, err := cbg.ReadCid(br)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.SealedCID: %w", err)
|
||||
}
|
||||
|
||||
t.SealedCID = c
|
||||
|
||||
}
|
||||
// t.DealIDs ([]abi.DealID) (slice)
|
||||
|
||||
maj, extra, err = cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.DealIDs: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.DealIDs = make([]abi.DealID, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
maj, val, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err)
|
||||
}
|
||||
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj)
|
||||
}
|
||||
|
||||
t.DealIDs[i] = abi.DealID(val)
|
||||
}
|
||||
|
||||
// t.Activation (abi.ChainEpoch) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.Activation = abi.ChainEpoch(extraI)
|
||||
}
|
||||
// t.Expiration (abi.ChainEpoch) (int64)
|
||||
{
|
||||
maj, extra, err := cbg.CborReadHeaderBuf(br, scratch)
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.Expiration = abi.ChainEpoch(extraI)
|
||||
}
|
||||
// t.DealWeight (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.DealWeight.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.DealWeight: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.VerifiedDealWeight (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.VerifiedDealWeight.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.VerifiedDealWeight: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.InitialPledge (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.InitialPledge.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.InitialPledge: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.ExpectedDayReward (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.ExpectedDayReward.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.ExpectedDayReward: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
// t.ExpectedStoragePledge (big.Int) (struct)
|
||||
|
||||
{
|
||||
|
||||
if err := t.ExpectedStoragePledge.UnmarshalCBOR(br); err != nil {
|
||||
return xerrors.Errorf("unmarshaling t.ExpectedStoragePledge: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
)
|
||||
|
||||
type DeadlinesDiff map[uint64]*DeadlineDiff
|
||||
|
||||
func DiffDeadlines(pre, cur State) (*DeadlinesDiff, error) {
|
||||
changed, err := pre.DeadlinesChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
numDl, err := pre.NumDeadlines()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dlDiff := make(DeadlinesDiff, numDl)
|
||||
if err := pre.ForEachDeadline(func(idx uint64, preDl Deadline) error {
|
||||
curDl, err := cur.LoadDeadline(idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
diff, err := DiffDeadline(preDl, curDl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dlDiff[idx] = diff
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dlDiff, nil
|
||||
}
|
||||
|
||||
type DeadlineDiff map[uint64]*PartitionDiff
|
||||
|
||||
func DiffDeadline(pre, cur Deadline) (*DeadlineDiff, error) {
|
||||
changed, err := pre.PartitionsChanged(cur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
partDiff := make(DeadlineDiff)
|
||||
if err := pre.ForEachPartition(func(idx uint64, prePart Partition) error {
|
||||
// try loading current partition at this index
|
||||
curPart, err := cur.LoadPartition(idx)
|
||||
if err != nil {
|
||||
if errors.Is(err, exitcode.ErrNotFound) {
|
||||
// TODO correctness?
|
||||
return nil // the partition was removed.
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// compare it with the previous partition
|
||||
diff, err := DiffPartition(prePart, curPart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
partDiff[idx] = diff
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// all previous partitions have been walked.
|
||||
// all partitions in cur and not in prev are new... can they be faulty already?
|
||||
// TODO is this correct?
|
||||
if err := cur.ForEachPartition(func(idx uint64, curPart Partition) error {
|
||||
if _, found := partDiff[idx]; found {
|
||||
return nil
|
||||
}
|
||||
faults, err := curPart.FaultySectors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
recovering, err := curPart.RecoveringSectors()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
partDiff[idx] = &PartitionDiff{
|
||||
Removed: bitfield.New(),
|
||||
Recovered: bitfield.New(),
|
||||
Faulted: faults,
|
||||
Recovering: recovering,
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &partDiff, nil
|
||||
}
|
||||
|
||||
type PartitionDiff struct {
|
||||
Removed bitfield.BitField
|
||||
Recovered bitfield.BitField
|
||||
Faulted bitfield.BitField
|
||||
Recovering bitfield.BitField
|
||||
}
|
||||
|
||||
func DiffPartition(pre, cur Partition) (*PartitionDiff, error) {
|
||||
prevLiveSectors, err := pre.LiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
curLiveSectors, err := cur.LiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
removed, err := bitfield.SubtractBitField(prevLiveSectors, curLiveSectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevRecoveries, err := pre.RecoveringSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
curRecoveries, err := cur.RecoveringSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recovering, err := bitfield.SubtractBitField(curRecoveries, prevRecoveries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevFaults, err := pre.FaultySectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
curFaults, err := cur.FaultySectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
faulted, err := bitfield.SubtractBitField(curFaults, prevFaults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// all current good sectors
|
||||
curActiveSectors, err := cur.ActiveSectors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// sectors that were previously fault and are now currently active are considered recovered.
|
||||
recovered, err := bitfield.IntersectBitField(prevFaults, curActiveSectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PartitionDiff{
|
||||
Removed: removed,
|
||||
Recovered: recovered,
|
||||
Faulted: faulted,
|
||||
Recovering: recovering,
|
||||
}, nil
|
||||
}
|
||||
@@ -11,24 +11,40 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/go-state-types/dline"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
)
|
||||
|
||||
var Address = builtin0.InitActorAddr
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.StorageMinerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
// Unchanged between v0 and v2 actors
|
||||
var WPoStProvingPeriod = miner0.WPoStProvingPeriod
|
||||
var WPoStPeriodDeadlines = miner0.WPoStPeriodDeadlines
|
||||
var WPoStChallengeWindow = miner0.WPoStChallengeWindow
|
||||
var WPoStChallengeLookback = miner0.WPoStChallengeLookback
|
||||
var FaultDeclarationCutoff = miner0.FaultDeclarationCutoff
|
||||
|
||||
const MinSectorExpiration = miner0.MinSectorExpiration
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||
switch act.Code {
|
||||
case builtin0.StorageMinerActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.StorageMinerActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
@@ -42,22 +58,24 @@ type State interface {
|
||||
VestedFunds(abi.ChainEpoch) (abi.TokenAmount, error)
|
||||
// Funds locked for various reasons.
|
||||
LockedFunds() (LockedFunds, error)
|
||||
FeeDebt() (abi.TokenAmount, error)
|
||||
|
||||
GetSector(abi.SectorNumber) (*SectorOnChainInfo, error)
|
||||
FindSector(abi.SectorNumber) (*SectorLocation, error)
|
||||
GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error)
|
||||
GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error)
|
||||
LoadSectors(sectorNos *bitfield.BitField) ([]*SectorOnChainInfo, error)
|
||||
NumLiveSectors() (uint64, error)
|
||||
IsAllocated(abi.SectorNumber) (bool, error)
|
||||
|
||||
LoadDeadline(idx uint64) (Deadline, error)
|
||||
ForEachDeadline(cb func(idx uint64, dl Deadline) error) error
|
||||
NumDeadlines() (uint64, error)
|
||||
DeadlinesChanged(State) bool
|
||||
DeadlinesChanged(State) (bool, error)
|
||||
|
||||
Info() (MinerInfo, error)
|
||||
|
||||
DeadlineInfo(epoch abi.ChainEpoch) *dline.Info
|
||||
DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error)
|
||||
|
||||
// Diff helpers. Used by Diff* functions internally.
|
||||
sectors() (adt.Array, error)
|
||||
@@ -71,7 +89,7 @@ type Deadline interface {
|
||||
ForEachPartition(cb func(idx uint64, part Partition) error) error
|
||||
PostSubmissions() (bitfield.BitField, error)
|
||||
|
||||
PartitionsChanged(Deadline) bool
|
||||
PartitionsChanged(Deadline) (bool, error)
|
||||
}
|
||||
|
||||
type Partition interface {
|
||||
@@ -127,6 +145,7 @@ type MinerInfo struct {
|
||||
SealProofType abi.RegisteredSealProof
|
||||
SectorSize abi.SectorSize
|
||||
WindowPoStPartitionSectors uint64
|
||||
ConsensusFaultElapsed abi.ChainEpoch
|
||||
}
|
||||
|
||||
type SectorExpiration struct {
|
||||
|
||||
@@ -4,21 +4,34 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"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/dline"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
miner0.State
|
||||
store adt.Store
|
||||
@@ -50,6 +63,10 @@ func (s *state0) LockedFunds() (LockedFunds, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state0) FeeDebt() (abi.TokenAmount, error) {
|
||||
return big.Zero(), nil
|
||||
}
|
||||
|
||||
func (s *state0) InitialPledge() (abi.TokenAmount, error) {
|
||||
return s.State.InitialPledgeRequirement, nil
|
||||
}
|
||||
@@ -79,11 +96,24 @@ func (s *state0) FindSector(num abi.SectorNumber) (*SectorLocation, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state0) NumLiveSectors() (uint64, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var total uint64
|
||||
if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner0.Deadline) error {
|
||||
total += dl.LiveSectors
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// GetSectorExpiration returns the effective expiration of the given sector.
|
||||
//
|
||||
// If the sector isn't found or has already been terminated, this method returns
|
||||
// nil and no error. If the sector does not expire early, the Early expiration
|
||||
// field is 0.
|
||||
// If the sector does not expire early, the Early expiration field is 0.
|
||||
func (s *state0) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
@@ -146,7 +176,7 @@ func (s *state0) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, e
|
||||
return nil, err
|
||||
}
|
||||
if out.Early == 0 && out.OnTime == 0 {
|
||||
return nil, nil
|
||||
return nil, xerrors.Errorf("failed to find sector %d", num)
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
@@ -171,9 +201,9 @@ func (s *state0) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, err
|
||||
if snos == nil {
|
||||
infos := make([]*SectorOnChainInfo, 0, sectors.Length())
|
||||
var info0 miner0.SectorOnChainInfo
|
||||
if err := sectors.ForEach(&info0, func(i int64) error {
|
||||
if err := sectors.ForEach(&info0, func(_ int64) error {
|
||||
info := fromV0SectorOnChainInfo(info0)
|
||||
infos[i] = &info
|
||||
infos = append(infos, &info)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -229,14 +259,14 @@ func (s *state0) NumDeadlines() (uint64, error) {
|
||||
return miner0.WPoStPeriodDeadlines, nil
|
||||
}
|
||||
|
||||
func (s *state0) DeadlinesChanged(other State) bool {
|
||||
func (s *state0) DeadlinesChanged(other State) (bool, error) {
|
||||
other0, ok := other.(*state0)
|
||||
if !ok {
|
||||
// treat an upgrade as a change, always
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return s.State.Deadlines.Equals(other0.Deadlines)
|
||||
return s.State.Deadlines.Equals(other0.Deadlines), nil
|
||||
}
|
||||
|
||||
func (s *state0) Info() (MinerInfo, error) {
|
||||
@@ -263,6 +293,7 @@ func (s *state0) Info() (MinerInfo, error) {
|
||||
SealProofType: info.SealProofType,
|
||||
SectorSize: info.SectorSize,
|
||||
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||
ConsensusFaultElapsed: -1,
|
||||
}
|
||||
|
||||
if info.PendingWorkerKey != nil {
|
||||
@@ -273,8 +304,8 @@ func (s *state0) Info() (MinerInfo, error) {
|
||||
return mi, nil
|
||||
}
|
||||
|
||||
func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) *dline.Info {
|
||||
return s.State.DeadlineInfo(epoch)
|
||||
func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) {
|
||||
return s.State.DeadlineInfo(epoch), nil
|
||||
}
|
||||
|
||||
func (s *state0) sectors() (adt.Array, error) {
|
||||
@@ -324,14 +355,14 @@ func (d *deadline0) ForEachPartition(cb func(uint64, Partition) error) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (d *deadline0) PartitionsChanged(other Deadline) bool {
|
||||
func (d *deadline0) PartitionsChanged(other Deadline) (bool, error) {
|
||||
other0, ok := other.(*deadline0)
|
||||
if !ok {
|
||||
// treat an upgrade as a change, always
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return d.Deadline.Partitions.Equals(other0.Deadline.Partitions)
|
||||
return d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
|
||||
}
|
||||
|
||||
func (d *deadline0) PostSubmissions() (bitfield.BitField, error) {
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"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/dline"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
miner2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
type deadline2 struct {
|
||||
miner2.Deadline
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
type partition2 struct {
|
||||
miner2.Partition
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return s.GetAvailableBalance(bal)
|
||||
}
|
||||
|
||||
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
return s.CheckVestedFunds(s.store, epoch)
|
||||
}
|
||||
|
||||
func (s *state2) LockedFunds() (LockedFunds, error) {
|
||||
return LockedFunds{
|
||||
VestingFunds: s.State.LockedFunds,
|
||||
InitialPledgeRequirement: s.State.InitialPledge,
|
||||
PreCommitDeposits: s.State.PreCommitDeposits,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state2) FeeDebt() (abi.TokenAmount, error) {
|
||||
return s.State.FeeDebt, nil
|
||||
}
|
||||
|
||||
func (s *state2) InitialPledge() (abi.TokenAmount, error) {
|
||||
return s.State.InitialPledge, nil
|
||||
}
|
||||
|
||||
func (s *state2) PreCommitDeposits() (abi.TokenAmount, error) {
|
||||
return s.State.PreCommitDeposits, nil
|
||||
}
|
||||
|
||||
func (s *state2) GetSector(num abi.SectorNumber) (*SectorOnChainInfo, error) {
|
||||
info, ok, err := s.State.GetSector(s.store, num)
|
||||
if !ok || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := fromV2SectorOnChainInfo(*info)
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (s *state2) FindSector(num abi.SectorNumber) (*SectorLocation, error) {
|
||||
dlIdx, partIdx, err := s.State.FindSector(s.store, num)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SectorLocation{
|
||||
Deadline: dlIdx,
|
||||
Partition: partIdx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state2) NumLiveSectors() (uint64, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var total uint64
|
||||
if err := dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error {
|
||||
total += dl.LiveSectors
|
||||
return nil
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// GetSectorExpiration returns the effective expiration of the given sector.
|
||||
//
|
||||
// If the sector does not expire early, the Early expiration field is 0.
|
||||
func (s *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// NOTE: this can be optimized significantly.
|
||||
// 1. If the sector is non-faulty, it will either expire on-time (can be
|
||||
// learned from the sector info), or in the next quantized expiration
|
||||
// epoch (i.e., the first element in the partition's expiration queue.
|
||||
// 2. If it's faulty, it will expire early within the first 14 entries
|
||||
// of the expiration queue.
|
||||
stopErr := errors.New("stop")
|
||||
out := SectorExpiration{}
|
||||
err = dls.ForEach(s.store, func(dlIdx uint64, dl *miner2.Deadline) error {
|
||||
partitions, err := dl.PartitionsArray(s.store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
quant := s.State.QuantSpecForDeadline(dlIdx)
|
||||
var part miner2.Partition
|
||||
return partitions.ForEach(&part, func(partIdx int64) error {
|
||||
if found, err := part.Sectors.IsSet(uint64(num)); err != nil {
|
||||
return err
|
||||
} else if !found {
|
||||
return nil
|
||||
}
|
||||
if found, err := part.Terminated.IsSet(uint64(num)); err != nil {
|
||||
return err
|
||||
} else if found {
|
||||
// already terminated
|
||||
return stopErr
|
||||
}
|
||||
|
||||
q, err := miner2.LoadExpirationQueue(s.store, part.ExpirationsEpochs, quant)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var exp miner2.ExpirationSet
|
||||
return q.ForEach(&exp, func(epoch int64) error {
|
||||
if early, err := exp.EarlySectors.IsSet(uint64(num)); err != nil {
|
||||
return err
|
||||
} else if early {
|
||||
out.Early = abi.ChainEpoch(epoch)
|
||||
return nil
|
||||
}
|
||||
if onTime, err := exp.OnTimeSectors.IsSet(uint64(num)); err != nil {
|
||||
return err
|
||||
} else if onTime {
|
||||
out.OnTime = abi.ChainEpoch(epoch)
|
||||
return stopErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
})
|
||||
if err == stopErr {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out.Early == 0 && out.OnTime == 0 {
|
||||
return nil, xerrors.Errorf("failed to find sector %d", num)
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func (s *state2) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) {
|
||||
info, ok, err := s.State.GetPrecommittedSector(s.store, num)
|
||||
if !ok || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := fromV2SectorPreCommitOnChainInfo(*info)
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (s *state2) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) {
|
||||
sectors, err := miner2.LoadSectors(s.store, s.State.Sectors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If no sector numbers are specified, load all.
|
||||
if snos == nil {
|
||||
infos := make([]*SectorOnChainInfo, 0, sectors.Length())
|
||||
var info2 miner2.SectorOnChainInfo
|
||||
if err := sectors.ForEach(&info2, func(_ int64) error {
|
||||
info := fromV2SectorOnChainInfo(info2)
|
||||
infos = append(infos, &info)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
||||
// Otherwise, load selected.
|
||||
infos2, err := sectors.Load(*snos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
infos := make([]*SectorOnChainInfo, len(infos2))
|
||||
for i, info2 := range infos2 {
|
||||
info := fromV2SectorOnChainInfo(*info2)
|
||||
infos[i] = &info
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
|
||||
func (s *state2) IsAllocated(num abi.SectorNumber) (bool, error) {
|
||||
var allocatedSectors bitfield.BitField
|
||||
if err := s.store.Get(s.store.Context(), s.State.AllocatedSectors, &allocatedSectors); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return allocatedSectors.IsSet(uint64(num))
|
||||
}
|
||||
|
||||
func (s *state2) LoadDeadline(idx uint64) (Deadline, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := dls.LoadDeadline(s.store, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &deadline2{*dl, s.store}, nil
|
||||
}
|
||||
|
||||
func (s *state2) ForEachDeadline(cb func(uint64, Deadline) error) error {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return dls.ForEach(s.store, func(i uint64, dl *miner2.Deadline) error {
|
||||
return cb(i, &deadline2{*dl, s.store})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *state2) NumDeadlines() (uint64, error) {
|
||||
return miner2.WPoStPeriodDeadlines, nil
|
||||
}
|
||||
|
||||
func (s *state2) DeadlinesChanged(other State) (bool, error) {
|
||||
other2, ok := other.(*state2)
|
||||
if !ok {
|
||||
// treat an upgrade as a change, always
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return s.State.Deadlines.Equals(other2.Deadlines), nil
|
||||
}
|
||||
|
||||
func (s *state2) Info() (MinerInfo, error) {
|
||||
info, err := s.State.GetInfo(s.store)
|
||||
if err != nil {
|
||||
return MinerInfo{}, err
|
||||
}
|
||||
|
||||
var pid *peer.ID
|
||||
if peerID, err := peer.IDFromBytes(info.PeerId); err == nil {
|
||||
pid = &peerID
|
||||
}
|
||||
|
||||
mi := MinerInfo{
|
||||
Owner: info.Owner,
|
||||
Worker: info.Worker,
|
||||
ControlAddresses: info.ControlAddresses,
|
||||
|
||||
NewWorker: address.Undef,
|
||||
WorkerChangeEpoch: -1,
|
||||
|
||||
PeerId: pid,
|
||||
Multiaddrs: info.Multiaddrs,
|
||||
SealProofType: info.SealProofType,
|
||||
SectorSize: info.SectorSize,
|
||||
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||
ConsensusFaultElapsed: info.ConsensusFaultElapsed,
|
||||
}
|
||||
|
||||
if info.PendingWorkerKey != nil {
|
||||
mi.NewWorker = info.PendingWorkerKey.NewWorker
|
||||
mi.WorkerChangeEpoch = info.PendingWorkerKey.EffectiveAt
|
||||
}
|
||||
|
||||
return mi, nil
|
||||
}
|
||||
|
||||
func (s *state2) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) {
|
||||
return s.State.DeadlineInfo(epoch), nil
|
||||
}
|
||||
|
||||
func (s *state2) sectors() (adt.Array, error) {
|
||||
return adt2.AsArray(s.store, s.Sectors)
|
||||
}
|
||||
|
||||
func (s *state2) decodeSectorOnChainInfo(val *cbg.Deferred) (SectorOnChainInfo, error) {
|
||||
var si miner2.SectorOnChainInfo
|
||||
err := si.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return SectorOnChainInfo{}, err
|
||||
}
|
||||
|
||||
return fromV2SectorOnChainInfo(si), nil
|
||||
}
|
||||
|
||||
func (s *state2) precommits() (adt.Map, error) {
|
||||
return adt2.AsMap(s.store, s.PreCommittedSectors)
|
||||
}
|
||||
|
||||
func (s *state2) decodeSectorPreCommitOnChainInfo(val *cbg.Deferred) (SectorPreCommitOnChainInfo, error) {
|
||||
var sp miner2.SectorPreCommitOnChainInfo
|
||||
err := sp.UnmarshalCBOR(bytes.NewReader(val.Raw))
|
||||
if err != nil {
|
||||
return SectorPreCommitOnChainInfo{}, err
|
||||
}
|
||||
|
||||
return fromV2SectorPreCommitOnChainInfo(sp), nil
|
||||
}
|
||||
|
||||
func (d *deadline2) LoadPartition(idx uint64) (Partition, error) {
|
||||
p, err := d.Deadline.LoadPartition(d.store, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &partition2{*p, d.store}, nil
|
||||
}
|
||||
|
||||
func (d *deadline2) ForEachPartition(cb func(uint64, Partition) error) error {
|
||||
ps, err := d.Deadline.PartitionsArray(d.store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var part miner2.Partition
|
||||
return ps.ForEach(&part, func(i int64) error {
|
||||
return cb(uint64(i), &partition2{part, d.store})
|
||||
})
|
||||
}
|
||||
|
||||
func (d *deadline2) PartitionsChanged(other Deadline) (bool, error) {
|
||||
other2, ok := other.(*deadline2)
|
||||
if !ok {
|
||||
// treat an upgrade as a change, always
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return d.Deadline.Partitions.Equals(other2.Deadline.Partitions), nil
|
||||
}
|
||||
|
||||
func (d *deadline2) PostSubmissions() (bitfield.BitField, error) {
|
||||
return d.Deadline.PostSubmissions, nil
|
||||
}
|
||||
|
||||
func (p *partition2) AllSectors() (bitfield.BitField, error) {
|
||||
return p.Partition.Sectors, nil
|
||||
}
|
||||
|
||||
func (p *partition2) FaultySectors() (bitfield.BitField, error) {
|
||||
return p.Partition.Faults, nil
|
||||
}
|
||||
|
||||
func (p *partition2) RecoveringSectors() (bitfield.BitField, error) {
|
||||
return p.Partition.Recoveries, nil
|
||||
}
|
||||
|
||||
func fromV2SectorOnChainInfo(v2 miner2.SectorOnChainInfo) SectorOnChainInfo {
|
||||
return SectorOnChainInfo{
|
||||
SectorNumber: v2.SectorNumber,
|
||||
SealProof: v2.SealProof,
|
||||
SealedCID: v2.SealedCID,
|
||||
DealIDs: v2.DealIDs,
|
||||
Activation: v2.Activation,
|
||||
Expiration: v2.Expiration,
|
||||
DealWeight: v2.DealWeight,
|
||||
VerifiedDealWeight: v2.VerifiedDealWeight,
|
||||
InitialPledge: v2.InitialPledge,
|
||||
ExpectedDayReward: v2.ExpectedDayReward,
|
||||
ExpectedStoragePledge: v2.ExpectedStoragePledge,
|
||||
}
|
||||
}
|
||||
|
||||
func fromV2SectorPreCommitOnChainInfo(v2 miner2.SectorPreCommitOnChainInfo) SectorPreCommitOnChainInfo {
|
||||
return SectorPreCommitOnChainInfo{
|
||||
Info: (SectorPreCommitInfo)(v2.Info),
|
||||
PreCommitDeposit: v2.PreCommitDeposit,
|
||||
PreCommitEpoch: v2.PreCommitEpoch,
|
||||
DealWeight: v2.DealWeight,
|
||||
VerifiedDealWeight: v2.VerifiedDealWeight,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package multisig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/minio/blake2b-simd"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func Message(version actors.Version, from address.Address) MessageBuilder {
|
||||
switch version {
|
||||
case actors.Version0:
|
||||
return message0{from}
|
||||
case actors.Version2:
|
||||
return message2{message0{from}}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported actors version: %d", version))
|
||||
}
|
||||
}
|
||||
|
||||
type MessageBuilder interface {
|
||||
// Create a new multisig with the specified parameters.
|
||||
Create(signers []address.Address, threshold uint64,
|
||||
vestingStart, vestingDuration abi.ChainEpoch,
|
||||
initialAmount abi.TokenAmount) (*types.Message, error)
|
||||
|
||||
// Propose a transaction to the given multisig.
|
||||
Propose(msig, target address.Address, amt abi.TokenAmount,
|
||||
method abi.MethodNum, params []byte) (*types.Message, error)
|
||||
|
||||
// Approve a multisig transaction. The "hash" is optional.
|
||||
Approve(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||
|
||||
// Cancel a multisig transaction. The "hash" is optional.
|
||||
Cancel(msig address.Address, txID uint64, hash *ProposalHashData) (*types.Message, error)
|
||||
}
|
||||
|
||||
// this type is the same between v0 and v2
|
||||
type ProposalHashData = multisig2.ProposalHashData
|
||||
|
||||
func txnParams(id uint64, data *ProposalHashData) ([]byte, error) {
|
||||
params := multisig2.TxnIDParams{ID: multisig2.TxnID(id)}
|
||||
if data != nil {
|
||||
if data.Requester.Protocol() != address.ID {
|
||||
return nil, xerrors.Errorf("proposer address must be an ID address, was %s", data.Requester)
|
||||
}
|
||||
if data.Value.Sign() == -1 {
|
||||
return nil, xerrors.Errorf("proposal value must be non-negative, was %s", data.Value)
|
||||
}
|
||||
if data.To == address.Undef {
|
||||
return nil, xerrors.Errorf("proposed destination address must be set")
|
||||
}
|
||||
pser, err := data.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash := blake2b.Sum256(pser)
|
||||
params.ProposalHash = hash[:]
|
||||
}
|
||||
|
||||
return actors.SerializeParams(¶ms)
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package multisig
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type message0 struct{ from address.Address }
|
||||
|
||||
func (m message0) Create(
|
||||
signers []address.Address, threshold uint64,
|
||||
unlockStart, unlockDuration abi.ChainEpoch,
|
||||
initialAmount abi.TokenAmount,
|
||||
) (*types.Message, error) {
|
||||
|
||||
lenAddrs := uint64(len(signers))
|
||||
|
||||
if lenAddrs < threshold {
|
||||
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||
}
|
||||
|
||||
if threshold == 0 {
|
||||
threshold = lenAddrs
|
||||
}
|
||||
|
||||
if m.from == address.Undef {
|
||||
return nil, xerrors.Errorf("must provide source address")
|
||||
}
|
||||
|
||||
if unlockStart != 0 {
|
||||
return nil, xerrors.Errorf("actors v0 does not support a non-zero vesting start time")
|
||||
}
|
||||
|
||||
// Set up constructor parameters for multisig
|
||||
msigParams := &multisig0.ConstructorParams{
|
||||
Signers: signers,
|
||||
NumApprovalsThreshold: threshold,
|
||||
UnlockDuration: unlockDuration,
|
||||
}
|
||||
|
||||
enc, actErr := actors.SerializeParams(msigParams)
|
||||
if actErr != nil {
|
||||
return nil, actErr
|
||||
}
|
||||
|
||||
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||
execParams := &init0.ExecParams{
|
||||
CodeCID: builtin0.MultisigActorCodeID,
|
||||
ConstructorParams: enc,
|
||||
}
|
||||
|
||||
enc, actErr = actors.SerializeParams(execParams)
|
||||
if actErr != nil {
|
||||
return nil, actErr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: init_.Address,
|
||||
From: m.from,
|
||||
Method: builtin0.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
Value: initialAmount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Propose(msig, to address.Address, amt abi.TokenAmount,
|
||||
method abi.MethodNum, params []byte) (*types.Message, error) {
|
||||
|
||||
if msig == address.Undef {
|
||||
return nil, xerrors.Errorf("must provide a multisig address for proposal")
|
||||
}
|
||||
|
||||
if to == address.Undef {
|
||||
return nil, xerrors.Errorf("must provide a target address for proposal")
|
||||
}
|
||||
|
||||
if amt.Sign() == -1 {
|
||||
return nil, xerrors.Errorf("must provide a non-negative amount for proposed send")
|
||||
}
|
||||
|
||||
if m.from == address.Undef {
|
||||
return nil, xerrors.Errorf("must provide source address")
|
||||
}
|
||||
|
||||
enc, actErr := actors.SerializeParams(&multisig0.ProposeParams{
|
||||
To: to,
|
||||
Value: amt,
|
||||
Method: method,
|
||||
Params: params,
|
||||
})
|
||||
if actErr != nil {
|
||||
return nil, xerrors.Errorf("failed to serialize parameters: %w", actErr)
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: msig,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin0.MethodsMultisig.Propose,
|
||||
Params: enc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Approve(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||
enc, err := txnParams(txID, hashData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: msig,
|
||||
From: m.from,
|
||||
Value: types.NewInt(0),
|
||||
Method: builtin0.MethodsMultisig.Approve,
|
||||
Params: enc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Cancel(msig address.Address, txID uint64, hashData *ProposalHashData) (*types.Message, error) {
|
||||
enc, err := txnParams(txID, hashData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: msig,
|
||||
From: m.from,
|
||||
Value: types.NewInt(0),
|
||||
Method: builtin0.MethodsMultisig.Cancel,
|
||||
Params: enc,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package multisig
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||
multisig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type message2 struct{ message0 }
|
||||
|
||||
func (m message2) Create(
|
||||
signers []address.Address, threshold uint64,
|
||||
unlockStart, unlockDuration abi.ChainEpoch,
|
||||
initialAmount abi.TokenAmount,
|
||||
) (*types.Message, error) {
|
||||
|
||||
lenAddrs := uint64(len(signers))
|
||||
|
||||
if lenAddrs < threshold {
|
||||
return nil, xerrors.Errorf("cannot require signing of more addresses than provided for multisig")
|
||||
}
|
||||
|
||||
if threshold == 0 {
|
||||
threshold = lenAddrs
|
||||
}
|
||||
|
||||
if m.from == address.Undef {
|
||||
return nil, xerrors.Errorf("must provide source address")
|
||||
}
|
||||
|
||||
// Set up constructor parameters for multisig
|
||||
msigParams := &multisig2.ConstructorParams{
|
||||
Signers: signers,
|
||||
NumApprovalsThreshold: threshold,
|
||||
UnlockDuration: unlockDuration,
|
||||
StartEpoch: unlockStart,
|
||||
}
|
||||
|
||||
enc, actErr := actors.SerializeParams(msigParams)
|
||||
if actErr != nil {
|
||||
return nil, actErr
|
||||
}
|
||||
|
||||
// new actors are created by invoking 'exec' on the init actor with the constructor params
|
||||
execParams := &init2.ExecParams{
|
||||
CodeCID: builtin2.MultisigActorCodeID,
|
||||
ConstructorParams: enc,
|
||||
}
|
||||
|
||||
enc, actErr = actors.SerializeParams(execParams)
|
||||
if actErr != nil {
|
||||
return nil, actErr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: init_.Address,
|
||||
From: m.from,
|
||||
Method: builtin2.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
Value: initialAmount,
|
||||
}, nil
|
||||
}
|
||||
+20
-11
@@ -6,23 +6,32 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.MultisigActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.MultisigActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.MultisigActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
@@ -31,11 +40,11 @@ type State interface {
|
||||
cbor.Marshaler
|
||||
|
||||
LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error)
|
||||
StartEpoch() abi.ChainEpoch
|
||||
UnlockDuration() abi.ChainEpoch
|
||||
InitialBalance() abi.TokenAmount
|
||||
Threshold() uint64
|
||||
Signers() []address.Address
|
||||
StartEpoch() (abi.ChainEpoch, error)
|
||||
UnlockDuration() (abi.ChainEpoch, error)
|
||||
InitialBalance() (abi.TokenAmount, error)
|
||||
Threshold() (uint64, error)
|
||||
Signers() ([]address.Address, error)
|
||||
|
||||
ForEachPendingTxn(func(id int64, txn Transaction) error) error
|
||||
}
|
||||
@@ -5,15 +5,26 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
msig0.State
|
||||
store adt.Store
|
||||
@@ -23,24 +34,24 @@ func (s *state0) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error
|
||||
return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil
|
||||
}
|
||||
|
||||
func (s *state0) StartEpoch() abi.ChainEpoch {
|
||||
return s.State.StartEpoch
|
||||
func (s *state0) StartEpoch() (abi.ChainEpoch, error) {
|
||||
return s.State.StartEpoch, nil
|
||||
}
|
||||
|
||||
func (s *state0) UnlockDuration() abi.ChainEpoch {
|
||||
return s.State.UnlockDuration
|
||||
func (s *state0) UnlockDuration() (abi.ChainEpoch, error) {
|
||||
return s.State.UnlockDuration, nil
|
||||
}
|
||||
|
||||
func (s *state0) InitialBalance() abi.TokenAmount {
|
||||
return s.State.InitialBalance
|
||||
func (s *state0) InitialBalance() (abi.TokenAmount, error) {
|
||||
return s.State.InitialBalance, nil
|
||||
}
|
||||
|
||||
func (s *state0) Threshold() uint64 {
|
||||
return s.State.NumApprovalsThreshold
|
||||
func (s *state0) Threshold() (uint64, error) {
|
||||
return s.State.NumApprovalsThreshold, nil
|
||||
}
|
||||
|
||||
func (s *state0) Signers() []address.Address {
|
||||
return s.State.Signers
|
||||
func (s *state0) Signers() ([]address.Address, error) {
|
||||
return s.State.Signers, nil
|
||||
}
|
||||
|
||||
func (s *state0) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error {
|
||||
@@ -0,0 +1,70 @@
|
||||
package multisig
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
msig2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/multisig"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
msig2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil
|
||||
}
|
||||
|
||||
func (s *state2) StartEpoch() (abi.ChainEpoch, error) {
|
||||
return s.State.StartEpoch, nil
|
||||
}
|
||||
|
||||
func (s *state2) UnlockDuration() (abi.ChainEpoch, error) {
|
||||
return s.State.UnlockDuration, nil
|
||||
}
|
||||
|
||||
func (s *state2) InitialBalance() (abi.TokenAmount, error) {
|
||||
return s.State.InitialBalance, nil
|
||||
}
|
||||
|
||||
func (s *state2) Threshold() (uint64, error) {
|
||||
return s.State.NumApprovalsThreshold, nil
|
||||
}
|
||||
|
||||
func (s *state2) Signers() ([]address.Address, error) {
|
||||
return s.State.Signers, nil
|
||||
}
|
||||
|
||||
func (s *state2) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error {
|
||||
arr, err := adt2.AsMap(s.store, s.State.PendingTxns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var out msig2.Transaction
|
||||
return arr.ForEach(&out, func(key string) error {
|
||||
txid, n := binary.Varint([]byte(key))
|
||||
if n <= 0 {
|
||||
return xerrors.Errorf("invalid pending transaction key: %v", key)
|
||||
}
|
||||
return cb(txid, (Transaction)(out))
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func Message(version actors.Version, from address.Address) MessageBuilder {
|
||||
switch version {
|
||||
case actors.Version0:
|
||||
return message0{from}
|
||||
case actors.Version2:
|
||||
return message2{from}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported actors version: %d", version))
|
||||
}
|
||||
}
|
||||
|
||||
type MessageBuilder interface {
|
||||
Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error)
|
||||
Update(paych address.Address, voucher *SignedVoucher, secret []byte) (*types.Message, error)
|
||||
Settle(paych address.Address) (*types.Message, error)
|
||||
Collect(paych address.Address) (*types.Message, error)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type message0 struct{ from address.Address }
|
||||
|
||||
func (m message0) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) {
|
||||
params, aerr := actors.SerializeParams(&paych0.ConstructorParams{From: m.from, To: to})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
enc, aerr := actors.SerializeParams(&init0.ExecParams{
|
||||
CodeCID: builtin0.PaymentChannelActorCodeID,
|
||||
ConstructorParams: params,
|
||||
})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: init_.Address,
|
||||
From: m.from,
|
||||
Value: initialAmount,
|
||||
Method: builtin0.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) {
|
||||
params, aerr := actors.SerializeParams(&paych0.UpdateChannelStateParams{
|
||||
Sv: *sv,
|
||||
Secret: secret,
|
||||
})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin0.MethodsPaych.UpdateChannelState,
|
||||
Params: params,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Settle(paych address.Address) (*types.Message, error) {
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin0.MethodsPaych.Settle,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message0) Collect(paych address.Address) (*types.Message, error) {
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin0.MethodsPaych.Collect,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
|
||||
paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type message2 struct{ from address.Address }
|
||||
|
||||
func (m message2) Create(to address.Address, initialAmount abi.TokenAmount) (*types.Message, error) {
|
||||
params, aerr := actors.SerializeParams(&paych2.ConstructorParams{From: m.from, To: to})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
enc, aerr := actors.SerializeParams(&init2.ExecParams{
|
||||
CodeCID: builtin2.PaymentChannelActorCodeID,
|
||||
ConstructorParams: params,
|
||||
})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: init_.Address,
|
||||
From: m.from,
|
||||
Value: initialAmount,
|
||||
Method: builtin2.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message2) Update(paych address.Address, sv *SignedVoucher, secret []byte) (*types.Message, error) {
|
||||
params, aerr := actors.SerializeParams(&paych2.UpdateChannelStateParams{
|
||||
Sv: *sv,
|
||||
Secret: secret,
|
||||
})
|
||||
if aerr != nil {
|
||||
return nil, aerr
|
||||
}
|
||||
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin2.MethodsPaych.UpdateChannelState,
|
||||
Params: params,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message2) Settle(paych address.Address) (*types.Message, error) {
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin2.MethodsPaych.Settle,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m message2) Collect(paych address.Address) (*types.Message, error) {
|
||||
return &types.Message{
|
||||
To: paych,
|
||||
From: m.from,
|
||||
Value: abi.NewTokenAmount(0),
|
||||
Method: builtin2.MethodsPaych.Collect,
|
||||
}, nil
|
||||
}
|
||||
@@ -27,10 +27,9 @@ type mockLaneState struct {
|
||||
func NewMockPayChState(from address.Address,
|
||||
to address.Address,
|
||||
settlingAt abi.ChainEpoch,
|
||||
toSend abi.TokenAmount,
|
||||
lanes map[uint64]paych.LaneState,
|
||||
) paych.State {
|
||||
return &mockState{from, to, settlingAt, toSend, lanes}
|
||||
return &mockState{from: from, to: to, settlingAt: settlingAt, toSend: big.NewInt(0), lanes: lanes}
|
||||
}
|
||||
|
||||
// NewMockLaneState constructs a state for a payment channel lane with the set fixed values
|
||||
@@ -45,23 +44,23 @@ func (ms *mockState) MarshalCBOR(io.Writer) error {
|
||||
}
|
||||
|
||||
// Channel owner, who has funded the actor
|
||||
func (ms *mockState) From() address.Address {
|
||||
return ms.from
|
||||
func (ms *mockState) From() (address.Address, error) {
|
||||
return ms.from, nil
|
||||
}
|
||||
|
||||
// Recipient of payouts from channel
|
||||
func (ms *mockState) To() address.Address {
|
||||
return ms.to
|
||||
func (ms *mockState) To() (address.Address, error) {
|
||||
return ms.to, nil
|
||||
}
|
||||
|
||||
// Height at which the channel can be `Collected`
|
||||
func (ms *mockState) SettlingAt() abi.ChainEpoch {
|
||||
return ms.settlingAt
|
||||
func (ms *mockState) SettlingAt() (abi.ChainEpoch, error) {
|
||||
return ms.settlingAt, nil
|
||||
}
|
||||
|
||||
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||
func (ms *mockState) ToSend() abi.TokenAmount {
|
||||
return ms.toSend
|
||||
func (ms *mockState) ToSend() (abi.TokenAmount, error) {
|
||||
return ms.toSend, nil
|
||||
}
|
||||
|
||||
// Get total number of lanes
|
||||
@@ -80,10 +79,10 @@ func (ms *mockState) ForEachLaneState(cb func(idx uint64, dl paych.LaneState) er
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (mls *mockLaneState) Redeemed() big.Int {
|
||||
return mls.redeemed
|
||||
func (mls *mockLaneState) Redeemed() (big.Int, error) {
|
||||
return mls.redeemed, nil
|
||||
}
|
||||
|
||||
func (mls *mockLaneState) Nonce() uint64 {
|
||||
return mls.nonce
|
||||
func (mls *mockLaneState) Nonce() (uint64, error) {
|
||||
return mls.nonce, nil
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
big "github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
// Load returns an abstract copy of payment channel state, irregardless of actor version
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.PaymentChannelActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
// State is an abstract version of payment channel state that works across
|
||||
// versions
|
||||
type State interface {
|
||||
cbor.Marshaler
|
||||
// Channel owner, who has funded the actor
|
||||
From() address.Address
|
||||
// Recipient of payouts from channel
|
||||
To() address.Address
|
||||
|
||||
// Height at which the channel can be `Collected`
|
||||
SettlingAt() abi.ChainEpoch
|
||||
|
||||
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||
ToSend() abi.TokenAmount
|
||||
|
||||
// Get total number of lanes
|
||||
LaneCount() (uint64, error)
|
||||
|
||||
// Iterate lane states
|
||||
ForEachLaneState(cb func(idx uint64, dl LaneState) error) error
|
||||
}
|
||||
|
||||
// LaneState is an abstract copy of the state of a single lane
|
||||
type LaneState interface {
|
||||
Redeemed() big.Int
|
||||
Nonce() uint64
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
big "github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/ipfs/go-cid"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.PaymentChannelActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
// Load returns an abstract copy of payment channel state, irregardless of actor version
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.PaymentChannelActorCodeID:
|
||||
return load0(store, act.Head)
|
||||
case builtin2.PaymentChannelActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
// State is an abstract version of payment channel state that works across
|
||||
// versions
|
||||
type State interface {
|
||||
cbor.Marshaler
|
||||
// Channel owner, who has funded the actor
|
||||
From() (address.Address, error)
|
||||
// Recipient of payouts from channel
|
||||
To() (address.Address, error)
|
||||
|
||||
// Height at which the channel can be `Collected`
|
||||
SettlingAt() (abi.ChainEpoch, error)
|
||||
|
||||
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||
ToSend() (abi.TokenAmount, error)
|
||||
|
||||
// Get total number of lanes
|
||||
LaneCount() (uint64, error)
|
||||
|
||||
// Iterate lane states
|
||||
ForEachLaneState(cb func(idx uint64, dl LaneState) error) error
|
||||
}
|
||||
|
||||
// LaneState is an abstract copy of the state of a single lane
|
||||
type LaneState interface {
|
||||
Redeemed() (big.Int, error)
|
||||
Nonce() (uint64, error)
|
||||
}
|
||||
|
||||
type SignedVoucher = paych0.SignedVoucher
|
||||
type ModVerifyParams = paych0.ModVerifyParams
|
||||
|
||||
// DecodeSignedVoucher decodes base64 encoded signed voucher.
|
||||
func DecodeSignedVoucher(s string) (*SignedVoucher, error) {
|
||||
data, err := base64.RawURLEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sv SignedVoucher
|
||||
if err := ipldcbor.DecodeInto(data, &sv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &sv, nil
|
||||
}
|
||||
@@ -1,40 +1,53 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
big "github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
|
||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
paych.State
|
||||
paych0.State
|
||||
store adt.Store
|
||||
lsAmt *adt0.Array
|
||||
}
|
||||
|
||||
// Channel owner, who has funded the actor
|
||||
func (s *state0) From() address.Address {
|
||||
return s.State.From
|
||||
func (s *state0) From() (address.Address, error) {
|
||||
return s.State.From, nil
|
||||
}
|
||||
|
||||
// Recipient of payouts from channel
|
||||
func (s *state0) To() address.Address {
|
||||
return s.State.To
|
||||
func (s *state0) To() (address.Address, error) {
|
||||
return s.State.To, nil
|
||||
}
|
||||
|
||||
// Height at which the channel can be `Collected`
|
||||
func (s *state0) SettlingAt() abi.ChainEpoch {
|
||||
return s.State.SettlingAt
|
||||
func (s *state0) SettlingAt() (abi.ChainEpoch, error) {
|
||||
return s.State.SettlingAt, nil
|
||||
}
|
||||
|
||||
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||
func (s *state0) ToSend() abi.TokenAmount {
|
||||
return s.State.ToSend
|
||||
func (s *state0) ToSend() (abi.TokenAmount, error) {
|
||||
return s.State.ToSend, nil
|
||||
}
|
||||
|
||||
func (s *state0) getOrLoadLsAmt() (*adt0.Array, error) {
|
||||
@@ -72,20 +85,20 @@ func (s *state0) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error
|
||||
// Note: we use a map instead of an array to store laneStates because the
|
||||
// client sets the lane ID (the index) and potentially they could use a
|
||||
// very large index.
|
||||
var ls paych.LaneState
|
||||
var ls paych0.LaneState
|
||||
return lsamt.ForEach(&ls, func(i int64) error {
|
||||
return cb(uint64(i), &laneState0{ls})
|
||||
})
|
||||
}
|
||||
|
||||
type laneState0 struct {
|
||||
paych.LaneState
|
||||
paych0.LaneState
|
||||
}
|
||||
|
||||
func (ls *laneState0) Redeemed() big.Int {
|
||||
return ls.LaneState.Redeemed
|
||||
func (ls *laneState0) Redeemed() (big.Int, error) {
|
||||
return ls.LaneState.Redeemed, nil
|
||||
}
|
||||
|
||||
func (ls *laneState0) Nonce() uint64 {
|
||||
return ls.LaneState.Nonce
|
||||
func (ls *laneState0) Nonce() (uint64, error) {
|
||||
return ls.LaneState.Nonce, nil
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package paych
|
||||
|
||||
import (
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
paych2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/paych"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
paych2.State
|
||||
store adt.Store
|
||||
lsAmt *adt2.Array
|
||||
}
|
||||
|
||||
// Channel owner, who has funded the actor
|
||||
func (s *state2) From() (address.Address, error) {
|
||||
return s.State.From, nil
|
||||
}
|
||||
|
||||
// Recipient of payouts from channel
|
||||
func (s *state2) To() (address.Address, error) {
|
||||
return s.State.To, nil
|
||||
}
|
||||
|
||||
// Height at which the channel can be `Collected`
|
||||
func (s *state2) SettlingAt() (abi.ChainEpoch, error) {
|
||||
return s.State.SettlingAt, nil
|
||||
}
|
||||
|
||||
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
|
||||
func (s *state2) ToSend() (abi.TokenAmount, error) {
|
||||
return s.State.ToSend, nil
|
||||
}
|
||||
|
||||
func (s *state2) getOrLoadLsAmt() (*adt2.Array, error) {
|
||||
if s.lsAmt != nil {
|
||||
return s.lsAmt, nil
|
||||
}
|
||||
|
||||
// Get the lane state from the chain
|
||||
lsamt, err := adt2.AsArray(s.store, s.State.LaneStates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.lsAmt = lsamt
|
||||
return lsamt, nil
|
||||
}
|
||||
|
||||
// Get total number of lanes
|
||||
func (s *state2) LaneCount() (uint64, error) {
|
||||
lsamt, err := s.getOrLoadLsAmt()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return lsamt.Length(), nil
|
||||
}
|
||||
|
||||
// Iterate lane states
|
||||
func (s *state2) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error {
|
||||
// Get the lane state from the chain
|
||||
lsamt, err := s.getOrLoadLsAmt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Note: we use a map instead of an array to store laneStates because the
|
||||
// client sets the lane ID (the index) and potentially they could use a
|
||||
// very large index.
|
||||
var ls paych2.LaneState
|
||||
return lsamt.ForEach(&ls, func(i int64) error {
|
||||
return cb(uint64(i), &laneState2{ls})
|
||||
})
|
||||
}
|
||||
|
||||
type laneState2 struct {
|
||||
paych2.LaneState
|
||||
}
|
||||
|
||||
func (ls *laneState2) Redeemed() (big.Int, error) {
|
||||
return ls.LaneState.Redeemed, nil
|
||||
}
|
||||
|
||||
func (ls *laneState2) Nonce() (uint64, error) {
|
||||
return ls.LaneState.Nonce, nil
|
||||
}
|
||||
@@ -2,28 +2,37 @@ package power
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.StoragePowerActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
var Address = builtin0.StoragePowerActorAddr
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||
switch act.Code {
|
||||
case builtin0.StoragePowerActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.StoragePowerActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
@@ -3,13 +3,26 @@ package power
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
power0.State
|
||||
store adt.Store
|
||||
@@ -35,7 +48,7 @@ func (s *state0) TotalCommitted() (Claim, error) {
|
||||
}
|
||||
|
||||
func (s *state0) MinerPower(addr address.Address) (Claim, bool, error) {
|
||||
claims, err := adt.AsMap(s.store, s.Claims)
|
||||
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return Claim{}, false, err
|
||||
}
|
||||
@@ -63,7 +76,7 @@ func (s *state0) MinerCounts() (uint64, uint64, error) {
|
||||
}
|
||||
|
||||
func (s *state0) ListAllMiners() ([]address.Address, error) {
|
||||
claims, err := adt.AsMap(s.store, s.Claims)
|
||||
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package power
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power"
|
||||
adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
power2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) TotalLocked() (abi.TokenAmount, error) {
|
||||
return s.TotalPledgeCollateral, nil
|
||||
}
|
||||
|
||||
func (s *state2) TotalPower() (Claim, error) {
|
||||
return Claim{
|
||||
RawBytePower: s.TotalRawBytePower,
|
||||
QualityAdjPower: s.TotalQualityAdjPower,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Committed power to the network. Includes miners below the minimum threshold.
|
||||
func (s *state2) TotalCommitted() (Claim, error) {
|
||||
return Claim{
|
||||
RawBytePower: s.TotalBytesCommitted,
|
||||
QualityAdjPower: s.TotalQABytesCommitted,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state2) MinerPower(addr address.Address) (Claim, bool, error) {
|
||||
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return Claim{}, false, err
|
||||
}
|
||||
var claim power2.Claim
|
||||
ok, err := claims.Get(abi.AddrKey(addr), &claim)
|
||||
if err != nil {
|
||||
return Claim{}, false, err
|
||||
}
|
||||
return Claim{
|
||||
RawBytePower: claim.RawBytePower,
|
||||
QualityAdjPower: claim.QualityAdjPower,
|
||||
}, ok, nil
|
||||
}
|
||||
|
||||
func (s *state2) MinerNominalPowerMeetsConsensusMinimum(a address.Address) (bool, error) {
|
||||
return s.State.MinerNominalPowerMeetsConsensusMinimum(s.store, a)
|
||||
}
|
||||
|
||||
func (s *state2) TotalPowerSmoothed() (builtin.FilterEstimate, error) {
|
||||
return builtin.FromV2FilterEstimate(s.State.ThisEpochQAPowerSmoothed), nil
|
||||
}
|
||||
|
||||
func (s *state2) MinerCounts() (uint64, uint64, error) {
|
||||
return uint64(s.State.MinerAboveMinPowerCount), uint64(s.State.MinerCount), nil
|
||||
}
|
||||
|
||||
func (s *state2) ListAllMiners() ([]address.Address, error) {
|
||||
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var miners []address.Address
|
||||
err = claims.ForEach(nil, func(k string) error {
|
||||
a, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
miners = append(miners, a)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return miners, nil
|
||||
}
|
||||
@@ -2,33 +2,42 @@ package reward
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.RewardActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
var Address = builtin0.RewardActorAddr
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (st State, err error) {
|
||||
switch act.Code {
|
||||
case builtin0.RewardActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.RewardActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
|
||||
type State interface {
|
||||
cbor.Er
|
||||
cbor.Marshaler
|
||||
|
||||
ThisEpochBaselinePower() (abi.StoragePower, error)
|
||||
ThisEpochReward() (abi.StoragePower, error)
|
||||
@@ -45,3 +54,5 @@ type State interface {
|
||||
InitialPledgeForPower(abi.StoragePower, abi.TokenAmount, *builtin.FilterEstimate, abi.TokenAmount) (abi.TokenAmount, error)
|
||||
PreCommitDepositForPower(builtin.FilterEstimate, abi.StoragePower) (abi.TokenAmount, error)
|
||||
}
|
||||
|
||||
type AwardBlockRewardParams = reward0.AwardBlockRewardParams
|
||||
|
||||
@@ -2,17 +2,29 @@ package reward
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
smoothing0 "github.com/filecoin-project/specs-actors/actors/util/smoothing"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
reward.State
|
||||
reward0.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
@@ -54,7 +66,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot
|
||||
s.State.ThisEpochBaselinePower,
|
||||
networkTotalPledge,
|
||||
s.State.ThisEpochRewardSmoothed,
|
||||
&smoothing.FilterEstimate{
|
||||
&smoothing0.FilterEstimate{
|
||||
PositionEstimate: networkQAPower.PositionEstimate,
|
||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||
},
|
||||
@@ -63,7 +75,7 @@ func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTot
|
||||
|
||||
func (s *state0) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) {
|
||||
return miner0.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed,
|
||||
&smoothing.FilterEstimate{
|
||||
&smoothing0.FilterEstimate{
|
||||
PositionEstimate: networkQAPower.PositionEstimate,
|
||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package reward
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
reward2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/reward"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
reward2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) ThisEpochReward() (abi.StoragePower, error) {
|
||||
return s.State.ThisEpochReward, nil
|
||||
}
|
||||
|
||||
func (s *state2) ThisEpochRewardSmoothed() (builtin.FilterEstimate, error) {
|
||||
return builtin.FilterEstimate{
|
||||
PositionEstimate: s.State.ThisEpochRewardSmoothed.PositionEstimate,
|
||||
VelocityEstimate: s.State.ThisEpochRewardSmoothed.VelocityEstimate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *state2) ThisEpochBaselinePower() (abi.StoragePower, error) {
|
||||
return s.State.ThisEpochBaselinePower, nil
|
||||
}
|
||||
|
||||
func (s *state2) TotalStoragePowerReward() (abi.TokenAmount, error) {
|
||||
return s.State.TotalStoragePowerReward, nil
|
||||
}
|
||||
|
||||
func (s *state2) EffectiveBaselinePower() (abi.StoragePower, error) {
|
||||
return s.State.EffectiveBaselinePower, nil
|
||||
}
|
||||
|
||||
func (s *state2) EffectiveNetworkTime() (abi.ChainEpoch, error) {
|
||||
return s.State.EffectiveNetworkTime, nil
|
||||
}
|
||||
|
||||
func (s *state2) CumsumBaseline() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
}
|
||||
|
||||
func (s *state2) CumsumRealized() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
}
|
||||
|
||||
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return miner2.InitialPledgeForPower(
|
||||
qaPower,
|
||||
s.State.ThisEpochBaselinePower,
|
||||
s.State.ThisEpochRewardSmoothed,
|
||||
smoothing2.FilterEstimate{
|
||||
PositionEstimate: networkQAPower.PositionEstimate,
|
||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||
},
|
||||
circSupply,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (s *state2) PreCommitDepositForPower(networkQAPower builtin.FilterEstimate, sectorWeight abi.StoragePower) (abi.TokenAmount, error) {
|
||||
return miner2.PreCommitDepositForPower(s.State.ThisEpochRewardSmoothed,
|
||||
smoothing2.FilterEstimate{
|
||||
PositionEstimate: networkQAPower.PositionEstimate,
|
||||
VelocityEstimate: networkQAPower.VelocityEstimate,
|
||||
},
|
||||
sectorWeight), nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package verifreg
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func getDataCap(store adt.Store, ver actors.Version, root cid.Cid, addr address.Address) (bool, abi.StoragePower, error) {
|
||||
if addr.Protocol() != address.ID {
|
||||
return false, big.Zero(), xerrors.Errorf("can only look up ID addresses")
|
||||
}
|
||||
|
||||
vh, err := adt.AsMap(store, root, ver)
|
||||
if err != nil {
|
||||
return false, big.Zero(), xerrors.Errorf("loading verifreg: %w", err)
|
||||
}
|
||||
|
||||
var dcap abi.StoragePower
|
||||
if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil {
|
||||
return false, big.Zero(), xerrors.Errorf("looking up addr: %w", err)
|
||||
} else if !found {
|
||||
return false, big.Zero(), nil
|
||||
}
|
||||
|
||||
return true, dcap, nil
|
||||
}
|
||||
|
||||
func forEachCap(store adt.Store, ver actors.Version, root cid.Cid, cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||
vh, err := adt.AsMap(store, root, ver)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading verified clients: %w", err)
|
||||
}
|
||||
var dcap abi.StoragePower
|
||||
return vh.ForEach(&dcap, func(key string) error {
|
||||
a, err := address.NewFromBytes([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, dcap)
|
||||
})
|
||||
}
|
||||
@@ -3,37 +3,46 @@ package verifreg
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"golang.org/x/xerrors"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
var _ State = (*state0)(nil)
|
||||
|
||||
func load0(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state0 struct {
|
||||
verifreg0.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state0) RootKey() (address.Address, error) {
|
||||
return s.State.RootKey, nil
|
||||
}
|
||||
|
||||
func (s *state0) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||
if addr.Protocol() != address.ID {
|
||||
return false, big.Zero(), xerrors.Errorf("can only look up ID addresses")
|
||||
}
|
||||
return getDataCap(s.store, actors.Version0, s.State.VerifiedClients, addr)
|
||||
}
|
||||
|
||||
vh, err := adt0.AsMap(s.store, s.VerifiedClients)
|
||||
if err != nil {
|
||||
return false, big.Zero(), xerrors.Errorf("loading verified clients: %w", err)
|
||||
}
|
||||
func (s *state0) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||
return getDataCap(s.store, actors.Version0, s.State.Verifiers, addr)
|
||||
}
|
||||
|
||||
var dcap abi.StoragePower
|
||||
if found, err := vh.Get(abi.AddrKey(addr), &dcap); err != nil {
|
||||
return false, big.Zero(), xerrors.Errorf("looking up verified clients: %w", err)
|
||||
} else if !found {
|
||||
return false, big.Zero(), nil
|
||||
}
|
||||
func (s *state0) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||
return forEachCap(s.store, actors.Version0, s.State.Verifiers, cb)
|
||||
}
|
||||
|
||||
return true, dcap, nil
|
||||
func (s *state0) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||
return forEachCap(s.store, actors.Version0, s.State.VerifiedClients, cb)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package verifreg
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
|
||||
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
var _ State = (*state2)(nil)
|
||||
|
||||
func load2(store adt.Store, root cid.Cid) (State, error) {
|
||||
out := state2{store: store}
|
||||
err := store.Get(store.Context(), root, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
type state2 struct {
|
||||
verifreg2.State
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) RootKey() (address.Address, error) {
|
||||
return s.State.RootKey, nil
|
||||
}
|
||||
|
||||
func (s *state2) VerifiedClientDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||
return getDataCap(s.store, actors.Version2, s.State.VerifiedClients, addr)
|
||||
}
|
||||
|
||||
func (s *state2) VerifierDataCap(addr address.Address) (bool, abi.StoragePower, error) {
|
||||
return getDataCap(s.store, actors.Version2, s.State.Verifiers, addr)
|
||||
}
|
||||
|
||||
func (s *state2) ForEachVerifier(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||
return forEachCap(s.store, actors.Version2, s.State.Verifiers, cb)
|
||||
}
|
||||
|
||||
func (s *state2) ForEachClient(cb func(addr address.Address, dcap abi.StoragePower) error) error {
|
||||
return forEachCap(s.store, actors.Version2, s.State.VerifiedClients, cb)
|
||||
}
|
||||
@@ -3,26 +3,35 @@ package verifreg
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builtin.RegisterActorState(builtin0.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load0(store, root)
|
||||
})
|
||||
builtin.RegisterActorState(builtin2.VerifiedRegistryActorCodeID, func(store adt.Store, root cid.Cid) (cbor.Marshaler, error) {
|
||||
return load2(store, root)
|
||||
})
|
||||
}
|
||||
|
||||
var Address = builtin0.VerifiedRegistryActorAddr
|
||||
|
||||
func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
switch act.Code {
|
||||
case builtin0.VerifiedRegistryActorCodeID:
|
||||
out := state0{store: store}
|
||||
err := store.Get(store.Context(), act.Head, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
return load0(store, act.Head)
|
||||
case builtin2.VerifiedRegistryActorCodeID:
|
||||
return load2(store, act.Head)
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
|
||||
}
|
||||
@@ -30,5 +39,9 @@ func Load(store adt.Store, act *types.Actor) (State, error) {
|
||||
type State interface {
|
||||
cbor.Marshaler
|
||||
|
||||
RootKey() (address.Address, error)
|
||||
VerifiedClientDataCap(address.Address) (bool, abi.StoragePower, error)
|
||||
VerifierDataCap(address.Address) (bool, abi.StoragePower, error)
|
||||
ForEachVerifier(func(addr address.Address, dcap abi.StoragePower) error) error
|
||||
ForEachClient(func(addr address.Address, dcap abi.StoragePower) error) error
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
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"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
const (
|
||||
ChainFinality = miner0.ChainFinality
|
||||
SealRandomnessLookback = ChainFinality
|
||||
)
|
||||
|
||||
// SetSupportedProofTypes sets supported proof types, across all actor versions.
|
||||
// This should only be used for testing.
|
||||
func SetSupportedProofTypes(types ...abi.RegisteredSealProof) {
|
||||
newTypes := make(map[abi.RegisteredSealProof]struct{}, len(types))
|
||||
for _, t := range types {
|
||||
newTypes[t] = struct{}{}
|
||||
}
|
||||
// Set for all miner versions.
|
||||
miner0.SupportedProofTypes = newTypes
|
||||
miner2.SupportedProofTypes = newTypes
|
||||
}
|
||||
|
||||
// AddSupportedProofTypes sets supported proof types, across all actor versions.
|
||||
// This should only be used for testing.
|
||||
func AddSupportedProofTypes(types ...abi.RegisteredSealProof) {
|
||||
for _, t := range types {
|
||||
// Set for all miner versions.
|
||||
miner0.SupportedProofTypes[t] = struct{}{}
|
||||
miner2.SupportedProofTypes[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// SetPreCommitChallengeDelay sets the pre-commit challenge delay across all
|
||||
// actors versions. Use for testing.
|
||||
func SetPreCommitChallengeDelay(delay abi.ChainEpoch) {
|
||||
// Set for all miner versions.
|
||||
miner0.PreCommitChallengeDelay = delay
|
||||
miner2.PreCommitChallengeDelay = delay
|
||||
}
|
||||
|
||||
// TODO: this function shouldn't really exist. Instead, the API should expose the precommit delay.
|
||||
func GetPreCommitChallengeDelay() abi.ChainEpoch {
|
||||
return miner0.PreCommitChallengeDelay
|
||||
}
|
||||
|
||||
// SetConsensusMinerMinPower sets the minimum power of an individual miner must
|
||||
// meet for leader election, across all actor versions. This should only be used
|
||||
// for testing.
|
||||
func SetConsensusMinerMinPower(p abi.StoragePower) {
|
||||
power0.ConsensusMinerMinPower = p
|
||||
for _, policy := range builtin2.SealProofPolicies {
|
||||
policy.ConsensusMinerMinPower = p
|
||||
}
|
||||
}
|
||||
|
||||
// SetMinVerifiedDealSize sets the minimum size of a verified deal. This should
|
||||
// only be used for testing.
|
||||
func SetMinVerifiedDealSize(size abi.StoragePower) {
|
||||
verifreg0.MinVerifiedDealSize = size
|
||||
verifreg2.MinVerifiedDealSize = size
|
||||
}
|
||||
|
||||
func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) abi.ChainEpoch {
|
||||
switch ver {
|
||||
case actors.Version0:
|
||||
return miner0.MaxSealDuration[t]
|
||||
case actors.Version2:
|
||||
return miner2.MaxProveCommitDuration[t]
|
||||
default:
|
||||
panic("unsupported actors version")
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
case actors.Version0:
|
||||
return market0.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil, nwVer)
|
||||
case actors.Version2:
|
||||
return market2.DealProviderCollateralBounds(size, verified, rawBytePower, qaPower, baselinePower, circulatingFil)
|
||||
default:
|
||||
panic("unsupported network version")
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the challenge window and scales the proving period to match (such that
|
||||
// there are always 48 challenge windows in a proving period).
|
||||
func SetWPoStChallengeWindow(period abi.ChainEpoch) {
|
||||
miner0.WPoStChallengeWindow = period
|
||||
miner0.WPoStProvingPeriod = period * abi.ChainEpoch(miner0.WPoStPeriodDeadlines)
|
||||
|
||||
miner2.WPoStChallengeWindow = period
|
||||
miner2.WPoStProvingPeriod = period * abi.ChainEpoch(miner2.WPoStPeriodDeadlines)
|
||||
}
|
||||
|
||||
func GetWinningPoStSectorSetLookback(nwVer network.Version) abi.ChainEpoch {
|
||||
if nwVer <= network.Version3 {
|
||||
return 10
|
||||
}
|
||||
|
||||
return ChainFinality
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
|
||||
verifreg2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/verifreg"
|
||||
)
|
||||
|
||||
func TestSupportedProofTypes(t *testing.T) {
|
||||
var oldTypes []abi.RegisteredSealProof
|
||||
for t := range miner0.SupportedProofTypes {
|
||||
oldTypes = append(oldTypes, t)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
SetSupportedProofTypes(oldTypes...)
|
||||
})
|
||||
|
||||
SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
require.EqualValues(t,
|
||||
miner0.SupportedProofTypes,
|
||||
map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
},
|
||||
)
|
||||
AddSupportedProofTypes(abi.RegisteredSealProof_StackedDrg8MiBV1)
|
||||
require.EqualValues(t,
|
||||
miner0.SupportedProofTypes,
|
||||
map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
abi.RegisteredSealProof_StackedDrg8MiBV1: {},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Tests assumptions about policies being the same between actor versions.
|
||||
func TestAssumptions(t *testing.T) {
|
||||
require.EqualValues(t, miner0.SupportedProofTypes, miner2.SupportedProofTypes)
|
||||
require.Equal(t, miner0.PreCommitChallengeDelay, miner2.PreCommitChallengeDelay)
|
||||
require.Equal(t, miner0.ChainFinality, miner2.ChainFinality)
|
||||
require.Equal(t, miner0.WPoStChallengeWindow, miner2.WPoStChallengeWindow)
|
||||
require.Equal(t, miner0.WPoStProvingPeriod, miner2.WPoStProvingPeriod)
|
||||
require.Equal(t, miner0.WPoStPeriodDeadlines, miner2.WPoStPeriodDeadlines)
|
||||
require.True(t, verifreg0.MinVerifiedDealSize.Equals(verifreg2.MinVerifiedDealSize))
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package actors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
)
|
||||
|
||||
type Version int
|
||||
|
||||
const (
|
||||
Version0 Version = 0
|
||||
Version2 Version = 2
|
||||
)
|
||||
|
||||
// Converts a network version into an actors adt version.
|
||||
func VersionForNetwork(version network.Version) Version {
|
||||
switch version {
|
||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||
return Version0
|
||||
case network.Version4:
|
||||
return Version2
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,12 @@ type DiffBalanceTablesFunc func(ctx context.Context, oldBalanceTable, newBalance
|
||||
// OnBalanceChanged runs when the escrow table for available balances changes
|
||||
func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
|
||||
if !oldState.BalancesChanged(newState) {
|
||||
bc, err := oldState.BalancesChanged(newState)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if !bc {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
@@ -132,7 +137,12 @@ type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateR
|
||||
// OnDealStateChanged calls diffDealStates when the market deal state changes
|
||||
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
|
||||
if !oldState.StatesChanged(newState) {
|
||||
sc, err := oldState.StatesChanged(newState)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if !sc {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
@@ -152,7 +162,12 @@ func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc)
|
||||
// OnDealProposalChanged calls diffDealProps when the market proposal state changes
|
||||
func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffDealProposalsFunc) DiffStorageMarketStateFunc {
|
||||
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
|
||||
if !oldState.ProposalsChanged(newState) {
|
||||
pc, err := oldState.ProposalsChanged(newState)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if !pc {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
@@ -303,7 +318,7 @@ func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorSta
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return diffInitActorState(ctx, &oldState, &newState)
|
||||
return diffInitActorState(ctx, oldState, newState)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -379,12 +394,22 @@ type PayChToSendChange struct {
|
||||
// OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel
|
||||
func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc {
|
||||
return func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error) {
|
||||
if oldState.ToSend().Equals(newState.ToSend()) {
|
||||
ots, err := oldState.ToSend()
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
nts, err := newState.ToSend()
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
if ots.Equals(nts) {
|
||||
return false, nil, nil
|
||||
}
|
||||
return true, &PayChToSendChange{
|
||||
OldToSend: oldState.ToSend(),
|
||||
NewToSend: newState.ToSend(),
|
||||
OldToSend: ots,
|
||||
NewToSend: nts,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@@ -405,7 +430,7 @@ type AddressChange struct {
|
||||
To AddressPair
|
||||
}
|
||||
|
||||
type DiffInitActorStateFunc func(ctx context.Context, oldState *init_.State, newState *init_.State) (changed bool, user UserData, err error)
|
||||
type DiffInitActorStateFunc func(ctx context.Context, oldState init_.State, newState init_.State) (changed bool, user UserData, err error)
|
||||
|
||||
func (i *InitActorAddressChanges) AsKey(key string) (abi.Keyer, error) {
|
||||
addr, err := address.NewFromBytes([]byte(key))
|
||||
@@ -493,33 +518,73 @@ func (i *InitActorAddressChanges) Remove(key string, val *typegen.Deferred) erro
|
||||
}
|
||||
|
||||
func (sp *StatePredicates) OnAddressMapChange() DiffInitActorStateFunc {
|
||||
return func(ctx context.Context, oldState, newState *init_.State) (changed bool, user UserData, err error) {
|
||||
/*ctxStore := &contextStore{
|
||||
ctx: ctx,
|
||||
cst: sp.cst,
|
||||
}
|
||||
|
||||
return func(ctx context.Context, oldState, newState init_.State) (changed bool, user UserData, err error) {
|
||||
addressChanges := &InitActorAddressChanges{
|
||||
Added: []AddressPair{},
|
||||
Modified: []AddressChange{},
|
||||
Removed: []AddressPair{},
|
||||
}
|
||||
|
||||
if oldState.AddressMap.Equals(newState.AddressMap) {
|
||||
return false, nil, nil
|
||||
}
|
||||
err = oldState.ForEachActor(func(oldId abi.ActorID, oldAddress address.Address) error {
|
||||
oldIdAddress, err := address.NewIDAddress(uint64(oldId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newIdAddress, found, err := newState.ResolveAddress(oldAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !found {
|
||||
addressChanges.Removed = append(addressChanges.Removed, AddressPair{
|
||||
ID: oldIdAddress,
|
||||
PK: oldAddress,
|
||||
})
|
||||
}
|
||||
|
||||
if oldIdAddress != newIdAddress {
|
||||
addressChanges.Modified = append(addressChanges.Modified, AddressChange{
|
||||
From: AddressPair{
|
||||
ID: oldIdAddress,
|
||||
PK: oldAddress,
|
||||
},
|
||||
To: AddressPair{
|
||||
ID: newIdAddress,
|
||||
PK: oldAddress,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
oldAddrs, err := adt0.AsMap(ctxStore, oldState.AddressMap)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
newAddrs, err := adt0.AsMap(ctxStore, newState.AddressMap)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
err = newState.ForEachActor(func(newId abi.ActorID, newAddress address.Address) error {
|
||||
newIdAddress, err := address.NewIDAddress(uint64(newId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := adt.DiffAdtMap(oldAddrs, newAddrs, addressChanges); err != nil {
|
||||
_, found, err := newState.ResolveAddress(newAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !found {
|
||||
addressChanges.Added = append(addressChanges.Added, AddressPair{
|
||||
ID: newIdAddress,
|
||||
PK: newAddress,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
@@ -527,8 +592,6 @@ func (sp *StatePredicates) OnAddressMapChange() DiffInitActorStateFunc {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
return true, addressChanges, nil*/
|
||||
|
||||
panic("TODO")
|
||||
return true, addressChanges, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,7 +581,7 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, o
|
||||
func createSectorsAMT(ctx context.Context, t *testing.T, store adt.Store, sectors []miner.SectorOnChainInfo) cid.Cid {
|
||||
root := adt.MakeEmptyArray(store)
|
||||
for _, sector := range sectors {
|
||||
sector := sector
|
||||
sector := (miner0.SectorOnChainInfo)(sector)
|
||||
err := root.Set(uint64(sector.SectorNumber), §or)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@@ -614,8 +614,8 @@ const (
|
||||
)
|
||||
|
||||
// returns a unique SectorPreCommitInfo with each invocation with SectorNumber set to `sectorNo`.
|
||||
func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiration abi.ChainEpoch) *miner.SectorPreCommitInfo {
|
||||
return &miner.SectorPreCommitInfo{
|
||||
func newSectorPreCommitInfo(sectorNo abi.SectorNumber, sealed cid.Cid, expiration abi.ChainEpoch) *miner0.SectorPreCommitInfo {
|
||||
return &miner0.SectorPreCommitInfo{
|
||||
SealProof: abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
SectorNumber: sectorNo,
|
||||
SealedCID: sealed,
|
||||
|
||||
+93
-32
@@ -7,6 +7,7 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/helpers"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
@@ -64,7 +65,15 @@ func NewClient(lc fx.Lifecycle, host host.Host, pmgr peermgr.MaybePeerMgr) Clien
|
||||
// request options without disrupting external calls. In the future the
|
||||
// consumers should be forced to use a more standardized service and
|
||||
// adhere to a single API derived from this function.
|
||||
func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.ID) (*validatedResponse, error) {
|
||||
func (c *client) doRequest(
|
||||
ctx context.Context,
|
||||
req *Request,
|
||||
singlePeer *peer.ID,
|
||||
// In the `GetChainMessages` case, we won't request the headers but we still
|
||||
// need them to check the integrity of the `CompactedMessages` in the response
|
||||
// so the tipset blocks need to be provided by the caller.
|
||||
tipsets []*types.TipSet,
|
||||
) (*validatedResponse, error) {
|
||||
// Validate request.
|
||||
if req.Length == 0 {
|
||||
return nil, xerrors.Errorf("invalid request of length 0")
|
||||
@@ -108,14 +117,14 @@ func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.I
|
||||
res, err := c.sendRequestToPeer(ctx, peer, req)
|
||||
if err != nil {
|
||||
if !xerrors.Is(err, network.ErrNoConn) {
|
||||
log.Warnf("could not connect to peer %s: %s",
|
||||
log.Warnf("could not send request to peer %s: %s",
|
||||
peer.String(), err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Process and validate response.
|
||||
validRes, err := c.processResponse(req, res)
|
||||
validRes, err := c.processResponse(req, res, tipsets)
|
||||
if err != nil {
|
||||
log.Warnf("processing peer %s response failed: %s",
|
||||
peer.String(), err)
|
||||
@@ -143,7 +152,7 @@ func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.I
|
||||
// errors. Peer penalization should happen here then, before returning, so
|
||||
// we can apply the correct penalties depending on the cause of the error.
|
||||
// FIXME: Add the `peer` as argument once we implement penalties.
|
||||
func (c *client) processResponse(req *Request, res *Response) (*validatedResponse, error) {
|
||||
func (c *client) processResponse(req *Request, res *Response, tipsets []*types.TipSet) (*validatedResponse, error) {
|
||||
err := res.statusToError()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("status error: %s", err)
|
||||
@@ -175,6 +184,16 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons
|
||||
// Check for valid block sets and extract them into `TipSet`s.
|
||||
validRes.tipsets = make([]*types.TipSet, resLength)
|
||||
for i := 0; i < resLength; i++ {
|
||||
if res.Chain[i] == nil {
|
||||
return nil, xerrors.Errorf("response with nil tipset in pos %d", i)
|
||||
}
|
||||
for blockIdx, block := range res.Chain[i].Blocks {
|
||||
if block == nil {
|
||||
return nil, xerrors.Errorf("tipset with nil block in pos %d", blockIdx)
|
||||
// FIXME: Maybe we should move this check to `NewTipSet`.
|
||||
}
|
||||
}
|
||||
|
||||
validRes.tipsets[i], err = types.NewTipSet(res.Chain[i].Blocks)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid tipset blocks at height (head - %d): %w", i, err)
|
||||
@@ -209,31 +228,28 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons
|
||||
// If the headers were also returned check that the compression
|
||||
// indexes are valid before `toFullTipSets()` is called by the
|
||||
// consumer.
|
||||
for tipsetIdx := 0; tipsetIdx < resLength; tipsetIdx++ {
|
||||
msgs := res.Chain[tipsetIdx].Messages
|
||||
blocksNum := len(res.Chain[tipsetIdx].Blocks)
|
||||
if len(msgs.BlsIncludes) != blocksNum {
|
||||
return nil, xerrors.Errorf("BlsIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.BlsIncludes), blocksNum)
|
||||
}
|
||||
if len(msgs.SecpkIncludes) != blocksNum {
|
||||
return nil, xerrors.Errorf("SecpkIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.SecpkIncludes), blocksNum)
|
||||
}
|
||||
for blockIdx := 0; blockIdx < blocksNum; blockIdx++ {
|
||||
for _, mi := range msgs.BlsIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Bls) {
|
||||
return nil, xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Bls))
|
||||
}
|
||||
}
|
||||
for _, mi := range msgs.SecpkIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Secpk) {
|
||||
return nil, xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Secpk))
|
||||
}
|
||||
}
|
||||
err := c.validateCompressedIndices(res.Chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// If we didn't request the headers they should have been provided
|
||||
// by the caller.
|
||||
if len(tipsets) < len(res.Chain) {
|
||||
return nil, xerrors.Errorf("not enought tipsets provided for message response validation, needed %d, have %d", len(res.Chain), len(tipsets))
|
||||
}
|
||||
chain := make([]*BSTipSet, 0, resLength)
|
||||
for i, resChain := range res.Chain {
|
||||
next := &BSTipSet{
|
||||
Blocks: tipsets[i].Blocks(),
|
||||
Messages: resChain.Messages,
|
||||
}
|
||||
chain = append(chain, next)
|
||||
}
|
||||
|
||||
err := c.validateCompressedIndices(chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,6 +257,42 @@ func (c *client) processResponse(req *Request, res *Response) (*validatedRespons
|
||||
return validRes, nil
|
||||
}
|
||||
|
||||
func (c *client) validateCompressedIndices(chain []*BSTipSet) error {
|
||||
resLength := len(chain)
|
||||
for tipsetIdx := 0; tipsetIdx < resLength; tipsetIdx++ {
|
||||
msgs := chain[tipsetIdx].Messages
|
||||
blocksNum := len(chain[tipsetIdx].Blocks)
|
||||
|
||||
if len(msgs.BlsIncludes) != blocksNum {
|
||||
return xerrors.Errorf("BlsIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.BlsIncludes), blocksNum)
|
||||
}
|
||||
|
||||
if len(msgs.SecpkIncludes) != blocksNum {
|
||||
return xerrors.Errorf("SecpkIncludes (%d) does not match number of blocks (%d)",
|
||||
len(msgs.SecpkIncludes), blocksNum)
|
||||
}
|
||||
|
||||
for blockIdx := 0; blockIdx < blocksNum; blockIdx++ {
|
||||
for _, mi := range msgs.BlsIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Bls) {
|
||||
return xerrors.Errorf("index in BlsIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Bls))
|
||||
}
|
||||
}
|
||||
|
||||
for _, mi := range msgs.SecpkIncludes[blockIdx] {
|
||||
if int(mi) >= len(msgs.Secpk) {
|
||||
return xerrors.Errorf("index in SecpkIncludes (%d) exceeds number of messages (%d)",
|
||||
mi, len(msgs.Secpk))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBlocks implements Client.GetBlocks(). Refer to the godocs there.
|
||||
func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks")
|
||||
@@ -258,7 +310,7 @@ func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int)
|
||||
Options: Headers,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, nil)
|
||||
validRes, err := c.doRequest(ctx, req, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -276,7 +328,7 @@ func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipS
|
||||
Options: Headers | Messages,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, &peer)
|
||||
validRes, err := c.doRequest(ctx, req, &peer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -287,7 +339,10 @@ func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipS
|
||||
}
|
||||
|
||||
// GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there.
|
||||
func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) {
|
||||
func (c *client) GetChainMessages(ctx context.Context, tipsets []*types.TipSet) ([]*CompactedMessages, error) {
|
||||
head := tipsets[0]
|
||||
length := uint64(len(tipsets))
|
||||
|
||||
ctx, span := trace.StartSpan(ctx, "GetChainMessages")
|
||||
if span.IsRecordingEvents() {
|
||||
span.AddAttributes(
|
||||
@@ -303,7 +358,7 @@ func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, lengt
|
||||
Options: Messages,
|
||||
}
|
||||
|
||||
validRes, err := c.doRequest(ctx, req, nil)
|
||||
validRes, err := c.doRequest(ctx, req, nil, tipsets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -357,6 +412,12 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque
|
||||
return nil, xerrors.Errorf("failed to open stream to peer: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Note: this will become just stream.Close once we've completed the go-libp2p migration to
|
||||
// go-libp2p-core 0.7.0
|
||||
go helpers.FullClose(stream) //nolint:errcheck
|
||||
}()
|
||||
|
||||
// Write request.
|
||||
_ = stream.SetWriteDeadline(time.Now().Add(WriteReqDeadline))
|
||||
if err := cborutil.WriteCborRPC(stream, req); err != nil {
|
||||
|
||||
@@ -32,10 +32,9 @@ type Client interface {
|
||||
// or less.
|
||||
GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error)
|
||||
|
||||
// GetChainMessages fetches messages from the network, from the provided
|
||||
// tipset *backwards*, returning the messages from as many tipsets as the
|
||||
// count parameter, or less.
|
||||
GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error)
|
||||
// GetChainMessages fetches messages from the network, starting from the first provided tipset
|
||||
// and returning messages from as many tipsets as requested or less.
|
||||
GetChainMessages(ctx context.Context, tipsets []*types.TipSet) ([]*CompactedMessages, error)
|
||||
|
||||
// GetFullTipSet fetches a full tipset from a given peer. If successful,
|
||||
// the fetched object contains block headers and all messages in full form.
|
||||
|
||||
@@ -40,7 +40,7 @@ const (
|
||||
WriteReqDeadline = 5 * time.Second
|
||||
ReadResDeadline = WriteReqDeadline
|
||||
ReadResMinSpeed = 50 << 10
|
||||
ShufflePeersPrefix = 5
|
||||
ShufflePeersPrefix = 16
|
||||
WriteResDeadline = 60 * time.Second
|
||||
)
|
||||
|
||||
@@ -139,6 +139,8 @@ func (res *Response) statusToError() error {
|
||||
|
||||
// FIXME: Rename.
|
||||
type BSTipSet struct {
|
||||
// List of blocks belonging to a single tipset to which the
|
||||
// `CompactedMessages` are linked.
|
||||
Blocks []*types.BlockHeader
|
||||
Messages *CompactedMessages
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/helpers"
|
||||
inet "github.com/libp2p/go-libp2p-core/network"
|
||||
)
|
||||
|
||||
@@ -39,7 +40,9 @@ func (s *server) HandleStream(stream inet.Stream) {
|
||||
ctx, span := trace.StartSpan(context.Background(), "chainxchg.HandleStream")
|
||||
defer span.End()
|
||||
|
||||
defer stream.Close() //nolint:errcheck
|
||||
// Note: this will become just stream.Close once we've completed the go-libp2p migration to
|
||||
// go-libp2p-core 0.7.0
|
||||
defer helpers.FullClose(stream) //nolint:errcheck
|
||||
|
||||
var req Request
|
||||
if err := cborutil.ReadCborRPC(bufio.NewReader(stream), &req); err != nil {
|
||||
|
||||
+5
-5
@@ -9,12 +9,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-blockservice"
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/beacon"
|
||||
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
@@ -121,9 +122,8 @@ var DefaultRemainderAccountActor = genesis.Actor{
|
||||
}
|
||||
|
||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
// TODO: we really shouldn't modify a global variable here.
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
|
||||
mr := repo.NewMemory(nil)
|
||||
lr, err := mr.Lock(repo.StorageMiner)
|
||||
@@ -225,7 +225,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
},
|
||||
VerifregRootKey: DefaultVerifregRootkeyActor,
|
||||
RemainderAccount: DefaultRemainderAccountActor,
|
||||
NetworkName: "",
|
||||
NetworkName: uuid.New().String(),
|
||||
Timestamp: uint64(build.Clock.Now().Add(-500 * time.Duration(build.BlockDelaySecs) * time.Second).Unix()),
|
||||
}
|
||||
|
||||
|
||||
@@ -4,21 +4,16 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg0.MinVerifiedDealSize = big.NewInt(256)
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
func testGeneration(t testing.TB, n int, msgs int, sectors int) {
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@@ -24,7 +26,6 @@ import (
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -115,7 +116,7 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||
}
|
||||
|
||||
state, err := state.NewStateTree(cst, builtin.Version0)
|
||||
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
@@ -296,14 +297,9 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
return nil, nil, xerrors.Errorf("somehow overallocated filecoin (allocated = %s)", types.FIL(totalFilAllocated))
|
||||
}
|
||||
|
||||
remAccKey, err := address.NewIDAddress(90)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
template.RemainderAccount.Balance = remainingFil
|
||||
|
||||
if err := createMultisigAccount(ctx, bs, cst, state, remAccKey, template.RemainderAccount, keyIDs); err != nil {
|
||||
if err := createMultisigAccount(ctx, bs, cst, state, builtin.ReserveAddress, template.RemainderAccount, keyIDs); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to set up remainder account: %w", err)
|
||||
}
|
||||
|
||||
|
||||
+21
-16
@@ -6,6 +6,12 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
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"
|
||||
@@ -19,7 +25,6 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"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"
|
||||
@@ -109,7 +114,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
|
||||
params := mustEnc(constructorParams)
|
||||
rval, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, m.Owner, m.PowerBalance, builtin.MethodsPower.CreateMiner, params)
|
||||
rval, err := doExecValue(ctx, vm, power.Address, m.Owner, m.PowerBalance, builtin.MethodsPower.CreateMiner, params)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
|
||||
}
|
||||
@@ -141,7 +146,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
|
||||
if m.MarketBalance.GreaterThan(big.Zero()) {
|
||||
params := mustEnc(&minerInfos[i].maddr)
|
||||
_, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params)
|
||||
_, err := doExecValue(ctx, vm, market.Address, m.Worker, m.MarketBalance, builtin.MethodsMarket.AddBalance, params)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create genesis miner (add balance): %w", err)
|
||||
}
|
||||
@@ -153,7 +158,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
publish := func(params *market.PublishStorageDealsParams) error {
|
||||
fmt.Printf("publishing %d storage deals on miner %s with worker %s\n", len(params.Deals), params.Deals[0].Proposal.Provider, m.Worker)
|
||||
|
||||
ret, err := doExecValue(ctx, vm, builtin.StorageMarketActorAddr, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params))
|
||||
ret, err := doExecValue(ctx, vm, market.Address, m.Worker, big.Zero(), builtin.MethodsMarket.PublishStorageDeals, mustEnc(params))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err)
|
||||
}
|
||||
@@ -210,7 +215,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
st.TotalQualityAdjPower = qaPow
|
||||
st.TotalRawBytePower = rawPow
|
||||
|
||||
@@ -222,7 +227,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
return cid.Undef, xerrors.Errorf("mutating state: %w", err)
|
||||
}
|
||||
|
||||
err = vm.MutateState(ctx, builtin.RewardActorAddr, func(sct cbor.IpldStore, st *reward0.State) error {
|
||||
err = vm.MutateState(ctx, reward.Address, func(sct cbor.IpldStore, st *reward0.State) error {
|
||||
*st = *reward0.ConstructState(qaPow)
|
||||
return nil
|
||||
})
|
||||
@@ -252,7 +257,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
sectorWeight := miner0.QAPowerForWeight(m.SectorSize, minerInfos[i].presealExp, dweight.DealWeight, dweight.VerifiedDealWeight)
|
||||
|
||||
// we've added fake power for this sector above, remove it now
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
st.TotalQualityAdjPower = types.BigSub(st.TotalQualityAdjPower, sectorWeight) //nolint:scopelint
|
||||
st.TotalRawBytePower = types.BigSub(st.TotalRawBytePower, types.NewInt(uint64(m.SectorSize)))
|
||||
return nil
|
||||
@@ -295,7 +300,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, builtin.StoragePowerActorAddr, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams))
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), builtin.MethodsMiner.ConfirmSectorProofsValid, mustEnc(confirmParams))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
@@ -304,7 +309,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
|
||||
}
|
||||
|
||||
// Sanity-check total network power
|
||||
err = vm.MutateState(ctx, builtin.StoragePowerActorAddr, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
err = vm.MutateState(ctx, power.Address, func(cst cbor.IpldStore, st *power0.State) error {
|
||||
if !st.TotalRawBytePower.Equals(rawPow) {
|
||||
return xerrors.Errorf("st.TotalRawBytePower doesn't match previously calculated rawPow")
|
||||
}
|
||||
@@ -344,7 +349,7 @@ func (fr *fakeRand) GetBeaconRandomness(ctx context.Context, personalization cry
|
||||
}
|
||||
|
||||
func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*power0.CurrentTotalPowerReturn, error) {
|
||||
pwret, err := doExecValue(ctx, vm, builtin.StoragePowerActorAddr, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil)
|
||||
pwret, err := doExecValue(ctx, vm, power.Address, maddr, big.Zero(), builtin.MethodsPower.CurrentTotalPower, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -356,33 +361,33 @@ func currentTotalPower(ctx context.Context, vm *vm.VM, maddr address.Address) (*
|
||||
return &pwr, nil
|
||||
}
|
||||
|
||||
func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market.VerifyDealsForActivationReturn, error) {
|
||||
func dealWeight(ctx context.Context, vm *vm.VM, maddr address.Address, dealIDs []abi.DealID, sectorStart, sectorExpiry abi.ChainEpoch) (market0.VerifyDealsForActivationReturn, error) {
|
||||
params := &market.VerifyDealsForActivationParams{
|
||||
DealIDs: dealIDs,
|
||||
SectorStart: sectorStart,
|
||||
SectorExpiry: sectorExpiry,
|
||||
}
|
||||
|
||||
var dealWeights market.VerifyDealsForActivationReturn
|
||||
var dealWeights market0.VerifyDealsForActivationReturn
|
||||
ret, err := doExecValue(ctx, vm,
|
||||
builtin.StorageMarketActorAddr,
|
||||
market.Address,
|
||||
maddr,
|
||||
abi.NewTokenAmount(0),
|
||||
builtin.MethodsMarket.VerifyDealsForActivation,
|
||||
mustEnc(params),
|
||||
)
|
||||
if err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
return market0.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
if err := dealWeights.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return market.VerifyDealsForActivationReturn{}, err
|
||||
return market0.VerifyDealsForActivationReturn{}, err
|
||||
}
|
||||
|
||||
return dealWeights, nil
|
||||
}
|
||||
|
||||
func currentEpochBlockReward(ctx context.Context, vm *vm.VM, maddr address.Address) (*reward0.ThisEpochRewardReturn, error) {
|
||||
rwret, err := doExecValue(ctx, vm, builtin.RewardActorAddr, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil)
|
||||
rwret, err := doExecValue(ctx, vm, reward.Address, maddr, big.Zero(), builtin.MethodsReward.ThisEpochReward, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -105,6 +105,10 @@ func checkFault(t ds.Datastore, key ds.Key, bh *types.BlockHeader, faultType str
|
||||
return err
|
||||
}
|
||||
|
||||
if other == bh.Cid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return xerrors.Errorf("produced block would trigger '%s' consensus fault; miner: %s; bh: %s, other: %s", faultType, bh.Miner, bh.Cid(), other)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -151,7 +152,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
}
|
||||
|
||||
smsg, err := fm.api.MpoolPushMessage(ctx, &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
To: market.Address,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
@@ -47,7 +48,7 @@ func (fapi *fakeAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, s
|
||||
func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Address) *types.Message {
|
||||
params, _ := actors.SerializeParams(&addr)
|
||||
return &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
To: market.Address,
|
||||
From: wallet,
|
||||
Value: toAdd,
|
||||
Method: builtin.MethodsMarket.AddBalance,
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
)
|
||||
|
||||
type ActorLookup func(context.Context, address.Address, types.TipSetKey) (*types.Actor, error)
|
||||
@@ -27,19 +29,33 @@ type CostKey struct {
|
||||
}
|
||||
|
||||
var Costs = map[CostKey]int64{
|
||||
{builtin.InitActorCodeID, 2}: 8916753,
|
||||
{builtin.StorageMarketActorCodeID, 2}: 6955002,
|
||||
{builtin.StorageMarketActorCodeID, 4}: 245436108,
|
||||
{builtin.StorageMinerActorCodeID, 4}: 2315133,
|
||||
{builtin.StorageMinerActorCodeID, 5}: 1600271356,
|
||||
{builtin.StorageMinerActorCodeID, 6}: 22864493,
|
||||
{builtin.StorageMinerActorCodeID, 7}: 142002419,
|
||||
{builtin.StorageMinerActorCodeID, 10}: 23008274,
|
||||
{builtin.StorageMinerActorCodeID, 11}: 19303178,
|
||||
{builtin.StorageMinerActorCodeID, 14}: 566356835,
|
||||
{builtin.StorageMinerActorCodeID, 16}: 5325185,
|
||||
{builtin.StorageMinerActorCodeID, 18}: 2328637,
|
||||
{builtin.StoragePowerActorCodeID, 2}: 23600956,
|
||||
{builtin0.InitActorCodeID, 2}: 8916753,
|
||||
{builtin0.StorageMarketActorCodeID, 2}: 6955002,
|
||||
{builtin0.StorageMarketActorCodeID, 4}: 245436108,
|
||||
{builtin0.StorageMinerActorCodeID, 4}: 2315133,
|
||||
{builtin0.StorageMinerActorCodeID, 5}: 1600271356,
|
||||
{builtin0.StorageMinerActorCodeID, 6}: 22864493,
|
||||
{builtin0.StorageMinerActorCodeID, 7}: 142002419,
|
||||
{builtin0.StorageMinerActorCodeID, 10}: 23008274,
|
||||
{builtin0.StorageMinerActorCodeID, 11}: 19303178,
|
||||
{builtin0.StorageMinerActorCodeID, 14}: 566356835,
|
||||
{builtin0.StorageMinerActorCodeID, 16}: 5325185,
|
||||
{builtin0.StorageMinerActorCodeID, 18}: 2328637,
|
||||
{builtin0.StoragePowerActorCodeID, 2}: 23600956,
|
||||
// TODO: Just reuse v0 values for now, this isn't actually used
|
||||
{builtin2.InitActorCodeID, 2}: 8916753,
|
||||
{builtin2.StorageMarketActorCodeID, 2}: 6955002,
|
||||
{builtin2.StorageMarketActorCodeID, 4}: 245436108,
|
||||
{builtin2.StorageMinerActorCodeID, 4}: 2315133,
|
||||
{builtin2.StorageMinerActorCodeID, 5}: 1600271356,
|
||||
{builtin2.StorageMinerActorCodeID, 6}: 22864493,
|
||||
{builtin2.StorageMinerActorCodeID, 7}: 142002419,
|
||||
{builtin2.StorageMinerActorCodeID, 10}: 23008274,
|
||||
{builtin2.StorageMinerActorCodeID, 11}: 19303178,
|
||||
{builtin2.StorageMinerActorCodeID, 14}: 566356835,
|
||||
{builtin2.StorageMinerActorCodeID, 16}: 5325185,
|
||||
{builtin2.StorageMinerActorCodeID, 18}: 2328637,
|
||||
{builtin2.StoragePowerActorCodeID, 2}: 23600956,
|
||||
}
|
||||
|
||||
func failedGuess(msg *types.SignedMessage) int64 {
|
||||
@@ -51,7 +67,8 @@ func failedGuess(msg *types.SignedMessage) int64 {
|
||||
}
|
||||
|
||||
func GuessGasUsed(ctx context.Context, tsk types.TipSetKey, msg *types.SignedMessage, al ActorLookup) (int64, error) {
|
||||
if msg.Message.Method == builtin.MethodSend {
|
||||
// MethodSend is the same in all versions.
|
||||
if msg.Message.Method == builtin0.MethodSend {
|
||||
switch msg.Message.From.Protocol() {
|
||||
case address.BLS:
|
||||
return 1298450, nil
|
||||
|
||||
@@ -55,6 +55,7 @@ var baseFeeLowerBoundFactor = types.NewInt(10)
|
||||
var baseFeeLowerBoundFactorConservative = types.NewInt(100)
|
||||
|
||||
var MaxActorPendingMessages = 1000
|
||||
var MaxUntrustedActorPendingMessages = 10
|
||||
|
||||
var MaxNonceGap = uint64(4)
|
||||
|
||||
@@ -75,8 +76,6 @@ var (
|
||||
ErrRBFTooLowPremium = errors.New("replace by fee has too low GasPremium")
|
||||
ErrTooManyPendingMessages = errors.New("too many pending messages for actor")
|
||||
ErrNonceGap = errors.New("unfulfilled nonce gap")
|
||||
|
||||
ErrTryAgain = errors.New("state inconsistency while pushing message; please try again")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -197,9 +196,17 @@ func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) {
|
||||
msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap
|
||||
}
|
||||
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) {
|
||||
func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict, untrusted bool) (bool, error) {
|
||||
nextNonce := ms.nextNonce
|
||||
nonceGap := false
|
||||
|
||||
maxNonceGap := MaxNonceGap
|
||||
maxActorPendingMessages := MaxActorPendingMessages
|
||||
if untrusted {
|
||||
maxNonceGap = 0
|
||||
maxActorPendingMessages = MaxUntrustedActorPendingMessages
|
||||
}
|
||||
|
||||
switch {
|
||||
case m.Message.Nonce == nextNonce:
|
||||
nextNonce++
|
||||
@@ -208,7 +215,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (boo
|
||||
nextNonce++
|
||||
}
|
||||
|
||||
case strict && m.Message.Nonce > nextNonce+MaxNonceGap:
|
||||
case strict && m.Message.Nonce > nextNonce+maxNonceGap:
|
||||
return false, xerrors.Errorf("message nonce has too big a gap from expected nonce (Nonce: %d, nextNonce: %d): %w", m.Message.Nonce, nextNonce, ErrNonceGap)
|
||||
|
||||
case m.Message.Nonce > nextNonce:
|
||||
@@ -244,7 +251,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (boo
|
||||
//ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
||||
}
|
||||
|
||||
if !has && strict && len(ms.msgs) > MaxActorPendingMessages {
|
||||
if !has && strict && len(ms.msgs) >= maxActorPendingMessages {
|
||||
log.Errorf("too many pending messages from actor %s", m.Message.From)
|
||||
return false, ErrTooManyPendingMessages
|
||||
}
|
||||
@@ -486,7 +493,7 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) {
|
||||
}
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
publish, err := mp.addTs(m, mp.curTs, true)
|
||||
publish, err := mp.addTs(m, mp.curTs, true, false)
|
||||
if err != nil {
|
||||
mp.curTsLk.Unlock()
|
||||
return cid.Undef, err
|
||||
@@ -553,7 +560,7 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
|
||||
_, err = mp.addTs(m, mp.curTs, false)
|
||||
_, err = mp.addTs(m, mp.curTs, false, false)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -621,7 +628,7 @@ func (mp *MessagePool) checkBalance(m *types.SignedMessage, curTs *types.TipSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) {
|
||||
func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local, untrusted bool) (bool, error) {
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||
@@ -643,7 +650,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local
|
||||
return false, err
|
||||
}
|
||||
|
||||
return publish, mp.addLocked(m, !local)
|
||||
return publish, mp.addLocked(m, !local, untrusted)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
@@ -678,17 +685,17 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return mp.addLocked(m, false)
|
||||
return mp.addLocked(m, false, false)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addSkipChecks(m *types.SignedMessage) error {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
return mp.addLocked(m, false)
|
||||
return mp.addLocked(m, false, false)
|
||||
}
|
||||
|
||||
func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
func (mp *MessagePool) addLocked(m *types.SignedMessage, strict, untrusted bool) error {
|
||||
log.Debugf("mpooladd: %s %d", m.Message.From, m.Message.Nonce)
|
||||
if m.Signature.Type == crypto.SigTypeBLS {
|
||||
mp.blsSigCache.Add(m.Cid(), m.Signature)
|
||||
@@ -715,7 +722,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
mp.pending[m.Message.From] = mset
|
||||
}
|
||||
|
||||
incr, err := mset.add(m, mp, strict)
|
||||
incr, err := mset.add(m, mp, strict, untrusted)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
@@ -795,96 +802,48 @@ func (mp *MessagePool) getStateBalance(addr address.Address, ts *types.TipSet) (
|
||||
return act.Balance, nil
|
||||
}
|
||||
|
||||
func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, cb func(address.Address, uint64) (*types.SignedMessage, error)) (*types.SignedMessage, error) {
|
||||
// this method is provided for the gateway to push messages.
|
||||
// differences from Push:
|
||||
// - strict checks are enabled
|
||||
// - extra strict add checks are used when adding the messages to the msgSet
|
||||
// that means: no nonce gaps, at most 10 pending messages for the actor
|
||||
func (mp *MessagePool) PushUntrusted(m *types.SignedMessage) (cid.Cid, error) {
|
||||
err := mp.checkMessage(m)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
// serialize push access to reduce lock contention
|
||||
mp.addSema <- struct{}{}
|
||||
defer func() {
|
||||
<-mp.addSema
|
||||
}()
|
||||
|
||||
mp.curTsLk.Lock()
|
||||
mp.lk.Lock()
|
||||
|
||||
curTs := mp.curTs
|
||||
|
||||
fromKey := addr
|
||||
if fromKey.Protocol() == address.ID {
|
||||
var err error
|
||||
fromKey, err = mp.api.StateAccountKey(ctx, fromKey, mp.curTs)
|
||||
if err != nil {
|
||||
mp.lk.Unlock()
|
||||
mp.curTsLk.Unlock()
|
||||
return nil, xerrors.Errorf("resolving sender key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
nonce, err := mp.getNonceLocked(fromKey, mp.curTs)
|
||||
msgb, err := m.Serialize()
|
||||
if err != nil {
|
||||
mp.lk.Unlock()
|
||||
mp.curTsLk.Unlock()
|
||||
return nil, xerrors.Errorf("get nonce locked failed: %w", err)
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
// release the locks for signing
|
||||
mp.lk.Unlock()
|
||||
mp.curTsLk.Lock()
|
||||
publish, err := mp.addTs(m, mp.curTs, false, true)
|
||||
if err != nil {
|
||||
mp.curTsLk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
mp.curTsLk.Unlock()
|
||||
|
||||
msg, err := cb(fromKey, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = mp.checkMessage(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgb, err := msg.Serialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// reacquire the locks and check state for consistency
|
||||
mp.curTsLk.Lock()
|
||||
defer mp.curTsLk.Unlock()
|
||||
|
||||
if mp.curTs != curTs {
|
||||
return nil, ErrTryAgain
|
||||
}
|
||||
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
nonce2, err := mp.getNonceLocked(fromKey, mp.curTs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get nonce locked failed: %w", err)
|
||||
}
|
||||
|
||||
if nonce2 != nonce {
|
||||
return nil, ErrTryAgain
|
||||
}
|
||||
|
||||
publish, err := mp.verifyMsgBeforeAdd(msg, curTs, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mp.checkBalance(msg, curTs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := mp.addLocked(msg, false); err != nil {
|
||||
return nil, xerrors.Errorf("add locked failed: %w", err)
|
||||
}
|
||||
if err := mp.addLocal(msg, msgb); err != nil {
|
||||
log.Errorf("addLocal failed: %+v", err)
|
||||
if err := mp.addLocal(m, msgb); err != nil {
|
||||
mp.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
mp.lk.Unlock()
|
||||
|
||||
if publish {
|
||||
err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb)
|
||||
}
|
||||
|
||||
return msg, err
|
||||
return m.Cid(), err
|
||||
}
|
||||
|
||||
func (mp *MessagePool) Remove(from address.Address, nonce uint64, applied bool) {
|
||||
|
||||
@@ -149,13 +149,13 @@ loop:
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
msgsEv := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
for _, m := range msgs {
|
||||
msgs = append(msgs, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
msgsEv = append(msgsEv, MessagePoolEvtMessage{Message: m.Message, CID: m.Cid()})
|
||||
}
|
||||
return MessagePoolEvt{
|
||||
Action: "repub",
|
||||
Messages: msgs,
|
||||
Messages: msgsEv,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package messagesigner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/namespace"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const dsKeyActorNonce = "ActorNextNonce"
|
||||
|
||||
var log = logging.Logger("messagesigner")
|
||||
|
||||
type mpoolAPI interface {
|
||||
GetNonce(address.Address) (uint64, error)
|
||||
}
|
||||
|
||||
// MessageSigner keeps track of nonces per address, and increments the nonce
|
||||
// when signing a message
|
||||
type MessageSigner struct {
|
||||
wallet *wallet.Wallet
|
||||
lk sync.Mutex
|
||||
mpool mpoolAPI
|
||||
ds datastore.Batching
|
||||
}
|
||||
|
||||
func NewMessageSigner(wallet *wallet.Wallet, mpool *messagepool.MessagePool, ds dtypes.MetadataDS) *MessageSigner {
|
||||
return newMessageSigner(wallet, mpool, ds)
|
||||
}
|
||||
|
||||
func newMessageSigner(wallet *wallet.Wallet, mpool mpoolAPI, ds dtypes.MetadataDS) *MessageSigner {
|
||||
ds = namespace.Wrap(ds, datastore.NewKey("/message-signer/"))
|
||||
return &MessageSigner{
|
||||
wallet: wallet,
|
||||
mpool: mpool,
|
||||
ds: ds,
|
||||
}
|
||||
}
|
||||
|
||||
// SignMessage increments the nonce for the message From address, and signs
|
||||
// the message
|
||||
func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, cb func(*types.SignedMessage) error) (*types.SignedMessage, error) {
|
||||
ms.lk.Lock()
|
||||
defer ms.lk.Unlock()
|
||||
|
||||
// Get the next message nonce
|
||||
nonce, err := ms.nextNonce(msg.From)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create nonce: %w", err)
|
||||
}
|
||||
|
||||
// Sign the message with the nonce
|
||||
msg.Nonce = nonce
|
||||
sig, err := ms.wallet.Sign(ctx, msg.From, msg.Cid().Bytes())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign message: %w", err)
|
||||
}
|
||||
|
||||
// Callback with the signed message
|
||||
smsg := &types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: *sig,
|
||||
}
|
||||
err = cb(smsg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the callback executed successfully, write the nonce to the datastore
|
||||
if err := ms.saveNonce(msg.From, nonce); err != nil {
|
||||
return nil, xerrors.Errorf("failed to save nonce: %w", err)
|
||||
}
|
||||
|
||||
return smsg, nil
|
||||
}
|
||||
|
||||
// nextNonce gets the next nonce for the given address.
|
||||
// If there is no nonce in the datastore, gets the nonce from the message pool.
|
||||
func (ms *MessageSigner) nextNonce(addr address.Address) (uint64, error) {
|
||||
// Nonces used to be created by the mempool and we need to support nodes
|
||||
// that have mempool nonces, so first check the mempool for a nonce for
|
||||
// this address. Note that the mempool returns the actor state's nonce
|
||||
// by default.
|
||||
nonce, err := ms.mpool.GetNonce(addr)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to get nonce from mempool: %w", err)
|
||||
}
|
||||
|
||||
// Get the next nonce for this address from the datastore
|
||||
addrNonceKey := ms.dstoreKey(addr)
|
||||
dsNonceBytes, err := ms.ds.Get(addrNonceKey)
|
||||
|
||||
switch {
|
||||
case xerrors.Is(err, datastore.ErrNotFound):
|
||||
// If a nonce for this address hasn't yet been created in the
|
||||
// datastore, just use the nonce from the mempool
|
||||
return nonce, nil
|
||||
|
||||
case err != nil:
|
||||
return 0, xerrors.Errorf("failed to get nonce from datastore: %w", err)
|
||||
|
||||
default:
|
||||
// There is a nonce in the datastore, so unmarshall it
|
||||
maj, dsNonce, err := cbg.CborReadHeader(bytes.NewReader(dsNonceBytes))
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("failed to parse nonce from datastore: %w", err)
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return 0, xerrors.Errorf("bad cbor type parsing nonce from datastore")
|
||||
}
|
||||
|
||||
// The message pool nonce should be <= than the datastore nonce
|
||||
if nonce <= dsNonce {
|
||||
nonce = dsNonce
|
||||
} else {
|
||||
log.Warnf("mempool nonce was larger than datastore nonce (%d > %d)", nonce, dsNonce)
|
||||
}
|
||||
|
||||
return nonce, nil
|
||||
}
|
||||
}
|
||||
|
||||
// saveNonce increments the nonce for this address and writes it to the
|
||||
// datastore
|
||||
func (ms *MessageSigner) saveNonce(addr address.Address, nonce uint64) error {
|
||||
// Increment the nonce
|
||||
nonce++
|
||||
|
||||
// Write the nonce to the datastore
|
||||
addrNonceKey := ms.dstoreKey(addr)
|
||||
buf := bytes.Buffer{}
|
||||
_, err := buf.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, nonce))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to marshall nonce: %w", err)
|
||||
}
|
||||
err = ms.ds.Put(addrNonceKey, buf.Bytes())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to write nonce to datastore: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
|
||||
return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()})
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package messagesigner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-datastore"
|
||||
)
|
||||
|
||||
type mockMpool struct {
|
||||
lk sync.RWMutex
|
||||
nonces map[address.Address]uint64
|
||||
}
|
||||
|
||||
func newMockMpool() *mockMpool {
|
||||
return &mockMpool{nonces: make(map[address.Address]uint64)}
|
||||
}
|
||||
|
||||
func (mp *mockMpool) setNonce(addr address.Address, nonce uint64) {
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
mp.nonces[addr] = nonce
|
||||
}
|
||||
|
||||
func (mp *mockMpool) GetNonce(addr address.Address) (uint64, error) {
|
||||
mp.lk.RLock()
|
||||
defer mp.lk.RUnlock()
|
||||
|
||||
return mp.nonces[addr], nil
|
||||
}
|
||||
|
||||
func TestMessageSignerSignMessage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
w, _ := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
from1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
require.NoError(t, err)
|
||||
from2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to1, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to2, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
require.NoError(t, err)
|
||||
|
||||
type msgSpec struct {
|
||||
msg *types.Message
|
||||
mpoolNonce [1]uint64
|
||||
expNonce uint64
|
||||
cbErr error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
msgs []msgSpec
|
||||
}{{
|
||||
// No nonce yet in datastore
|
||||
name: "no nonce yet",
|
||||
msgs: []msgSpec{{
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 0,
|
||||
}},
|
||||
}, {
|
||||
// Get nonce value of zero from mpool
|
||||
name: "mpool nonce zero",
|
||||
msgs: []msgSpec{{
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
mpoolNonce: [1]uint64{0},
|
||||
expNonce: 0,
|
||||
}},
|
||||
}, {
|
||||
// Get non-zero nonce value from mpool
|
||||
name: "mpool nonce set",
|
||||
msgs: []msgSpec{{
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
mpoolNonce: [1]uint64{5},
|
||||
expNonce: 5,
|
||||
}, {
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
// Should adjust datastore nonce because mpool nonce is higher
|
||||
mpoolNonce: [1]uint64{10},
|
||||
expNonce: 10,
|
||||
}},
|
||||
}, {
|
||||
// Nonce should increment independently for each address
|
||||
name: "nonce increments per address",
|
||||
msgs: []msgSpec{{
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 0,
|
||||
}, {
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 1,
|
||||
}, {
|
||||
msg: &types.Message{
|
||||
To: to2,
|
||||
From: from2,
|
||||
},
|
||||
mpoolNonce: [1]uint64{5},
|
||||
expNonce: 5,
|
||||
}, {
|
||||
msg: &types.Message{
|
||||
To: to2,
|
||||
From: from2,
|
||||
},
|
||||
expNonce: 6,
|
||||
}, {
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 2,
|
||||
}},
|
||||
}, {
|
||||
name: "recover from callback error",
|
||||
msgs: []msgSpec{{
|
||||
// No nonce yet in datastore
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 0,
|
||||
}, {
|
||||
// Increment nonce
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 1,
|
||||
}, {
|
||||
// Callback returns error
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
cbErr: xerrors.Errorf("err"),
|
||||
}, {
|
||||
// Callback successful, should increment nonce in datastore
|
||||
msg: &types.Message{
|
||||
To: to1,
|
||||
From: from1,
|
||||
},
|
||||
expNonce: 2,
|
||||
}},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mpool := newMockMpool()
|
||||
ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
|
||||
ms := newMessageSigner(w, mpool, ds)
|
||||
|
||||
for _, m := range tt.msgs {
|
||||
if len(m.mpoolNonce) == 1 {
|
||||
mpool.setNonce(m.msg.From, m.mpoolNonce[0])
|
||||
}
|
||||
merr := m.cbErr
|
||||
smsg, err := ms.SignMessage(ctx, m.msg, func(message *types.SignedMessage) error {
|
||||
return merr
|
||||
})
|
||||
|
||||
if m.cbErr != nil {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, smsg)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, m.expNonce, smsg.Message.Nonce)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+65
-31
@@ -13,7 +13,8 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
@@ -26,7 +27,7 @@ var log = logging.Logger("statetree")
|
||||
// StateTree stores actors state by their ID.
|
||||
type StateTree struct {
|
||||
root adt.Map
|
||||
version builtin.Version // TODO
|
||||
version types.StateTreeVersion
|
||||
info cid.Cid
|
||||
Store cbor.IpldStore
|
||||
|
||||
@@ -120,15 +121,41 @@ func (ss *stateSnaps) deleteActor(addr address.Address) {
|
||||
ss.layers[len(ss.layers)-1].actors[addr] = streeOp{Delete: true}
|
||||
}
|
||||
|
||||
func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, error) {
|
||||
var info cid.Cid
|
||||
switch version {
|
||||
case builtin.Version0:
|
||||
// info is undefined
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", version)
|
||||
// VersionForNetwork returns the state tree version for the given network
|
||||
// version.
|
||||
func VersionForNetwork(ver network.Version) types.StateTreeVersion {
|
||||
if actors.VersionForNetwork(ver) == actors.Version0 {
|
||||
return types.StateTreeVersion0
|
||||
}
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
||||
return types.StateTreeVersion1
|
||||
}
|
||||
|
||||
func adtForSTVersion(ver types.StateTreeVersion) actors.Version {
|
||||
switch ver {
|
||||
case types.StateTreeVersion0:
|
||||
return actors.Version0
|
||||
case types.StateTreeVersion1:
|
||||
return actors.Version2
|
||||
default:
|
||||
panic("unhandled state tree version")
|
||||
}
|
||||
}
|
||||
|
||||
func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, error) {
|
||||
var info cid.Cid
|
||||
switch ver {
|
||||
case types.StateTreeVersion0:
|
||||
// info is undefined
|
||||
case types.StateTreeVersion1:
|
||||
var err error
|
||||
info, err = cst.Put(context.TODO(), new(types.StateInfo0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
|
||||
}
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -136,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version builtin.Version) (*StateTree, erro
|
||||
return &StateTree{
|
||||
root: root,
|
||||
info: info,
|
||||
version: version,
|
||||
version: ver,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
@@ -148,30 +175,31 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
||||
if err := cst.Get(context.TODO(), c, &root); err != nil {
|
||||
// We failed to decode as the new version, must be an old version.
|
||||
root.Actors = c
|
||||
root.Version = builtin.Version0
|
||||
}
|
||||
|
||||
// If that fails, load as an old-style state-tree (direct hampt, version 0.
|
||||
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, builtin.Version(root.Version))
|
||||
if err != nil {
|
||||
log.Errorf("loading hamt node %s failed: %s", c, err)
|
||||
return nil, err
|
||||
root.Version = types.StateTreeVersion0
|
||||
}
|
||||
|
||||
switch root.Version {
|
||||
case builtin.Version0:
|
||||
// supported
|
||||
case types.StateTreeVersion0, types.StateTreeVersion1:
|
||||
// Load the actual state-tree HAMT.
|
||||
nd, err := adt.AsMap(
|
||||
adt.WrapStore(context.TODO(), cst), root.Actors,
|
||||
adtForSTVersion(root.Version),
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("loading hamt node %s failed: %s", c, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &StateTree{
|
||||
root: nd,
|
||||
info: root.Info,
|
||||
version: root.Version,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", root.Version)
|
||||
}
|
||||
|
||||
return &StateTree{
|
||||
root: nd,
|
||||
info: root.Info,
|
||||
version: builtin.Version(root.Version),
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error {
|
||||
@@ -305,11 +333,11 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) {
|
||||
return cid.Undef, xerrors.Errorf("failed to flush state-tree hamt: %w", err)
|
||||
}
|
||||
// If we're version 0, return a raw tree.
|
||||
if st.version == builtin.Version0 {
|
||||
if st.version == types.StateTreeVersion0 {
|
||||
return root, nil
|
||||
}
|
||||
// Otherwise, return a versioned tree.
|
||||
return st.Store.Put(ctx, &types.StateRoot{Version: uint64(st.version), Actors: root, Info: st.info})
|
||||
return st.Store.Put(ctx, &types.StateRoot{Version: st.version, Actors: root, Info: st.info})
|
||||
}
|
||||
|
||||
func (st *StateTree) Snapshot(ctx context.Context) error {
|
||||
@@ -385,6 +413,7 @@ func (st *StateTree) MutateActor(addr address.Address, f func(*types.Actor) erro
|
||||
func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error {
|
||||
var act types.Actor
|
||||
return st.root.ForEach(&act, func(k string) error {
|
||||
act := act // copy
|
||||
addr, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("invalid address (%x) found in state tree key: %w", []byte(k), err)
|
||||
@@ -394,6 +423,11 @@ func (st *StateTree) ForEach(f func(address.Address, *types.Actor) error) error
|
||||
})
|
||||
}
|
||||
|
||||
// Version returns the version of the StateTree data structure in use.
|
||||
func (st *StateTree) Version() types.StateTreeVersion {
|
||||
return st.version
|
||||
}
|
||||
|
||||
func Diff(oldTree, newTree *StateTree) (map[string]types.Actor, error) {
|
||||
out := map[string]types.Actor{}
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func BenchmarkStateTreeSet(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
|
||||
func TestSetCache(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func TestSetCache(t *testing.T) {
|
||||
func TestSnapshots(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -237,7 +237,8 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
||||
|
||||
func TestStateTreeConsistency(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, builtin2.VersionForNetwork(build.NewestNetworkVersion))
|
||||
// TODO: ActorUpgrade: this test tests pre actors v2
|
||||
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+62
-18
@@ -2,10 +2,10 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -18,14 +18,47 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, r vm.Rand, bheight abi.ChainEpoch) (*api.InvocResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
|
||||
var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at epoch")
|
||||
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.Call")
|
||||
defer span.End()
|
||||
|
||||
// If no tipset is provided, try to find one without a fork.
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
|
||||
// Search back till we find a height with no fork, or we reach the beginning.
|
||||
for ts.Height() > 0 && sm.hasExpensiveFork(ctx, ts.Height()-1) {
|
||||
var err error
|
||||
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bstate := ts.ParentState()
|
||||
bheight := ts.Height()
|
||||
|
||||
// If we have to run an expensive migration, and we're not at genesis,
|
||||
// return an error because the migration will take too long.
|
||||
//
|
||||
// We allow this at height 0 for at-genesis migrations (for testing).
|
||||
if bheight-1 > 0 && sm.hasExpensiveFork(ctx, bheight-1) {
|
||||
return nil, ErrExpensiveFork
|
||||
}
|
||||
|
||||
// Run the (not expensive) migration.
|
||||
bstate, err := sm.handleStateForks(ctx, bstate, bheight-1, nil, ts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||
}
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: bstate,
|
||||
Epoch: bheight,
|
||||
Rand: r,
|
||||
Rand: store.NewChainRand(sm.cs, ts.Cids()),
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
@@ -33,7 +66,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
BaseFee: types.NewInt(0),
|
||||
}
|
||||
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
@@ -89,24 +122,30 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
|
||||
}
|
||||
|
||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
state := ts.ParentState()
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
return sm.CallRaw(ctx, msg, state, r, ts.Height())
|
||||
}
|
||||
|
||||
func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas")
|
||||
defer span.End()
|
||||
|
||||
if ts == nil {
|
||||
ts = sm.cs.GetHeaviestTipSet()
|
||||
|
||||
// Search back till we find a height with no fork, or we reach the beginning.
|
||||
// We need the _previous_ height to have no fork, because we'll
|
||||
// run the fork logic in `sm.TipSetState`. We need the _current_
|
||||
// height to have no fork, because we'll run it inside this
|
||||
// function before executing the given message.
|
||||
for ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||
var err error
|
||||
ts, err = sm.cs.GetTipSetFromKey(ts.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to find a non-forking epoch: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When we're not at the genesis block, make sure we don't have an expensive migration.
|
||||
if ts.Height() > 0 && (sm.hasExpensiveFork(ctx, ts.Height()) || sm.hasExpensiveFork(ctx, ts.Height()-1)) {
|
||||
return nil, ErrExpensiveFork
|
||||
}
|
||||
|
||||
state, _, err := sm.TipSetState(ctx, ts)
|
||||
@@ -114,6 +153,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
return nil, xerrors.Errorf("computing tipset state: %w", err)
|
||||
}
|
||||
|
||||
state, err = sm.handleStateForks(ctx, state, ts.Height(), nil, ts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to handle fork: %w", err)
|
||||
}
|
||||
|
||||
r := store.NewChainRand(sm.cs, ts.Cids())
|
||||
|
||||
if span.IsRecordingEvents() {
|
||||
@@ -134,7 +178,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up vm: %w", err)
|
||||
}
|
||||
|
||||
+600
-52
@@ -1,42 +1,172 @@
|
||||
package stmgr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
|
||||
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
|
||||
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"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"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/bufbstore"
|
||||
)
|
||||
|
||||
var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree, *types.TipSet) error{
|
||||
build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery,
|
||||
// UpgradeFunc is a migration function run at every upgrade.
|
||||
//
|
||||
// - The oldState is the state produced by the upgrade epoch.
|
||||
// - The returned newState is the new state that will be used by the next epoch.
|
||||
// - The height is the upgrade epoch height (already executed).
|
||||
// - The tipset is the tipset for the last non-null block before the upgrade. Do
|
||||
// not assume that ts.Height() is the upgrade height.
|
||||
type UpgradeFunc func(ctx context.Context, sm *StateManager, cb ExecCallback, oldState cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (newState cid.Cid, err error)
|
||||
|
||||
type Upgrade struct {
|
||||
Height abi.ChainEpoch
|
||||
Network network.Version
|
||||
Expensive bool
|
||||
Migration UpgradeFunc
|
||||
}
|
||||
|
||||
func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch, ts *types.TipSet) (err error) {
|
||||
f, ok := ForksAtHeight[height]
|
||||
if ok {
|
||||
err := f(ctx, sm, st, ts)
|
||||
if err != nil {
|
||||
return err
|
||||
type UpgradeSchedule []Upgrade
|
||||
|
||||
func DefaultUpgradeSchedule() UpgradeSchedule {
|
||||
var us UpgradeSchedule
|
||||
|
||||
updates := []Upgrade{{
|
||||
Height: build.UpgradeBreezeHeight,
|
||||
Network: network.Version1,
|
||||
Migration: UpgradeFaucetBurnRecovery,
|
||||
}, {
|
||||
Height: build.UpgradeSmokeHeight,
|
||||
Network: network.Version2,
|
||||
Migration: nil,
|
||||
}, {
|
||||
Height: build.UpgradeIgnitionHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeIgnition,
|
||||
}, {
|
||||
Height: build.UpgradeRefuelHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeRefuel,
|
||||
}, {
|
||||
Height: build.UpgradeActorsV2Height,
|
||||
Network: network.Version4,
|
||||
Expensive: true,
|
||||
Migration: UpgradeActorsV2,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version4,
|
||||
Migration: UpgradeLiftoff,
|
||||
}}
|
||||
|
||||
if build.UpgradeActorsV2Height == math.MaxInt64 { // disable actors upgrade
|
||||
updates = []Upgrade{{
|
||||
Height: build.UpgradeBreezeHeight,
|
||||
Network: network.Version1,
|
||||
Migration: UpgradeFaucetBurnRecovery,
|
||||
}, {
|
||||
Height: build.UpgradeSmokeHeight,
|
||||
Network: network.Version2,
|
||||
Migration: nil,
|
||||
}, {
|
||||
Height: build.UpgradeIgnitionHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeIgnition,
|
||||
}, {
|
||||
Height: build.UpgradeRefuelHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeRefuel,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version3,
|
||||
Migration: UpgradeLiftoff,
|
||||
}}
|
||||
}
|
||||
|
||||
for _, u := range updates {
|
||||
if u.Height < 0 {
|
||||
// upgrade disabled
|
||||
continue
|
||||
}
|
||||
us = append(us, u)
|
||||
}
|
||||
return us
|
||||
}
|
||||
|
||||
func (us UpgradeSchedule) Validate() error {
|
||||
// Make sure we're not trying to upgrade to version 0.
|
||||
for _, u := range us {
|
||||
if u.Network <= 0 {
|
||||
return xerrors.Errorf("cannot upgrade to version <= 0: %d", u.Network)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all the upgrades make sense.
|
||||
for i := 1; i < len(us); i++ {
|
||||
prev := &us[i-1]
|
||||
curr := &us[i]
|
||||
if !(prev.Network <= curr.Network) {
|
||||
return xerrors.Errorf("cannot downgrade from version %d to version %d", prev.Network, curr.Network)
|
||||
}
|
||||
// Make sure the heights make sense.
|
||||
if prev.Height < 0 {
|
||||
// Previous upgrade was disabled.
|
||||
continue
|
||||
}
|
||||
if !(prev.Height < curr.Height) {
|
||||
return xerrors.Errorf("upgrade heights must be strictly increasing: upgrade %d was at height %d, followed by upgrade %d at height %d", i-1, prev.Height, i, curr.Height)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type forEachTree interface {
|
||||
ForEach(func(address.Address, *types.Actor) error) error
|
||||
func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, height abi.ChainEpoch, cb ExecCallback, ts *types.TipSet) (cid.Cid, error) {
|
||||
retCid := root
|
||||
var err error
|
||||
f, ok := sm.stateMigrations[height]
|
||||
if ok {
|
||||
retCid, err = f(ctx, sm, cb, root, height, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
|
||||
return retCid, nil
|
||||
}
|
||||
|
||||
func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||
func (sm *StateManager) hasExpensiveFork(ctx context.Context, height abi.ChainEpoch) bool {
|
||||
_, ok := sm.expensiveUpgrades[height]
|
||||
return ok
|
||||
}
|
||||
|
||||
func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error {
|
||||
fromAct, err := tree.GetActor(from)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
||||
@@ -62,10 +192,43 @@ func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmo
|
||||
return xerrors.Errorf("failed to persist to actor: %w", err)
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
// record the transfer in execution traces
|
||||
|
||||
fakeMsg := &types.Message{
|
||||
From: from,
|
||||
To: to,
|
||||
Value: amt,
|
||||
Nonce: math.MaxUint64,
|
||||
}
|
||||
fakeRct := &types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
Return: nil,
|
||||
GasUsed: 0,
|
||||
}
|
||||
|
||||
if err := cb(fakeMsg.Cid(), fakeMsg, &vm.ApplyRet{
|
||||
MessageReceipt: *fakeRct,
|
||||
ActorErr: nil,
|
||||
ExecutionTrace: types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: nil,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return xerrors.Errorf("recording transfer: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree, ts *types.TipSet) error {
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
// Some initial parameters
|
||||
FundsForMiners := types.FromFil(1_000_000)
|
||||
LookbackEpoch := abi.ChainEpoch(32000)
|
||||
@@ -92,22 +255,22 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
// Grab lookback state for account checks
|
||||
lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, ts, false)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get tipset at lookback height: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to get tipset at lookback height: %w", err)
|
||||
}
|
||||
|
||||
lbtree, err := sm.ParentState(lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading state tree failed: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
|
||||
}
|
||||
|
||||
ReserveAddress, err := address.NewFromString("t090")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse reserve address: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
|
||||
}
|
||||
|
||||
fetree, ok := tree.(forEachTree)
|
||||
if !ok {
|
||||
return xerrors.Errorf("fork transition state tree doesnt support ForEach (%T)", tree)
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
type transfer struct {
|
||||
@@ -119,9 +282,9 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
var transfers []transfer
|
||||
|
||||
// Take all excess funds away, put them into the reserve account
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
switch act.Code {
|
||||
case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID:
|
||||
case builtin0.AccountActorCodeID, builtin0.MultisigActorCodeID, builtin0.PaymentChannelActorCodeID:
|
||||
sysAcc, err := isSystemAccount(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking system account: %w", err)
|
||||
@@ -134,7 +297,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
Amt: act.Balance,
|
||||
})
|
||||
}
|
||||
case builtin.StorageMinerActorCodeID:
|
||||
case builtin0.StorageMinerActorCodeID:
|
||||
var st miner0.State
|
||||
if err := sm.ChainStore().Store(ctx).Get(ctx, act.Head, &st); err != nil {
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
@@ -161,33 +324,33 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
}
|
||||
|
||||
// Execute transfers from previous step
|
||||
for _, t := range transfers {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil {
|
||||
return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
|
||||
// pull up power table to give miners back some funds proportional to their power
|
||||
var ps power0.State
|
||||
powAct, err := tree.GetActor(builtin.StoragePowerActorAddr)
|
||||
powAct, err := tree.GetActor(builtin0.StoragePowerActorAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load power actor: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
if err := cst.Get(ctx, powAct.Head, &ps); err != nil {
|
||||
return xerrors.Errorf("failed to get power actor state: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to get power actor state: %w", err)
|
||||
}
|
||||
|
||||
totalPower := ps.TotalBytesCommitted
|
||||
|
||||
var transfersBack []transfer
|
||||
// Now, we return some funds to places where they are needed
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
lbact, err := lbtree.GetActor(addr)
|
||||
if err != nil {
|
||||
if !xerrors.Is(err, types.ErrActorNotFound) {
|
||||
@@ -201,7 +364,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
}
|
||||
|
||||
switch act.Code {
|
||||
case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID:
|
||||
case builtin0.AccountActorCodeID, builtin0.MultisigActorCodeID, builtin0.PaymentChannelActorCodeID:
|
||||
nbalance := big.Min(prevBalance, AccountCap)
|
||||
if nbalance.Sign() != 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
@@ -210,7 +373,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
Amt: nbalance,
|
||||
})
|
||||
}
|
||||
case builtin.StorageMinerActorCodeID:
|
||||
case builtin0.StorageMinerActorCodeID:
|
||||
var st miner0.State
|
||||
if err := sm.ChainStore().Store(ctx).Get(ctx, act.Head, &st); err != nil {
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
@@ -221,7 +384,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
return xerrors.Errorf("failed to get miner info: %w", err)
|
||||
}
|
||||
|
||||
sectorsArr, err := adt.AsArray(sm.ChainStore().Store(ctx), st.Sectors)
|
||||
sectorsArr, err := adt0.AsArray(sm.ChainStore().Store(ctx), st.Sectors)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load sectors array: %w", err)
|
||||
}
|
||||
@@ -245,7 +408,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
return xerrors.Errorf("failed to load miner state: %w", err)
|
||||
}
|
||||
|
||||
lbsectors, err := adt.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors)
|
||||
lbsectors, err := adt0.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load lb sectors array: %w", err)
|
||||
}
|
||||
@@ -265,53 +428,438 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("foreach over state tree failed: %w", err)
|
||||
}
|
||||
|
||||
for _, t := range transfersBack {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil {
|
||||
return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
|
||||
// transfer all burnt funds back to the reserve account
|
||||
burntAct, err := tree.GetActor(builtin.BurntFundsActorAddr)
|
||||
burntAct, err := tree.GetActor(builtin0.BurntFundsActorAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||
}
|
||||
if err := doTransfer(tree, builtin.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
||||
return xerrors.Errorf("failed to unburn funds: %w", err)
|
||||
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
||||
}
|
||||
|
||||
// Top up the reimbursement service
|
||||
reimbAddr, err := address.NewFromString("t0111")
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to parse reimbursement service address")
|
||||
return cid.Undef, xerrors.Errorf("failed to parse reimbursement service address")
|
||||
}
|
||||
|
||||
reimb, err := tree.GetActor(reimbAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load reimbursement account actor: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("failed to load reimbursement account actor: %w", err)
|
||||
}
|
||||
|
||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||
if err := doTransfer(tree, ReserveAddress, reimbAddr, difference); err != nil {
|
||||
return xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||
}
|
||||
|
||||
// Now, a final sanity check to make sure the balances all check out
|
||||
total := abi.NewTokenAmount(0)
|
||||
err = fetree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
total = types.BigAdd(total, act.Balance)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("checking final state balance failed: %w", err)
|
||||
return cid.Undef, xerrors.Errorf("checking final state balance failed: %w", err)
|
||||
}
|
||||
|
||||
exp := types.FromFil(build.FilBase)
|
||||
if !exp.Equals(total) {
|
||||
return xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
|
||||
return cid.Undef, xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
store := sm.cs.Store(ctx)
|
||||
|
||||
if build.UpgradeLiftoffHeight <= epoch {
|
||||
return cid.Undef, xerrors.Errorf("liftoff height must be beyond ignition height")
|
||||
}
|
||||
|
||||
nst, err := nv3.MigrateStateTree(ctx, store, root, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("migrating actors state: %w", err)
|
||||
}
|
||||
|
||||
tree, err := sm.StateTree(nst)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
err = setNetworkName(ctx, store, tree, "ignition")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
||||
}
|
||||
|
||||
split1, err := address.NewFromString("t0115")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("first split address: %w", err)
|
||||
}
|
||||
|
||||
split2, err := address.NewFromString("t0116")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("second split address: %w", err)
|
||||
}
|
||||
|
||||
err = resetGenesisMsigs(ctx, sm, store, tree, build.UpgradeLiftoffHeight)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("resetting genesis msig start epochs: %w", err)
|
||||
}
|
||||
|
||||
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting first msig: %w", err)
|
||||
}
|
||||
|
||||
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
|
||||
}
|
||||
|
||||
err = nv3.CheckStateTree(ctx, store, nst, epoch, builtin0.TotalFilecoin)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("sanity check after ignition upgrade failed: %w", err)
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
|
||||
store := sm.cs.Store(ctx)
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString("t0122")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting address: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, addr, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.ReserveAddress, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.RootVerifierAddress, 0, 0, big.Zero())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("tweaking msig vesting: %w", err)
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
buf := bufbstore.NewTieredBstore(sm.cs.Blockstore(), bstore.NewTemporarySync())
|
||||
store := store.ActorStore(ctx, buf)
|
||||
|
||||
info, err := store.Put(ctx, new(types.StateInfo0))
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to create new state info for actors v2: %w", err)
|
||||
}
|
||||
|
||||
newHamtRoot, err := m2.MigrateStateTree(ctx, store, root, epoch, m2.DefaultConfig())
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("upgrading to actors v2: %w", err)
|
||||
}
|
||||
|
||||
newStateTree, err := states2.LoadTree(store, newHamtRoot)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load new state tree: %w", err)
|
||||
}
|
||||
|
||||
// Check all state-tree invariants.
|
||||
if msgs, err := states2.CheckStateInvariants(newStateTree, types.TotalFilecoinInt); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to check new state tree: %w", err)
|
||||
} else if !msgs.IsEmpty() {
|
||||
// This error is going to be really nasty.
|
||||
return cid.Undef, xerrors.Errorf("network upgrade failed: %v", msgs.Messages())
|
||||
}
|
||||
|
||||
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||
Version: types.StateTreeVersion1,
|
||||
Actors: newHamtRoot,
|
||||
Info: info,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err)
|
||||
}
|
||||
|
||||
// perform some basic sanity checks to make sure everything still works.
|
||||
if newSm, err := state.LoadStateTree(store, newRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("state tree sanity load failed: %w", err)
|
||||
} else if newRoot2, err := newSm.Flush(ctx); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("state tree sanity flush failed: %w", err)
|
||||
} else if newRoot2 != newRoot {
|
||||
return cid.Undef, xerrors.Errorf("state-root mismatch: %s != %s", newRoot, newRoot2)
|
||||
} else if _, err := newSm.GetActor(builtin0.InitActorAddr); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load init actor after upgrade: %w", err)
|
||||
}
|
||||
|
||||
{
|
||||
from := buf
|
||||
to := buf.Read()
|
||||
|
||||
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
func UpgradeLiftoff(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
err = setNetworkName(ctx, sm.cs.Store(ctx), tree, "mainnet")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("setting network name: %w", err)
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree, name string) error {
|
||||
ia, err := tree.GetActor(builtin0.InitActorAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting init actor: %w", err)
|
||||
}
|
||||
|
||||
initState, err := init_.Load(store, ia)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("reading init state: %w", err)
|
||||
}
|
||||
|
||||
if err := initState.SetNetworkName(name); err != nil {
|
||||
return xerrors.Errorf("setting network name: %w", err)
|
||||
}
|
||||
|
||||
ia.Head, err = store.Put(ctx, initState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing new init state: %w", err)
|
||||
}
|
||||
|
||||
if err := tree.SetActor(builtin0.InitActorAddr, ia); err != nil {
|
||||
return xerrors.Errorf("setting init actor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64) error {
|
||||
if portions < 1 {
|
||||
return xerrors.Errorf("cannot split into 0 portions")
|
||||
}
|
||||
|
||||
mact, err := tree.GetActor(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig actor: %w", err)
|
||||
}
|
||||
|
||||
mst, err := multisig.Load(store, mact)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig state: %w", err)
|
||||
}
|
||||
|
||||
signers, err := mst.Signers()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig signers: %w", err)
|
||||
}
|
||||
|
||||
thresh, err := mst.Threshold()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig threshold: %w", err)
|
||||
}
|
||||
|
||||
ibal, err := mst.InitialBalance()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig initial balance: %w", err)
|
||||
}
|
||||
|
||||
se, err := mst.StartEpoch()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig start epoch: %w", err)
|
||||
}
|
||||
|
||||
ud, err := mst.UnlockDuration()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting msig unlock duration: %w", err)
|
||||
}
|
||||
|
||||
pending, err := adt0.MakeEmptyMap(store).Root()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create empty map: %w", err)
|
||||
}
|
||||
|
||||
newIbal := big.Div(ibal, types.NewInt(portions))
|
||||
newState := &multisig0.State{
|
||||
Signers: signers,
|
||||
NumApprovalsThreshold: thresh,
|
||||
NextTxnID: 0,
|
||||
InitialBalance: newIbal,
|
||||
StartEpoch: se,
|
||||
UnlockDuration: ud,
|
||||
PendingTxns: pending,
|
||||
}
|
||||
|
||||
scid, err := store.Put(ctx, newState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("storing new state: %w", err)
|
||||
}
|
||||
|
||||
newActor := types.Actor{
|
||||
Code: builtin0.MultisigActorCodeID,
|
||||
Head: scid,
|
||||
Nonce: 0,
|
||||
Balance: big.Zero(),
|
||||
}
|
||||
|
||||
i := uint64(0)
|
||||
for i < portions {
|
||||
keyAddr, err := makeKeyAddr(addr, i)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("creating key address: %w", err)
|
||||
}
|
||||
|
||||
idAddr, err := tree.RegisterNewAddress(keyAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("registering new address: %w", err)
|
||||
}
|
||||
|
||||
err = tree.SetActor(idAddr, &newActor)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting new msig actor state: %w", err)
|
||||
}
|
||||
|
||||
if err := doTransfer(cb, tree, addr, idAddr, newIbal); err != nil {
|
||||
return xerrors.Errorf("transferring split msig balance: %w", err)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, error) {
|
||||
var b bytes.Buffer
|
||||
if err := splitAddr.MarshalCBOR(&b); err != nil {
|
||||
return address.Undef, xerrors.Errorf("marshalling split address: %w", err)
|
||||
}
|
||||
|
||||
if err := binary.Write(&b, binary.BigEndian, count); err != nil {
|
||||
return address.Undef, xerrors.Errorf("writing count into a buffer: %w", err)
|
||||
}
|
||||
|
||||
if err := binary.Write(&b, binary.BigEndian, []byte("Ignition upgrade")); err != nil {
|
||||
return address.Undef, xerrors.Errorf("writing fork name into a buffer: %w", err)
|
||||
}
|
||||
|
||||
addr, err := address.NewActorAddress(b.Bytes())
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("create actor address: %w", err)
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// TODO: After the Liftoff epoch, refactor this to use resetMultisigVesting
|
||||
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree, startEpoch abi.ChainEpoch) 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)
|
||||
}
|
||||
|
||||
cst := cbor.NewCborStore(sm.cs.Blockstore())
|
||||
genesisTree, err := state.LoadStateTree(cst, gts.ParentState())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading state tree: %w", err)
|
||||
}
|
||||
|
||||
err = genesisTree.ForEach(func(addr address.Address, genesisActor *types.Actor) error {
|
||||
if genesisActor.Code == builtin0.MultisigActorCodeID {
|
||||
currActor, err := tree.GetActor(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading actor: %w", err)
|
||||
}
|
||||
|
||||
var currState multisig0.State
|
||||
if err := store.Get(ctx, currActor.Head, &currState); err != nil {
|
||||
return xerrors.Errorf("reading multisig state: %w", err)
|
||||
}
|
||||
|
||||
currState.StartEpoch = startEpoch
|
||||
|
||||
currActor.Head, err = store.Put(ctx, &currState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing new multisig state: %w", err)
|
||||
}
|
||||
|
||||
if err := tree.SetActor(addr, currActor); err != nil {
|
||||
return xerrors.Errorf("setting multisig actor: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("iterating over genesis actors: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetMultisigVesting(ctx context.Context, store adt0.Store, tree *state.StateTree, addr address.Address, startEpoch abi.ChainEpoch, duration abi.ChainEpoch, balance abi.TokenAmount) error {
|
||||
act, err := tree.GetActor(addr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting actor: %w", err)
|
||||
}
|
||||
|
||||
if !builtin.IsMultisigActor(act.Code) {
|
||||
return xerrors.Errorf("actor wasn't msig: %w", err)
|
||||
}
|
||||
|
||||
var msigState multisig0.State
|
||||
if err := store.Get(ctx, act.Head, &msigState); err != nil {
|
||||
return xerrors.Errorf("reading multisig state: %w", err)
|
||||
}
|
||||
|
||||
msigState.StartEpoch = startEpoch
|
||||
msigState.UnlockDuration = duration
|
||||
msigState.InitialBalance = balance
|
||||
|
||||
act.Head, err = store.Put(ctx, &msigState)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing new multisig state: %w", err)
|
||||
}
|
||||
|
||||
if err := tree.SetActor(addr, act); err != nil {
|
||||
return xerrors.Errorf("setting multisig actor: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+135
-41
@@ -8,36 +8,34 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
||||
lotusinit "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
. "github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"github.com/ipfs/go-cid"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg0.MinVerifiedDealSize = big.NewInt(256)
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
const testForkHeight = 40
|
||||
@@ -45,6 +43,10 @@ const testForkHeight = 40
|
||||
type testActor struct {
|
||||
}
|
||||
|
||||
// must use existing actor that an account is allowed to exec.
|
||||
func (testActor) Code() cid.Cid { return builtin.PaymentChannelActorCodeID }
|
||||
func (testActor) State() cbor.Er { return new(testActorState) }
|
||||
|
||||
type testActorState struct {
|
||||
HasUpgraded uint64
|
||||
}
|
||||
@@ -65,7 +67,7 @@ func (tas *testActorState) UnmarshalCBOR(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ta *testActor) Exports() []interface{} {
|
||||
func (ta testActor) Exports() []interface{} {
|
||||
return []interface{}{
|
||||
1: ta.Constructor,
|
||||
2: ta.TestMethod,
|
||||
@@ -75,7 +77,7 @@ func (ta *testActor) Exports() []interface{} {
|
||||
func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue {
|
||||
rt.ValidateImmediateCallerAcceptAny()
|
||||
rt.StateCreate(&testActorState{11})
|
||||
fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
//fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Receiver())
|
||||
|
||||
return abi.Empty
|
||||
}
|
||||
@@ -108,46 +110,57 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sm := NewStateManager(cg.ChainStore())
|
||||
|
||||
inv := vm.NewInvoker()
|
||||
|
||||
// predicting the address here... may break if other assumptions change
|
||||
taddr, err := address.NewIDAddress(1002)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree, ts *types.TipSet) error {
|
||||
cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
Network: 1,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
cst := ipldcbor.NewCborStore(sm.ChainStore().Blockstore())
|
||||
|
||||
act, err := st.GetActor(taddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
var tas testActorState
|
||||
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
||||
return xerrors.Errorf("in fork handler, failed to run get: %w", err)
|
||||
}
|
||||
act, err := st.GetActor(taddr)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
tas.HasUpgraded = 55
|
||||
var tas testActorState
|
||||
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err)
|
||||
}
|
||||
|
||||
ns, err := cst.Put(ctx, &tas)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tas.HasUpgraded = 55
|
||||
|
||||
act.Head = ns
|
||||
ns, err := cst.Put(ctx, &tas)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
if err := st.SetActor(taddr, act); err != nil {
|
||||
return err
|
||||
}
|
||||
act.Head = ns
|
||||
|
||||
return nil
|
||||
if err := st.SetActor(taddr, act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return st.Flush(ctx)
|
||||
}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{})
|
||||
inv := vm.NewActorRegistry()
|
||||
inv.Register(nil, testActor{})
|
||||
|
||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
@@ -161,14 +174,14 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
|
||||
var msgs []*types.SignedMessage
|
||||
|
||||
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: builtin.PaymentChannelActorCodeID})
|
||||
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
From: cg.Banker(),
|
||||
To: builtin.InitActorAddr,
|
||||
To: lotusinit.Address,
|
||||
Method: builtin.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
GasLimit: types.TestGasLimit,
|
||||
@@ -221,3 +234,84 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestForkRefuseCall(t *testing.T) {
|
||||
logging.SetAllLoggers(logging.LevelInfo)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
cg, err := gen.NewGenerator()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(
|
||||
cg.ChainStore(), UpgradeSchedule{{
|
||||
Network: 1,
|
||||
Expensive: true,
|
||||
Height: testForkHeight,
|
||||
Migration: func(ctx context.Context, sm *StateManager, cb ExecCallback,
|
||||
root cid.Cid, height abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
return root, nil
|
||||
}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inv := vm.NewActorRegistry()
|
||||
inv.Register(nil, testActor{})
|
||||
|
||||
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (*vm.VM, error) {
|
||||
nvm, err := vm.NewVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nvm.SetInvoker(inv)
|
||||
return nvm, nil
|
||||
})
|
||||
|
||||
cg.SetStateManager(sm)
|
||||
|
||||
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := &types.Message{
|
||||
From: cg.Banker(),
|
||||
To: lotusinit.Address,
|
||||
Method: builtin.MethodsInit.Exec,
|
||||
Params: enc,
|
||||
GasLimit: types.TestGasLimit,
|
||||
Value: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
ts, err := cg.NextTipSet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := sm.CallWithGas(ctx, m, nil, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight, testForkHeight + 1:
|
||||
// If I had a fork, or I _will_ have a fork, it should fail.
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
// Call just runs on the parent state for a tipset, so we only
|
||||
// expect an error at the fork height.
|
||||
ret, err = sm.Call(ctx, m, ts.TipSet.TipSet())
|
||||
switch ts.TipSet.TipSet().Height() {
|
||||
case testForkHeight + 1:
|
||||
require.Equal(t, ErrExpensiveFork, err)
|
||||
default:
|
||||
require.NoError(t, err)
|
||||
require.True(t, ret.MsgRct.ExitCode.IsSuccess())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+364
-165
@@ -2,15 +2,15 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -22,16 +22,16 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
"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/adt"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -40,24 +40,83 @@ import (
|
||||
|
||||
var log = logging.Logger("statemgr")
|
||||
|
||||
type versionSpec struct {
|
||||
networkVersion network.Version
|
||||
atOrBelow abi.ChainEpoch
|
||||
}
|
||||
|
||||
type StateManager struct {
|
||||
cs *store.ChainStore
|
||||
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
stlk sync.Mutex
|
||||
genesisMsigLk sync.Mutex
|
||||
newVM func(context.Context, *vm.VMOpts) (*vm.VM, error)
|
||||
genInfo *genesisInfo
|
||||
// Determines the network version at any given epoch.
|
||||
networkVersions []versionSpec
|
||||
latestVersion network.Version
|
||||
|
||||
// Maps chain epochs to upgrade functions.
|
||||
stateMigrations map[abi.ChainEpoch]UpgradeFunc
|
||||
// A set of potentially expensive/time consuming upgrades. Explicit
|
||||
// calls for, e.g., gas estimation fail against this epoch with
|
||||
// ErrExpensiveFork.
|
||||
expensiveUpgrades map[abi.ChainEpoch]struct{}
|
||||
|
||||
stCache map[string][]cid.Cid
|
||||
compWait map[string]chan struct{}
|
||||
stlk sync.Mutex
|
||||
genesisMsigLk sync.Mutex
|
||||
newVM func(context.Context, *vm.VMOpts) (*vm.VM, error)
|
||||
preIgnitionGenInfos *genesisInfo
|
||||
postIgnitionGenInfos *genesisInfo
|
||||
}
|
||||
|
||||
func NewStateManager(cs *store.ChainStore) *StateManager {
|
||||
return &StateManager{
|
||||
newVM: vm.NewVM,
|
||||
cs: cs,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
compWait: make(map[string]chan struct{}),
|
||||
sm, err := NewStateManagerWithUpgradeSchedule(cs, DefaultUpgradeSchedule())
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("default upgrade schedule is invalid: %s", err))
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
func NewStateManagerWithUpgradeSchedule(cs *store.ChainStore, us UpgradeSchedule) (*StateManager, error) {
|
||||
// If we have upgrades, make sure they're in-order and make sense.
|
||||
if err := us.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stateMigrations := make(map[abi.ChainEpoch]UpgradeFunc, len(us))
|
||||
expensiveUpgrades := make(map[abi.ChainEpoch]struct{}, len(us))
|
||||
var networkVersions []versionSpec
|
||||
lastVersion := network.Version0
|
||||
if len(us) > 0 {
|
||||
// If we have any upgrades, process them and create a version
|
||||
// schedule.
|
||||
for _, upgrade := range us {
|
||||
if upgrade.Migration != nil {
|
||||
stateMigrations[upgrade.Height] = upgrade.Migration
|
||||
}
|
||||
if upgrade.Expensive {
|
||||
expensiveUpgrades[upgrade.Height] = struct{}{}
|
||||
}
|
||||
networkVersions = append(networkVersions, versionSpec{
|
||||
networkVersion: lastVersion,
|
||||
atOrBelow: upgrade.Height,
|
||||
})
|
||||
lastVersion = upgrade.Network
|
||||
}
|
||||
} else {
|
||||
// Otherwise, go directly to the latest version.
|
||||
lastVersion = build.NewestNetworkVersion
|
||||
}
|
||||
|
||||
return &StateManager{
|
||||
networkVersions: networkVersions,
|
||||
latestVersion: lastVersion,
|
||||
stateMigrations: stateMigrations,
|
||||
expensiveUpgrades: expensiveUpgrades,
|
||||
newVM: vm.NewVM,
|
||||
cs: cs,
|
||||
stCache: make(map[string][]cid.Cid),
|
||||
compWait: make(map[string]chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func cidsToKey(cids []cid.Cid) string {
|
||||
@@ -125,9 +184,8 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
|
||||
return st, rec, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||
var trace []*api.InvocResult
|
||||
st, _, err := sm.computeTipSetState(ctx, ts, func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||
func traceFunc(trace *[]*api.InvocResult) func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||
return func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
|
||||
ir := &api.InvocResult{
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
@@ -137,9 +195,14 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
|
||||
if ret.ActorErr != nil {
|
||||
ir.Error = ret.ActorErr.Error()
|
||||
}
|
||||
trace = append(trace, ir)
|
||||
*trace = append(*trace, ir)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||
var trace []*api.InvocResult
|
||||
st, _, err := sm.computeTipSetState(ctx, ts, traceFunc(&trace))
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
@@ -151,38 +214,42 @@ type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
|
||||
|
||||
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) {
|
||||
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: pstate,
|
||||
Epoch: epoch,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
makeVmWithBaseState := func(base cid.Cid) (*vm.VM, error) {
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: epoch,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
}
|
||||
|
||||
return sm.newVM(ctx, vmopt)
|
||||
}
|
||||
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
vmi, err := makeVmWithBaseState(pstate)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
|
||||
}
|
||||
|
||||
runCron := func() error {
|
||||
// TODO: this nonce-getting is a tiny bit ugly
|
||||
ca, err := vmi.StateTree().GetActor(builtin.SystemActorAddr)
|
||||
ca, err := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cronMsg := &types.Message{
|
||||
To: builtin.CronActorAddr,
|
||||
From: builtin.SystemActorAddr,
|
||||
To: builtin0.CronActorAddr,
|
||||
From: builtin0.SystemActorAddr,
|
||||
Nonce: ca.Nonce,
|
||||
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: builtin.MethodsCron.EpochTick,
|
||||
Method: builtin0.MethodsCron.EpochTick,
|
||||
Params: nil,
|
||||
}
|
||||
ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
|
||||
@@ -202,21 +269,34 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
|
||||
for i := parentEpoch; i < epoch; i++ {
|
||||
if i > parentEpoch {
|
||||
// run cron for null rounds if any
|
||||
if err := runCron(); 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
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts)
|
||||
newState, err := sm.handleStateForks(ctx, pstate, i, cb, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
|
||||
if i > parentEpoch {
|
||||
// run cron for null rounds if any
|
||||
if err := runCron(); err != nil {
|
||||
return cid.Cid{}, cid.Cid{}, 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
|
||||
}
|
||||
|
||||
var receipts []cbg.CBORMarshaler
|
||||
@@ -247,43 +327,35 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
processedMsgs[m.Cid()] = true
|
||||
}
|
||||
|
||||
var params []byte
|
||||
|
||||
nv := sm.GetNtwkVersion(ctx, epoch)
|
||||
if nv < build.ActorUpgradeNetworkVersion {
|
||||
params, err = actors.SerializeParams(&reward0.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)
|
||||
}
|
||||
} else {
|
||||
// TODO: ActorUpgrade
|
||||
params = nil
|
||||
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)
|
||||
}
|
||||
|
||||
sysAct, err := vmi.StateTree().GetActor(builtin.SystemActorAddr)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", err)
|
||||
sysAct, actErr := vmi.StateTree().GetActor(builtin0.SystemActorAddr)
|
||||
if actErr != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get system actor: %w", actErr)
|
||||
}
|
||||
|
||||
rwMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: builtin.RewardActorAddr,
|
||||
From: builtin0.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: sysAct.Nonce,
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
GasLimit: 1 << 30,
|
||||
Method: builtin.MethodsReward.AwardBlockReward,
|
||||
Method: builtin0.MethodsReward.AwardBlockReward,
|
||||
Params: params,
|
||||
}
|
||||
ret, err := vmi.ApplyImplicitMessage(ctx, rwMsg)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to apply reward message for miner %s: %w", b.Miner, err)
|
||||
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 cb != nil {
|
||||
if err := cb(rwMsg.Cid(), rwMsg, ret); err != nil {
|
||||
@@ -300,7 +372,11 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
return cid.Cid{}, cid.Cid{}, err
|
||||
}
|
||||
|
||||
rectarr := adt.MakeEmptyArray(sm.cs.Store(ctx))
|
||||
// XXX: Is the height correct? Or should it be epoch-1?
|
||||
rectarr, err := adt.NewArray(sm.cs.Store(ctx), actors.VersionForNetwork(sm.GetNtwkVersion(ctx, epoch)))
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to create receipts amt: %w", err)
|
||||
}
|
||||
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)
|
||||
@@ -432,16 +508,7 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
return nil, fmt.Errorf("failed to load message: %w", err)
|
||||
}
|
||||
|
||||
r, _, err := sm.tipsetExecutedMessage(ts, msg, m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
_, r, _, err = sm.searchBackForMsg(ctx, ts, m)
|
||||
_, r, _, err := sm.searchBackForMsg(ctx, ts, m)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
||||
}
|
||||
@@ -599,6 +666,18 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
|
||||
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 cur.Height() == 0 {
|
||||
// it ain't here!
|
||||
@@ -611,32 +690,37 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet
|
||||
default:
|
||||
}
|
||||
|
||||
act, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Cid{}, err
|
||||
}
|
||||
|
||||
// we either have no messages from the sender, or the latest message we found has a lower nonce than the one being searched for,
|
||||
// either way, no reason to lookback, it ain't there
|
||||
if act.Nonce == 0 || act.Nonce < m.VMMessage().Nonce {
|
||||
if curActor == nil || curActor.Nonce == 0 || curActor.Nonce < mNonce {
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
|
||||
ts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
pts, err := sm.cs.LoadTipSet(cur.Parents())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load tipset during msg wait searchback: %w", err)
|
||||
}
|
||||
|
||||
r, foundMsg, err := sm.tipsetExecutedMessage(ts, m.Cid(), m.VMMessage())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, fmt.Errorf("checking for message execution during lookback: %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)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return ts, r, foundMsg, nil
|
||||
// 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())
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("checking for message execution during lookback: %w", err)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return pts, r, foundMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
cur = ts
|
||||
cur = pts
|
||||
curActor = act
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,17 +782,13 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := adt.AsMap(sm.cs.Store(ctx), st)
|
||||
stateTree, err := sm.StateTree(st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []address.Address
|
||||
err = r.ForEach(nil, func(k string) error {
|
||||
addr, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("address in state tree was not valid: %w", err)
|
||||
}
|
||||
err = stateTree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
out = append(out, addr)
|
||||
return nil
|
||||
})
|
||||
@@ -725,7 +805,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address,
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
|
||||
act, err := st.GetActor(builtin.StorageMarketActorAddr)
|
||||
act, err := st.GetActor(market.Address)
|
||||
if err != nil {
|
||||
return api.MarketBalance{}, err
|
||||
}
|
||||
@@ -845,51 +925,56 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
return xerrors.Errorf("setting up genesis pledge: %w", err)
|
||||
}
|
||||
|
||||
r, err := adt.AsMap(sm.cs.Store(ctx), st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting genesis actors: %w", err)
|
||||
}
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
var act types.Actor
|
||||
err = r.ForEach(&act, func(k string) error {
|
||||
if act.Code == builtin.MultisigActorCodeID {
|
||||
var s multisig.State
|
||||
err := sm.cs.Store(ctx).Get(ctx, act.Head, &s)
|
||||
err = sTree.ForEach(func(kaddr address.Address, act *types.Actor) error {
|
||||
if builtin.IsMultisigActor(act.Code) {
|
||||
s, err := multisig.Load(sm.cs.Store(ctx), act)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.StartEpoch() != 0 {
|
||||
se, err := s.StartEpoch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if se != 0 {
|
||||
return xerrors.New("genesis multisig doesn't start vesting at epoch 0!")
|
||||
}
|
||||
|
||||
ot, f := totalsByEpoch[s.UnlockDuration()]
|
||||
if f {
|
||||
totalsByEpoch[s.UnlockDuration()] = big.Add(ot, s.InitialBalance())
|
||||
} else {
|
||||
totalsByEpoch[s.UnlockDuration()] = s.InitialBalance()
|
||||
ud, err := s.UnlockDuration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else if act.Code == builtin.AccountActorCodeID {
|
||||
ib, err := s.InitialBalance()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ot, f := totalsByEpoch[ud]
|
||||
if f {
|
||||
totalsByEpoch[ud] = big.Add(ot, ib)
|
||||
} else {
|
||||
totalsByEpoch[ud] = ib
|
||||
}
|
||||
|
||||
} else if builtin.IsAccountActor(act.Code) {
|
||||
// should exclude burnt funds actor and "remainder account actor"
|
||||
// should only ever be "faucet" accounts in testnets
|
||||
kaddr, err := address.NewFromBytes([]byte(k))
|
||||
if kaddr == builtin0.BurntFundsActorAddr {
|
||||
return nil
|
||||
}
|
||||
|
||||
kid, err := sTree.LookupID(kaddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding address: %w", err)
|
||||
return xerrors.Errorf("resolving address: %w", err)
|
||||
}
|
||||
|
||||
if kaddr != builtin.BurntFundsActorAddr {
|
||||
kid, err := sTree.LookupID(kaddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("resolving address: %w", err)
|
||||
}
|
||||
|
||||
gi.genesisActors = append(gi.genesisActors, genesisActor{
|
||||
addr: kid,
|
||||
initBal: act.Balance,
|
||||
})
|
||||
}
|
||||
gi.genesisActors = append(gi.genesisActors, genesisActor{
|
||||
addr: kid,
|
||||
initBal: act.Balance,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -898,6 +983,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
return xerrors.Errorf("error setting up genesis infos: %w", err)
|
||||
}
|
||||
|
||||
// TODO: use network upgrade abstractions or always start at actors v0?
|
||||
gi.genesisMsigs = make([]msig0.State, 0, len(totalsByEpoch))
|
||||
for k, v := range totalsByEpoch {
|
||||
ns := msig0.State{
|
||||
@@ -908,7 +994,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
gi.genesisMsigs = append(gi.genesisMsigs, ns)
|
||||
}
|
||||
|
||||
sm.genInfo = &gi
|
||||
sm.preIgnitionGenInfos = &gi
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -916,7 +1002,7 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
|
||||
// sets up information about the actors in the genesis state
|
||||
// For testnet we use a hardcoded set of multisig states, instead of what's actually in the genesis multisigs
|
||||
// We also do not consider ANY account actors (including the faucet)
|
||||
func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
|
||||
func (sm *StateManager) setupPreIgnitionGenesisActorsTestnet(ctx context.Context) error {
|
||||
|
||||
gi := genesisInfo{}
|
||||
|
||||
@@ -954,24 +1040,24 @@ func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin.EpochsInDay)
|
||||
sixMonths := abi.ChainEpoch(183 * builtin0.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)
|
||||
oneYear := abi.ChainEpoch(365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin.EpochsInDay)
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin.EpochsInDay)
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin.EpochsInDay)
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
|
||||
@@ -985,7 +1071,87 @@ func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
|
||||
gi.genesisMsigs = append(gi.genesisMsigs, ns)
|
||||
}
|
||||
|
||||
sm.genInfo = &gi
|
||||
sm.preIgnitionGenInfos = &gi
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sets up information about the actors in the genesis state, post the ignition fork
|
||||
func (sm *StateManager) setupPostIgnitionGenesisActors(ctx context.Context) error {
|
||||
|
||||
gi := genesisInfo{}
|
||||
|
||||
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.Blockstore())
|
||||
sTree, err := state.LoadStateTree(cst, st)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("loading state tree: %w", err)
|
||||
}
|
||||
|
||||
// Unnecessary, should be removed
|
||||
gi.genesisMarketFunds, err = getFilMarketLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis market funds: %w", err)
|
||||
}
|
||||
|
||||
// Unnecessary, should be removed
|
||||
gi.genesisPledge, err = getFilPowerLocked(ctx, sTree)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setting up genesis pledge: %w", err)
|
||||
}
|
||||
|
||||
totalsByEpoch := make(map[abi.ChainEpoch]abi.TokenAmount)
|
||||
|
||||
// 6 months
|
||||
sixMonths := abi.ChainEpoch(183 * builtin0.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 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[oneYear] = big.NewInt(22_421_712)
|
||||
|
||||
// 2 years
|
||||
twoYears := abi.ChainEpoch(2 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[twoYears] = big.NewInt(7_223_364)
|
||||
|
||||
// 3 years
|
||||
threeYears := abi.ChainEpoch(3 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[threeYears] = big.NewInt(87_637_883)
|
||||
|
||||
// 6 years
|
||||
sixYears := abi.ChainEpoch(6 * 365 * builtin0.EpochsInDay)
|
||||
totalsByEpoch[sixYears] = big.NewInt(100_000_000)
|
||||
totalsByEpoch[sixYears] = big.Add(totalsByEpoch[sixYears], big.NewInt(300_000_000))
|
||||
|
||||
gi.genesisMsigs = 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,
|
||||
}
|
||||
gi.genesisMsigs = append(gi.genesisMsigs, ns)
|
||||
}
|
||||
|
||||
sm.postIgnitionGenInfos = &gi
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -995,13 +1161,23 @@ func (sm *StateManager) setupGenesisActorsTestnet(ctx context.Context) error {
|
||||
// - 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()
|
||||
for _, v := range sm.genInfo.genesisMsigs {
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height))
|
||||
vf = big.Add(vf, au)
|
||||
if height <= build.UpgradeIgnitionHeight {
|
||||
for _, v := range sm.preIgnitionGenInfos.genesisMsigs {
|
||||
au := big.Sub(v.InitialBalance, v.AmountLocked(height))
|
||||
vf = big.Add(vf, au)
|
||||
}
|
||||
} else {
|
||||
for _, v := range sm.postIgnitionGenInfos.genesisMsigs {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// there should not be any such accounts in testnet (and also none in mainnet?)
|
||||
for _, v := range sm.genInfo.genesisActors {
|
||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||
for _, v := range sm.preIgnitionGenInfos.genesisActors {
|
||||
act, err := st.GetActor(v.addr)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to get actor: %w", err)
|
||||
@@ -1013,14 +1189,29 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
vf = big.Add(vf, sm.genInfo.genesisPledge)
|
||||
vf = big.Add(vf, sm.genInfo.genesisMarketFunds)
|
||||
// After UpgradeActorsV2Height these funds are accounted for in GetFilReserveDisbursed
|
||||
if height <= build.UpgradeActorsV2Height {
|
||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||
vf = big.Add(vf, sm.preIgnitionGenInfos.genesisPledge)
|
||||
// continue to use preIgnitionGenInfos, nothing changed at the Ignition epoch
|
||||
vf = big.Add(vf, sm.preIgnitionGenInfos.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(builtin.RewardActorAddr)
|
||||
ractor, err := st.GetActor(reward.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load reward actor state: %w", err)
|
||||
}
|
||||
@@ -1034,7 +1225,7 @@ func GetFilMined(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
||||
}
|
||||
|
||||
func getFilMarketLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
act, err := st.GetActor(builtin.StorageMarketActorAddr)
|
||||
act, err := st.GetActor(market.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load market actor: %w", err)
|
||||
}
|
||||
@@ -1048,7 +1239,7 @@ func getFilMarketLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmou
|
||||
}
|
||||
|
||||
func getFilPowerLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
pactor, err := st.GetActor(builtin.StoragePowerActorAddr)
|
||||
pactor, err := st.GetActor(power.Address)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
@@ -1077,7 +1268,7 @@ func (sm *StateManager) GetFilLocked(ctx context.Context, st *state.StateTree) (
|
||||
}
|
||||
|
||||
func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
burnt, err := st.GetActor(builtin.BurntFundsActorAddr)
|
||||
burnt, err := st.GetActor(builtin0.BurntFundsActorAddr)
|
||||
if err != nil {
|
||||
return big.Zero(), xerrors.Errorf("failed to load burnt actor: %w", err)
|
||||
}
|
||||
@@ -1088,10 +1279,16 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
||||
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.genInfo == nil {
|
||||
err := sm.setupGenesisActorsTestnet(ctx)
|
||||
if sm.preIgnitionGenInfos == nil {
|
||||
err := sm.setupPreIgnitionGenesisActorsTestnet(ctx)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup genesis information: %w", err)
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup pre-ignition genesis information: %w", err)
|
||||
}
|
||||
}
|
||||
if sm.postIgnitionGenInfos == nil {
|
||||
err := sm.setupPostIgnitionGenesisActors(ctx)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to setup post-ignition genesis information: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,6 +1297,14 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||
}
|
||||
|
||||
filReserveDisbursed := big.Zero()
|
||||
if height > build.UpgradeActorsV2Height {
|
||||
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)
|
||||
@@ -1116,6 +1321,7 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
||||
}
|
||||
|
||||
ret := types.BigAdd(filVested, filMined)
|
||||
ret = types.BigAdd(ret, filReserveDisbursed)
|
||||
ret = types.BigSub(ret, filBurnt)
|
||||
ret = types.BigSub(ret, filLocked)
|
||||
|
||||
@@ -1142,21 +1348,14 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||
// TODO: move hard fork epoch checks to a schedule defined in build/
|
||||
|
||||
if build.UseNewestNetwork() {
|
||||
return build.NewestNetworkVersion
|
||||
// The epochs here are the _last_ epoch for every version, or -1 if the
|
||||
// version is disabled.
|
||||
for _, spec := range sm.networkVersions {
|
||||
if height <= spec.atOrBelow {
|
||||
return spec.networkVersion
|
||||
}
|
||||
}
|
||||
|
||||
if height <= build.UpgradeBreezeHeight {
|
||||
return network.Version0
|
||||
}
|
||||
|
||||
if height <= build.UpgradeSmokeHeight {
|
||||
return network.Version1
|
||||
}
|
||||
|
||||
return build.NewestNetworkVersion
|
||||
return sm.latestVersion
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
||||
|
||||
+131
-91
@@ -9,10 +9,10 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
saruntime "github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -22,29 +22,24 @@ import (
|
||||
"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/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/go-state-types/rt"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
account0 "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
paych0 "github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
reward0 "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||
proof0 "github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
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/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"
|
||||
)
|
||||
|
||||
@@ -88,8 +83,7 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add
|
||||
}
|
||||
|
||||
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
// TODO: ActorUpgrade
|
||||
act, err := sm.LoadActorRaw(ctx, builtin0.StoragePowerActorAddr, st)
|
||||
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)
|
||||
}
|
||||
@@ -105,6 +99,7 @@ func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr addres
|
||||
}
|
||||
|
||||
var mpow power.Claim
|
||||
var minpow bool
|
||||
if maddr != address.Undef {
|
||||
var found bool
|
||||
mpow, found, err = pas.MinerPower(maddr)
|
||||
@@ -112,11 +107,11 @@ func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr addres
|
||||
// TODO: return an error when not found?
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
minpow, err := pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
minpow, err = pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
||||
if err != nil {
|
||||
return power.Claim{}, power.Claim{}, false, err
|
||||
}
|
||||
}
|
||||
|
||||
return mpow, tpow, minpow, nil
|
||||
@@ -164,7 +159,7 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
|
||||
return mas.LoadSectors(snos)
|
||||
}
|
||||
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) {
|
||||
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof0.SectorInfo, error) {
|
||||
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||
@@ -249,9 +244,9 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
|
||||
return nil, xerrors.Errorf("loading proving sectors: %w", err)
|
||||
}
|
||||
|
||||
out := make([]proof.SectorInfo, len(sectors))
|
||||
out := make([]proof0.SectorInfo, len(sectors))
|
||||
for i, sinfo := range sectors {
|
||||
out[i] = proof.SectorInfo{
|
||||
out[i] = proof0.SectorInfo{
|
||||
SealProof: spt,
|
||||
SectorNumber: sinfo.SectorNumber,
|
||||
SealedCID: sinfo.SealedCID,
|
||||
@@ -281,8 +276,7 @@ func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
|
||||
}
|
||||
|
||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||
// TODO: ActorUpgrade
|
||||
act, err := sm.LoadActor(ctx, builtin0.StoragePowerActorAddr, ts)
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
@@ -305,8 +299,7 @@ func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, ma
|
||||
}
|
||||
|
||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||
// TODO: ActorUpgrade
|
||||
act, err := sm.LoadActor(ctx, builtin0.StorageMarketActorAddr, ts)
|
||||
act, err := sm.LoadActor(ctx, market.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load market actor: %w", err)
|
||||
}
|
||||
@@ -350,8 +343,7 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts
|
||||
}
|
||||
|
||||
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
|
||||
// TODO: ActorUpgrade
|
||||
act, err := sm.LoadActor(ctx, builtin0.StoragePowerActorAddr, ts)
|
||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
@@ -374,6 +366,16 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
for i := ts.Height(); i < height; i++ {
|
||||
// handle state forks
|
||||
base, err = sm.handleStateForks(ctx, base, i, traceFunc(&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,
|
||||
@@ -385,21 +387,11 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: ts.Blocks()[0].ParentBaseFee,
|
||||
}
|
||||
vmi, err := vm.NewVM(ctx, vmopt)
|
||||
vmi, err := sm.newVM(ctx, vmopt)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, err
|
||||
}
|
||||
|
||||
for i := ts.Height(); i < height; i++ {
|
||||
// handle state forks
|
||||
err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err)
|
||||
}
|
||||
|
||||
// TODO: should we also run cron here?
|
||||
}
|
||||
|
||||
for i, msg := range msgs {
|
||||
// TODO: Use the signed message length for secp messages
|
||||
ret, err := vmi.ApplyMessage(ctx, msg)
|
||||
@@ -421,8 +413,9 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
|
||||
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
|
||||
var lbr abi.ChainEpoch
|
||||
if round > build.WinningPoStSectorSetLookback {
|
||||
lbr = round - build.WinningPoStSectorSetLookback
|
||||
lb := policy.GetWinningPoStSectorSetLookback(sm.GetNtwkVersion(ctx, round))
|
||||
if round > lb {
|
||||
lbr = round - lb
|
||||
}
|
||||
|
||||
// more null blocks than our lookback
|
||||
@@ -502,7 +495,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
mpow, tpow, hmp, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||
}
|
||||
@@ -517,15 +510,21 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
||||
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,
|
||||
HasMinPower: hmp,
|
||||
MinerPower: mpow.QualityAdjPower,
|
||||
NetworkPower: tpow.QualityAdjPower,
|
||||
Sectors: sectors,
|
||||
WorkerKey: worker,
|
||||
SectorSize: info.SectorSize,
|
||||
PrevBeaconEntry: *prev,
|
||||
BeaconEntries: entries,
|
||||
EligibleForMining: eligible,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -539,42 +538,23 @@ type MethodMeta struct {
|
||||
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
||||
|
||||
func init() {
|
||||
cidToMethods := map[cid.Cid][2]interface{}{
|
||||
// builtin.SystemActorCodeID: {builtin.MethodsSystem, system.Actor{} }- apparently it doesn't have methods
|
||||
builtin0.InitActorCodeID: {builtin0.MethodsInit, init0.Actor{}},
|
||||
builtin0.CronActorCodeID: {builtin0.MethodsCron, cron.Actor{}},
|
||||
builtin0.AccountActorCodeID: {builtin0.MethodsAccount, account0.Actor{}},
|
||||
builtin0.StoragePowerActorCodeID: {builtin0.MethodsPower, power0.Actor{}},
|
||||
builtin0.StorageMinerActorCodeID: {builtin0.MethodsMiner, miner0.Actor{}},
|
||||
builtin0.StorageMarketActorCodeID: {builtin0.MethodsMarket, market0.Actor{}},
|
||||
builtin0.PaymentChannelActorCodeID: {builtin0.MethodsPaych, paych0.Actor{}},
|
||||
builtin0.MultisigActorCodeID: {builtin0.MethodsMultisig, msig0.Actor{}},
|
||||
builtin0.RewardActorCodeID: {builtin0.MethodsReward, reward0.Actor{}},
|
||||
builtin0.VerifiedRegistryActorCodeID: {builtin0.MethodsVerifiedRegistry, verifreg0.Actor{}},
|
||||
}
|
||||
// TODO: combine with the runtime actor registry.
|
||||
var actors []rt.VMActor
|
||||
actors = append(actors, exported0.BuiltinActors()...)
|
||||
actors = append(actors, exported2.BuiltinActors()...)
|
||||
|
||||
for c, m := range cidToMethods {
|
||||
exports := m[1].(saruntime.Invokee).Exports()
|
||||
for _, actor := range actors {
|
||||
exports := actor.Exports()
|
||||
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
||||
|
||||
// Explicitly add send, it's special.
|
||||
// Note that builtin2.MethodSend = builtin0.MethodSend = 0.
|
||||
methods[builtin0.MethodSend] = MethodMeta{
|
||||
Name: "Send",
|
||||
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
||||
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
||||
}
|
||||
|
||||
// Learn method names from the builtin.Methods* structs.
|
||||
rv := reflect.ValueOf(m[0])
|
||||
rt := rv.Type()
|
||||
nf := rt.NumField()
|
||||
methodToName := make([]string, len(exports))
|
||||
for i := 0; i < nf; i++ {
|
||||
name := rt.Field(i).Name
|
||||
number := rv.Field(i).Interface().(abi.MethodNum)
|
||||
methodToName[number] = name
|
||||
}
|
||||
|
||||
// Iterate over exported methods. Some of these _may_ be nil and
|
||||
// must be skipped.
|
||||
for number, export := range exports {
|
||||
@@ -585,22 +565,19 @@ func init() {
|
||||
ev := reflect.ValueOf(export)
|
||||
et := ev.Type()
|
||||
|
||||
// Make sure the method name is correct.
|
||||
// This is just a nice sanity check.
|
||||
// Extract the method names using reflection. These
|
||||
// method names always match the field names in the
|
||||
// `builtin.Method*` structs (tested in the specs-actors
|
||||
// tests).
|
||||
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
||||
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
||||
mName := methodToName[number]
|
||||
if mName != fnName {
|
||||
panic(fmt.Sprintf(
|
||||
"actor method name is %s but exported method name is %s",
|
||||
fnName, mName,
|
||||
))
|
||||
}
|
||||
|
||||
switch abi.MethodNum(number) {
|
||||
case builtin0.MethodSend:
|
||||
// Note that builtin2.MethodSend = builtin0.MethodSend = 0.
|
||||
panic("method 0 is reserved for Send")
|
||||
case builtin0.MethodConstructor:
|
||||
// Note that builtin2.MethodConstructor = builtin0.MethodConstructor = 1.
|
||||
if fnName != "Constructor" {
|
||||
panic("method 1 is reserved for Constructor")
|
||||
}
|
||||
@@ -612,7 +589,7 @@ func init() {
|
||||
Ret: et.Out(0),
|
||||
}
|
||||
}
|
||||
MethodsMap[c] = methods
|
||||
MethodsMap[actor.Code()] = methods
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,9 +606,8 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
|
||||
func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||
// TODO: ActorUpgrade
|
||||
pact, err := sm.LoadActor(ctx, builtin0.StoragePowerActorAddr, ts)
|
||||
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)
|
||||
}
|
||||
@@ -644,6 +620,70 @@ func MinerHasMinPower(ctx context.Context, sm *StateManager, addr address.Addres
|
||||
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.Store(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.Store(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 CheckTotalFIL(ctx context.Context, sm *StateManager, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
str, err := state.LoadStateTree(sm.ChainStore().Store(ctx), ts.ParentState())
|
||||
if err != nil {
|
||||
|
||||
@@ -46,7 +46,7 @@ func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int
|
||||
}
|
||||
|
||||
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||
if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration {
|
||||
if build.UpgradeBreezeHeight >= 0 && ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration {
|
||||
return abi.NewTokenAmount(100), nil
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -11,24 +11,27 @@ import (
|
||||
|
||||
func TestBaseFee(t *testing.T) {
|
||||
tests := []struct {
|
||||
basefee uint64
|
||||
limitUsed int64
|
||||
noOfBlocks int
|
||||
output uint64
|
||||
basefee uint64
|
||||
limitUsed int64
|
||||
noOfBlocks int
|
||||
preSmoke, postSmoke uint64
|
||||
}{
|
||||
{100e6, 0, 1, 87.5e6},
|
||||
{100e6, 0, 5, 87.5e6},
|
||||
{100e6, build.BlockGasTarget, 1, 103.125e6},
|
||||
{100e6, build.BlockGasTarget * 2, 2, 103.125e6},
|
||||
{100e6, build.BlockGasLimit * 2, 2, 112.5e6},
|
||||
{100e6, build.BlockGasLimit * 1.5, 2, 110937500},
|
||||
{100e6, 0, 1, 87.5e6, 87.5e6},
|
||||
{100e6, 0, 5, 87.5e6, 87.5e6},
|
||||
{100e6, build.BlockGasTarget, 1, 103.125e6, 100e6},
|
||||
{100e6, build.BlockGasTarget * 2, 2, 103.125e6, 100e6},
|
||||
{100e6, build.BlockGasLimit * 2, 2, 112.5e6, 112.5e6},
|
||||
{100e6, build.BlockGasLimit * 1.5, 2, 110937500, 106.250e6},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
||||
output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0)
|
||||
assert.Equal(t, fmt.Sprintf("%d", test.output), output.String())
|
||||
preSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight-1)
|
||||
assert.Equal(t, fmt.Sprintf("%d", test.preSmoke), preSmoke.String())
|
||||
|
||||
postSmoke := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, build.UpgradeSmokeHeight+1)
|
||||
assert.Equal(t, fmt.Sprintf("%d", test.postSmoke), postSmoke.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+82
-28
@@ -10,14 +10,20 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
adt0 "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/adt"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
||||
@@ -282,6 +288,16 @@ func (cs *ChainStore) MarkBlockAsValidated(ctx context.Context, blkid cid.Cid) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) UnmarkBlockAsValidated(ctx context.Context, blkid cid.Cid) error {
|
||||
key := blockValidationCacheKeyPrefix.Instance(blkid.String())
|
||||
|
||||
if err := cs.ds.Delete(key); err != nil {
|
||||
return xerrors.Errorf("removing from valid block cache: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error {
|
||||
ts, err := types.NewTipSet([]*types.BlockHeader{b})
|
||||
if err != nil {
|
||||
@@ -465,14 +481,25 @@ func (cs *ChainStore) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return v.(*types.TipSet), nil
|
||||
}
|
||||
|
||||
var blks []*types.BlockHeader
|
||||
for _, c := range tsk.Cids() {
|
||||
b, err := cs.GetBlock(c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get block %s: %w", c, err)
|
||||
}
|
||||
// Fetch tipset block headers from blockstore in parallel
|
||||
var eg errgroup.Group
|
||||
cids := tsk.Cids()
|
||||
blks := make([]*types.BlockHeader, len(cids))
|
||||
for i, c := range cids {
|
||||
i, c := i, c
|
||||
eg.Go(func() error {
|
||||
b, err := cs.GetBlock(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get block %s: %w", c, err)
|
||||
}
|
||||
|
||||
blks = append(blks, b)
|
||||
blks[i] = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err := eg.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts, err := types.NewTipSet(blks)
|
||||
@@ -732,7 +759,8 @@ func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error)
|
||||
|
||||
func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
|
||||
ctx := context.TODO()
|
||||
a, err := adt.AsArray(cs.Store(ctx), root)
|
||||
// block headers use adt0, for now.
|
||||
a, err := adt0.AsArray(cs.Store(ctx), root)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
@@ -925,7 +953,8 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message,
|
||||
|
||||
func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
|
||||
ctx := context.TODO()
|
||||
a, err := adt.AsArray(cs.Store(ctx), b.ParentMessageReceipts)
|
||||
// block headers use adt0, for now.
|
||||
a, err := adt0.AsArray(cs.Store(ctx), b.ParentMessageReceipts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("amt load: %w", err)
|
||||
}
|
||||
@@ -1166,13 +1195,6 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid.
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error {
|
||||
if ts == nil {
|
||||
ts = cs.GetHeaviestTipSet()
|
||||
}
|
||||
|
||||
seen := cid.NewSet()
|
||||
walked := cid.NewSet()
|
||||
|
||||
h := &car.CarHeader{
|
||||
Roots: ts.Cids(),
|
||||
Version: 1,
|
||||
@@ -1182,27 +1204,57 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
return xerrors.Errorf("failed to write car header: %s", err)
|
||||
}
|
||||
|
||||
return cs.WalkSnapshot(ctx, ts, inclRecentRoots, skipOldMsgs, func(c cid.Cid) error {
|
||||
blk, err := cs.bs.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 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.bs.Get(blk)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("getting block: %w", err)
|
||||
}
|
||||
|
||||
if err := carutil.LdWrite(w, blk.Bytes(), data.RawData()); err != nil {
|
||||
return xerrors.Errorf("failed to write block to car output: %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 {
|
||||
mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages})
|
||||
@@ -1237,20 +1289,20 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
if c.Prefix().Codec != cid.DagCBOR {
|
||||
continue
|
||||
}
|
||||
data, err := cs.bs.Get(c)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("writing object to car (get %s): %w", c, err)
|
||||
|
||||
if err := cb(c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := carutil.LdWrite(w, c.Bytes(), data.RawData()); err != nil {
|
||||
return xerrors.Errorf("failed to write out car object: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Infow("export started")
|
||||
exportStart := build.Clock.Now()
|
||||
|
||||
for len(blocksToWalk) > 0 {
|
||||
next := blocksToWalk[0]
|
||||
blocksToWalk = blocksToWalk[1:]
|
||||
@@ -1259,6 +1311,8 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("export finished", "duration", build.Clock.Now().Sub(exportStart).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1301,7 +1355,7 @@ func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
||||
type chainRand struct {
|
||||
|
||||
@@ -8,12 +8,9 @@ import (
|
||||
datastore "github.com/ipfs/go-datastore"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -22,11 +19,9 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg0.MinVerifiedDealSize = big.NewInt(256)
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
func BenchmarkGetRandomness(b *testing.B) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
@@ -35,7 +34,7 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
|
||||
return types.NewInt(0), xerrors.Errorf("load state tree: %w", err)
|
||||
}
|
||||
|
||||
act, err := state.GetActor(builtin.StoragePowerActorAddr)
|
||||
act, err := state.GetActor(power.Address)
|
||||
if err != nil {
|
||||
return types.NewInt(0), xerrors.Errorf("get power actor: %w", err)
|
||||
}
|
||||
|
||||
+34
-23
@@ -10,7 +10,6 @@ import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
bserv "github.com/ipfs/go-blockservice"
|
||||
@@ -24,6 +23,8 @@ import (
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/tag"
|
||||
|
||||
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
@@ -43,7 +44,11 @@ var log = logging.Logger("sub")
|
||||
var ErrSoftFailure = errors.New("soft validation failure")
|
||||
var ErrInsufficientPower = errors.New("incoming block's miner does not have minimum power")
|
||||
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bserv bserv.BlockService, cmgr connmgr.ConnManager) {
|
||||
func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *chain.Syncer, bs bserv.BlockService, cmgr connmgr.ConnManager) {
|
||||
// Timeout after (block time + propagation delay). This is useless at
|
||||
// this point.
|
||||
timeout := time.Duration(build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second
|
||||
|
||||
for {
|
||||
msg, err := bsub.Next(ctx)
|
||||
if err != nil {
|
||||
@@ -64,15 +69,22 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
src := msg.GetFrom()
|
||||
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
// NOTE: we could also share a single session between
|
||||
// all requests but that may have other consequences.
|
||||
ses := bserv.NewSession(ctx, bs)
|
||||
|
||||
start := build.Clock.Now()
|
||||
log.Debug("about to fetch messages for block from pubsub")
|
||||
bmsgs, err := FetchMessagesByCids(context.TODO(), bserv, blk.BlsMessages)
|
||||
bmsgs, err := FetchMessagesByCids(ctx, ses, blk.BlsMessages)
|
||||
if err != nil {
|
||||
log.Errorf("failed to fetch all bls messages for block received over pubusb: %s; source: %s", err, src)
|
||||
return
|
||||
}
|
||||
|
||||
smsgs, err := FetchSignedMessagesByCids(context.TODO(), bserv, blk.SecpkMessages)
|
||||
smsgs, err := FetchSignedMessagesByCids(ctx, ses, blk.SecpkMessages)
|
||||
if err != nil {
|
||||
log.Errorf("failed to fetch all secpk messages for block received over pubusb: %s; source: %s", err, src)
|
||||
return
|
||||
@@ -97,7 +109,7 @@ func HandleIncomingBlocks(ctx context.Context, bsub *pubsub.Subscription, s *cha
|
||||
|
||||
func FetchMessagesByCids(
|
||||
ctx context.Context,
|
||||
bserv bserv.BlockService,
|
||||
bserv bserv.BlockGetter,
|
||||
cids []cid.Cid,
|
||||
) ([]*types.Message, error) {
|
||||
out := make([]*types.Message, len(cids))
|
||||
@@ -126,7 +138,7 @@ func FetchMessagesByCids(
|
||||
// FIXME: Duplicate of above.
|
||||
func FetchSignedMessagesByCids(
|
||||
ctx context.Context,
|
||||
bserv bserv.BlockService,
|
||||
bserv bserv.BlockGetter,
|
||||
cids []cid.Cid,
|
||||
) ([]*types.SignedMessage, error) {
|
||||
out := make([]*types.SignedMessage, len(cids))
|
||||
@@ -156,30 +168,28 @@ func FetchSignedMessagesByCids(
|
||||
// blocks we did not request.
|
||||
func fetchCids(
|
||||
ctx context.Context,
|
||||
bserv bserv.BlockService,
|
||||
bserv bserv.BlockGetter,
|
||||
cids []cid.Cid,
|
||||
cb func(int, blocks.Block) error,
|
||||
) error {
|
||||
// FIXME: Why don't we use the context here?
|
||||
fetchedBlocks := bserv.GetBlocks(context.TODO(), cids)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
cidIndex := make(map[cid.Cid]int)
|
||||
for i, c := range cids {
|
||||
cidIndex[c] = i
|
||||
}
|
||||
if len(cids) != len(cidIndex) {
|
||||
return fmt.Errorf("duplicate CIDs in fetchCids input")
|
||||
}
|
||||
|
||||
fetchedBlocks := bserv.GetBlocks(ctx, cids)
|
||||
|
||||
for i := 0; i < len(cids); i++ {
|
||||
select {
|
||||
case block, ok := <-fetchedBlocks:
|
||||
if !ok {
|
||||
// Closed channel, no more blocks fetched, check if we have all
|
||||
// of the CIDs requested.
|
||||
// FIXME: Review this check. We don't call the callback on the
|
||||
// last index?
|
||||
if i == len(cids)-1 {
|
||||
break
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to fetch all messages")
|
||||
}
|
||||
|
||||
@@ -374,9 +384,10 @@ func (bv *BlockValidator) isChainNearSynced() bool {
|
||||
|
||||
func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error {
|
||||
// TODO there has to be a simpler way to do this without the blockstore dance
|
||||
store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary()))
|
||||
bmArr := adt.MakeEmptyArray(store)
|
||||
smArr := adt.MakeEmptyArray(store)
|
||||
// block headers use adt0
|
||||
store := adt0.WrapStore(ctx, cbor.NewCborStore(blockstore.NewTemporary()))
|
||||
bmArr := adt0.MakeEmptyArray(store)
|
||||
smArr := adt0.MakeEmptyArray(store)
|
||||
|
||||
for i, m := range msg.BlsMessages {
|
||||
c := cbg.CborCid(m)
|
||||
@@ -473,14 +484,14 @@ func (bv *BlockValidator) checkPowerAndGetWorkerKey(ctx context.Context, bh *typ
|
||||
return address.Undef, ErrSoftFailure
|
||||
}
|
||||
|
||||
hmp, err := stmgr.MinerHasMinPower(ctx, bv.stmgr, bh.Miner, lbts)
|
||||
eligible, err := stmgr.MinerEligibleToMine(ctx, bv.stmgr, bh.Miner, baseTs, lbts)
|
||||
if err != nil {
|
||||
log.Warnf("failed to determine if incoming block's miner has minimum power: %s", err)
|
||||
return address.Undef, ErrSoftFailure
|
||||
}
|
||||
|
||||
if !hmp {
|
||||
log.Warnf("incoming block's miner does not have minimum power")
|
||||
if !eligible {
|
||||
log.Warnf("incoming block's miner is ineligible")
|
||||
return address.Undef, ErrInsufficientPower
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package sub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
address "github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type getter struct {
|
||||
msgs []*types.Message
|
||||
}
|
||||
|
||||
func (g *getter) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { panic("NYI") }
|
||||
|
||||
func (g *getter) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
|
||||
ch := make(chan blocks.Block, len(g.msgs))
|
||||
for _, m := range g.msgs {
|
||||
by, err := m.Serialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err := blocks.NewBlockWithCid(by, m.Cid())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ch <- b
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func TestFetchCidsWithDedup(t *testing.T) {
|
||||
msgs := []*types.Message{}
|
||||
for i := 0; i < 10; i++ {
|
||||
msgs = append(msgs, &types.Message{
|
||||
From: address.TestAddress,
|
||||
To: address.TestAddress,
|
||||
|
||||
Nonce: uint64(i),
|
||||
})
|
||||
}
|
||||
cids := []cid.Cid{}
|
||||
for _, m := range msgs {
|
||||
cids = append(cids, m.Cid())
|
||||
}
|
||||
g := &getter{msgs}
|
||||
|
||||
// the cids have a duplicate
|
||||
res, err := FetchMessagesByCids(context.TODO(), g, append(cids, cids[0]))
|
||||
|
||||
t.Logf("err: %+v", err)
|
||||
t.Logf("res: %+v", res)
|
||||
if err == nil {
|
||||
t.Errorf("there should be an error")
|
||||
}
|
||||
if err == nil && (res[0] == nil || res[len(res)-1] == nil) {
|
||||
t.Fatalf("there is a nil message: first %p, last %p", res[0], res[len(res)-1])
|
||||
}
|
||||
}
|
||||
+174
-116
@@ -7,17 +7,19 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime/proof"
|
||||
|
||||
"github.com/Gurpartap/async"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@@ -33,10 +35,10 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
blst "github.com/supranational/blst/bindings/go"
|
||||
|
||||
adt0 "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/builtin/power"
|
||||
@@ -63,20 +65,12 @@ var (
|
||||
// where the Syncer publishes candidate chain heads to be synced.
|
||||
LocalIncoming = "incoming"
|
||||
|
||||
log = logging.Logger("chain")
|
||||
defaultMessageFetchWindowSize = 200
|
||||
)
|
||||
log = logging.Logger("chain")
|
||||
|
||||
func init() {
|
||||
if s := os.Getenv("LOTUS_BSYNC_MSG_WINDOW"); s != "" {
|
||||
val, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse LOTUS_BSYNC_MSG_WINDOW: %s", err)
|
||||
return
|
||||
}
|
||||
defaultMessageFetchWindowSize = val
|
||||
}
|
||||
}
|
||||
concurrentSyncRequests = exchange.ShufflePeersPrefix
|
||||
syncRequestBatchSize = 8
|
||||
syncRequestRetries = 5
|
||||
)
|
||||
|
||||
// Syncer is in charge of running the chain synchronization logic. As such, it
|
||||
// is tasked with these functions, amongst others:
|
||||
@@ -132,8 +126,6 @@ type Syncer struct {
|
||||
|
||||
verifier ffiwrapper.Verifier
|
||||
|
||||
windowSize int
|
||||
|
||||
tickerCtxCancel context.CancelFunc
|
||||
|
||||
checkptLk sync.Mutex
|
||||
@@ -175,7 +167,6 @@ func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.C
|
||||
receiptTracker: newBlockReceiptTracker(),
|
||||
connmgr: connmgr,
|
||||
verifier: verifier,
|
||||
windowSize: defaultMessageFetchWindowSize,
|
||||
|
||||
incoming: pubsub.New(50),
|
||||
}
|
||||
@@ -226,6 +217,12 @@ func (syncer *Syncer) Stop() {
|
||||
// This should be called when connecting to new peers, and additionally
|
||||
// when receiving new blocks from the network
|
||||
func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("panic in InformNewHead: ", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
if fts == nil {
|
||||
log.Errorf("got nil tipset in InformNewHead")
|
||||
@@ -387,21 +384,28 @@ func (syncer *Syncer) InformNewBlock(from peer.ID, blk *types.FullBlock) bool {
|
||||
return syncer.InformNewHead(from, fts)
|
||||
}
|
||||
|
||||
func copyBlockstore(from, to bstore.Blockstore) error {
|
||||
cids, err := from.AllKeysChan(context.TODO())
|
||||
func copyBlockstore(ctx context.Context, from, to bstore.Blockstore) error {
|
||||
ctx, span := trace.StartSpan(ctx, "copyBlockstore")
|
||||
defer span.End()
|
||||
|
||||
cids, err := from.AllKeysChan(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: should probably expose better methods on the blockstore for this operation
|
||||
var blks []blocks.Block
|
||||
for c := range cids {
|
||||
b, err := from.Get(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := to.Put(b); err != nil {
|
||||
return err
|
||||
}
|
||||
blks = append(blks, b)
|
||||
}
|
||||
|
||||
if err := to.PutMany(blks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -460,9 +464,10 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types
|
||||
// computeMsgMeta computes the root CID of the combined arrays of message CIDs
|
||||
// of both types (BLS and Secpk).
|
||||
func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) {
|
||||
store := adt.WrapStore(context.TODO(), bs)
|
||||
bmArr := adt.MakeEmptyArray(store)
|
||||
smArr := adt.MakeEmptyArray(store)
|
||||
// block headers use adt0
|
||||
store := adt0.WrapStore(context.TODO(), bs)
|
||||
bmArr := adt0.MakeEmptyArray(store)
|
||||
smArr := adt0.MakeEmptyArray(store)
|
||||
|
||||
for i, m := range bmsgCids {
|
||||
c := cbg.CborCid(m)
|
||||
@@ -602,7 +607,7 @@ func isPermanent(err error) bool {
|
||||
return !errors.Is(err, ErrTemporal)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet) error {
|
||||
func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet, useCache bool) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validateTipSet")
|
||||
defer span.End()
|
||||
|
||||
@@ -618,7 +623,7 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
||||
b := b // rebind to a scoped variable
|
||||
|
||||
futures = append(futures, async.Err(func() error {
|
||||
if err := syncer.ValidateBlock(ctx, b); err != nil {
|
||||
if err := syncer.ValidateBlock(ctx, b, useCache); err != nil {
|
||||
if isPermanent(err) {
|
||||
syncer.bad.Add(b.Cid(), NewBadBlockReason([]cid.Cid{b.Cid()}, err.Error()))
|
||||
}
|
||||
@@ -640,7 +645,7 @@ func (syncer *Syncer) ValidateTipSet(ctx context.Context, fts *store.FullTipSet)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, baseTs *types.TipSet) error {
|
||||
act, err := syncer.sm.LoadActor(ctx, builtin.StoragePowerActorAddr, baseTs)
|
||||
act, err := syncer.sm.LoadActor(ctx, power.Address, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to load power actor: %w", err)
|
||||
}
|
||||
@@ -685,7 +690,7 @@ func blockSanityChecks(h *types.BlockHeader) error {
|
||||
}
|
||||
|
||||
// ValidateBlock should match up with 'Semantical Validation' in validation.md in the spec
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) {
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock, useCache bool) (err error) {
|
||||
defer func() {
|
||||
// b.Cid() could panic for empty blocks that are used in tests.
|
||||
if rerr := recover(); rerr != nil {
|
||||
@@ -694,13 +699,15 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
}
|
||||
}()
|
||||
|
||||
isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err)
|
||||
}
|
||||
if useCache {
|
||||
isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err)
|
||||
}
|
||||
|
||||
if isValidated {
|
||||
return nil
|
||||
if isValidated {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
validationStart := build.Clock.Now()
|
||||
@@ -730,7 +737,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
|
||||
lbst, _, err := syncer.sm.TipSetState(ctx, lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to compute lookback tipset state: %w", err)
|
||||
return xerrors.Errorf("failed to compute lookback tipset state (epoch %d): %w", lbts.Height(), err)
|
||||
}
|
||||
|
||||
prevBeacon, err := syncer.store.GetLatestBeaconEntry(baseTs)
|
||||
@@ -787,31 +794,35 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
b.Header.ParentWeight, pweight)
|
||||
}
|
||||
|
||||
// Stuff that needs stateroot / worker address
|
||||
stateroot, precp, err := syncer.sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||
}
|
||||
|
||||
if stateroot != h.ParentStateRoot {
|
||||
msgs, err := syncer.store.MessagesForTipset(baseTs)
|
||||
stateRootCheck := async.Err(func() error {
|
||||
stateroot, precp, err := syncer.sm.TipSetState(ctx, baseTs)
|
||||
if err != nil {
|
||||
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
||||
} else {
|
||||
log.Warn("Messages for tipset with mismatching state:")
|
||||
for i, m := range msgs {
|
||||
mm := m.VMMessage()
|
||||
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
||||
}
|
||||
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
|
||||
}
|
||||
|
||||
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", stateroot, h.ParentStateRoot)
|
||||
}
|
||||
if stateroot != h.ParentStateRoot {
|
||||
msgs, err := syncer.store.MessagesForTipset(baseTs)
|
||||
if err != nil {
|
||||
log.Error("failed to load messages for tipset during tipset state mismatch error: ", err)
|
||||
} else {
|
||||
log.Warn("Messages for tipset with mismatching state:")
|
||||
for i, m := range msgs {
|
||||
mm := m.VMMessage()
|
||||
log.Warnf("Message[%d]: from=%s to=%s method=%d params=%x", i, mm.From, mm.To, mm.Method, mm.Params)
|
||||
}
|
||||
}
|
||||
|
||||
if precp != h.ParentMessageReceipts {
|
||||
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
||||
}
|
||||
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", stateroot, h.ParentStateRoot)
|
||||
}
|
||||
|
||||
if precp != h.ParentMessageReceipts {
|
||||
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Stuff that needs worker address
|
||||
waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, lbst, h.Miner)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err)
|
||||
@@ -822,13 +833,13 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
return xerrors.Errorf("block is not claiming to be a winner")
|
||||
}
|
||||
|
||||
hp, err := stmgr.MinerHasMinPower(ctx, syncer.sm, h.Miner, lbts)
|
||||
eligible, err := stmgr.MinerEligibleToMine(ctx, syncer.sm, h.Miner, baseTs, lbts)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("determining if miner has min power failed: %w", err)
|
||||
}
|
||||
|
||||
if !hp {
|
||||
return xerrors.New("block's miner does not meet minimum power threshold")
|
||||
if !eligible {
|
||||
return xerrors.New("block's miner is ineligible to mine")
|
||||
}
|
||||
|
||||
rBeacon := *prevBeacon
|
||||
@@ -932,6 +943,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
winnerCheck,
|
||||
msgsCheck,
|
||||
baseFeeCheck,
|
||||
stateRootCheck,
|
||||
}
|
||||
|
||||
var merr error
|
||||
@@ -959,8 +971,10 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
return mulErr
|
||||
}
|
||||
|
||||
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil {
|
||||
return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err)
|
||||
if useCache {
|
||||
if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil {
|
||||
return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1083,7 +1097,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return xerrors.Errorf("failed to get actor: %w", err)
|
||||
}
|
||||
|
||||
if !act.IsAccountActor() {
|
||||
if !builtin.IsAccountActor(act.Code) {
|
||||
return xerrors.New("Sender must be an account actor")
|
||||
}
|
||||
nonces[m.From] = act.Nonce
|
||||
@@ -1097,9 +1111,9 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
return nil
|
||||
}
|
||||
|
||||
store := adt.WrapStore(ctx, cst)
|
||||
store := adt0.WrapStore(ctx, cst)
|
||||
|
||||
bmArr := adt.MakeEmptyArray(store)
|
||||
bmArr := adt0.MakeEmptyArray(store)
|
||||
for i, m := range b.BlsMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
|
||||
@@ -1111,7 +1125,7 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
|
||||
}
|
||||
}
|
||||
|
||||
smArr := adt.MakeEmptyArray(store)
|
||||
smArr := adt0.MakeEmptyArray(store)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
@@ -1273,9 +1287,11 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, incoming *types.TipSet
|
||||
|
||||
blockSet := []*types.TipSet{incoming}
|
||||
|
||||
// Parent of the new (possibly better) tipset that we need to fetch next.
|
||||
at := incoming.Parents()
|
||||
|
||||
// we want to sync all the blocks until the height above the block we have
|
||||
// we want to sync all the blocks until the height above our
|
||||
// best tipset so far
|
||||
untilHeight := known.Height() + 1
|
||||
|
||||
ss.SetHeight(blockSet[len(blockSet)-1].Height())
|
||||
@@ -1369,13 +1385,17 @@ loop:
|
||||
}
|
||||
|
||||
base := blockSet[len(blockSet)-1]
|
||||
if base.Parents() == known.Parents() {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
if base.IsChildOf(known) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
if types.CidArrsEqual(base.Parents().Cids(), known.Cids()) {
|
||||
// common case: receiving blocks that are building on top of our best tipset
|
||||
knownParent, err := syncer.store.LoadTipSet(known.Parents())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load next local tipset: %w", err)
|
||||
}
|
||||
if base.IsChildOf(knownParent) {
|
||||
// common case: receiving a block thats potentially part of the same tipset as our best block
|
||||
return blockSet, nil
|
||||
}
|
||||
|
||||
@@ -1462,7 +1482,7 @@ func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*
|
||||
|
||||
return syncer.iterFullTipsets(ctx, headers, func(ctx context.Context, fts *store.FullTipSet) error {
|
||||
log.Debugw("validating tipset", "height", fts.TipSet().Height(), "size", len(fts.TipSet().Cids()))
|
||||
if err := syncer.ValidateTipSet(ctx, fts); err != nil {
|
||||
if err := syncer.ValidateTipSet(ctx, fts, true); err != nil {
|
||||
log.Errorf("failed to validate tipset: %+v", err)
|
||||
return xerrors.Errorf("message processing failed: %w", err)
|
||||
}
|
||||
@@ -1482,8 +1502,6 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
|
||||
span.AddAttributes(trace.Int64Attribute("num_headers", int64(len(headers))))
|
||||
|
||||
windowSize := syncer.windowSize
|
||||
mainLoop:
|
||||
for i := len(headers) - 1; i >= 0; {
|
||||
fts, err := syncer.store.TryFillTipSet(headers[i])
|
||||
if err != nil {
|
||||
@@ -1497,35 +1515,20 @@ mainLoop:
|
||||
continue
|
||||
}
|
||||
|
||||
batchSize := windowSize
|
||||
batchSize := concurrentSyncRequests * syncRequestBatchSize
|
||||
if i < batchSize {
|
||||
batchSize = i
|
||||
batchSize = i + 1
|
||||
}
|
||||
|
||||
nextI := (i + 1) - batchSize // want to fetch batchSize values, 'i' points to last one we want to fetch, so its 'inclusive' of our request, thus we need to add one to our request start index
|
||||
|
||||
ss.SetStage(api.StageFetchingMessages)
|
||||
var bstout []*exchange.CompactedMessages
|
||||
for len(bstout) < batchSize {
|
||||
next := headers[nextI]
|
||||
|
||||
nreq := batchSize - len(bstout)
|
||||
bstips, err := syncer.Exchange.GetChainMessages(ctx, next, uint64(nreq))
|
||||
if err != nil {
|
||||
// TODO check errors for temporary nature
|
||||
if windowSize > 1 {
|
||||
windowSize /= 2
|
||||
log.Infof("error fetching messages: %s; reducing window size to %d and trying again", err, windowSize)
|
||||
continue mainLoop
|
||||
}
|
||||
return xerrors.Errorf("message processing failed: %w", err)
|
||||
}
|
||||
|
||||
bstout = append(bstout, bstips...)
|
||||
nextI += len(bstips)
|
||||
}
|
||||
startOffset := i + 1 - batchSize
|
||||
bstout, batchErr := syncer.fetchMessages(ctx, headers[startOffset:startOffset+batchSize], startOffset)
|
||||
ss.SetStage(api.StageMessages)
|
||||
|
||||
if batchErr != nil {
|
||||
return xerrors.Errorf("failed to fetch messages: %w", err)
|
||||
}
|
||||
|
||||
for bsi := 0; bsi < len(bstout); bsi++ {
|
||||
// temp storage so we don't persist data we dont want to
|
||||
bs := bstore.NewTemporary()
|
||||
@@ -1545,36 +1548,91 @@ mainLoop:
|
||||
return err
|
||||
}
|
||||
|
||||
if err := persistMessages(bs, bstip); err != nil {
|
||||
if err := persistMessages(ctx, bs, bstip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copyBlockstore(bs, syncer.store.Blockstore()); err != nil {
|
||||
if err := copyBlockstore(ctx, bs, syncer.store.Blockstore()); err != nil {
|
||||
return xerrors.Errorf("message processing failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if i >= windowSize {
|
||||
newWindowSize := windowSize + 10
|
||||
if newWindowSize > int(exchange.MaxRequestLength) {
|
||||
newWindowSize = int(exchange.MaxRequestLength)
|
||||
}
|
||||
if newWindowSize > windowSize {
|
||||
windowSize = newWindowSize
|
||||
log.Infof("successfully fetched %d messages; increasing window size to %d", len(bstout), windowSize)
|
||||
}
|
||||
}
|
||||
|
||||
i -= batchSize
|
||||
}
|
||||
|
||||
// remember our window size
|
||||
syncer.windowSize = windowSize
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func persistMessages(bs bstore.Blockstore, bst *exchange.CompactedMessages) error {
|
||||
func (syncer *Syncer) fetchMessages(ctx context.Context, headers []*types.TipSet, startOffset int) ([]*exchange.CompactedMessages, error) {
|
||||
batchSize := len(headers)
|
||||
batch := make([]*exchange.CompactedMessages, batchSize)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var mx sync.Mutex
|
||||
var batchErr error
|
||||
|
||||
start := build.Clock.Now()
|
||||
|
||||
for j := 0; j < batchSize; j += syncRequestBatchSize {
|
||||
wg.Add(1)
|
||||
go func(j int) {
|
||||
defer wg.Done()
|
||||
|
||||
nreq := syncRequestBatchSize
|
||||
if j+nreq > batchSize {
|
||||
nreq = batchSize - j
|
||||
}
|
||||
|
||||
failed := false
|
||||
for offset := 0; !failed && offset < nreq; {
|
||||
nextI := j + offset
|
||||
lastI := j + nreq
|
||||
|
||||
var requestErr error
|
||||
var requestResult []*exchange.CompactedMessages
|
||||
for retry := 0; requestResult == nil && retry < syncRequestRetries; retry++ {
|
||||
if retry > 0 {
|
||||
log.Infof("fetching messages at %d (retry %d)", startOffset+nextI, retry)
|
||||
} else {
|
||||
log.Infof("fetching messages at %d", startOffset+nextI)
|
||||
}
|
||||
|
||||
result, err := syncer.Exchange.GetChainMessages(ctx, headers[nextI:lastI])
|
||||
if err != nil {
|
||||
requestErr = multierror.Append(requestErr, err)
|
||||
} else {
|
||||
requestResult = result
|
||||
}
|
||||
}
|
||||
|
||||
mx.Lock()
|
||||
if requestResult != nil {
|
||||
copy(batch[j+offset:], requestResult)
|
||||
offset += len(requestResult)
|
||||
} else {
|
||||
log.Errorf("error fetching messages at %d: %s", nextI, requestErr)
|
||||
batchErr = multierror.Append(batchErr, requestErr)
|
||||
failed = true
|
||||
}
|
||||
mx.Unlock()
|
||||
}
|
||||
}(j)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if batchErr != nil {
|
||||
return nil, batchErr
|
||||
}
|
||||
|
||||
log.Infof("fetching messages for %d tipsets at %d done; took %s", batchSize, startOffset, build.Clock.Since(start))
|
||||
|
||||
return batch, nil
|
||||
}
|
||||
|
||||
func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.CompactedMessages) error {
|
||||
_, span := trace.StartSpan(ctx, "persistMessages")
|
||||
defer span.End()
|
||||
|
||||
for _, m := range bst.Bls {
|
||||
//log.Infof("putting BLS message: %s", m.Cid())
|
||||
if _, err := store.PutMessage(bs, m); err != nil {
|
||||
@@ -1706,7 +1764,7 @@ func (syncer *Syncer) getLatestBeaconEntry(_ context.Context, ts *types.TipSet)
|
||||
cur = next
|
||||
}
|
||||
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
|
||||
return nil, xerrors.Errorf("found NO beacon entries in the 20 latest tipsets")
|
||||
}
|
||||
|
||||
func (syncer *Syncer) IsEpochBeyondCurrMax(epoch abi.ChainEpoch) bool {
|
||||
|
||||
+6
-11
@@ -19,13 +19,10 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
||||
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
||||
verifreg0 "github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
"github.com/filecoin-project/lotus/chain/gen"
|
||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@@ -43,11 +40,9 @@ func init() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
miner0.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{
|
||||
abi.RegisteredSealProof_StackedDrg2KiBV1: {},
|
||||
}
|
||||
power0.ConsensusMinerMinPower = big.NewInt(2048)
|
||||
verifreg0.MinVerifiedDealSize = big.NewInt(256)
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
}
|
||||
|
||||
const source = 0
|
||||
@@ -737,7 +732,7 @@ func TestSyncInputs(t *testing.T) {
|
||||
|
||||
err := s.ValidateBlock(context.TODO(), &types.FullBlock{
|
||||
Header: &types.BlockHeader{},
|
||||
})
|
||||
}, false)
|
||||
if err == nil {
|
||||
t.Fatal("should error on empty block")
|
||||
}
|
||||
@@ -746,7 +741,7 @@ func TestSyncInputs(t *testing.T) {
|
||||
|
||||
h.ElectionProof = nil
|
||||
|
||||
err = s.ValidateBlock(context.TODO(), &types.FullBlock{Header: h})
|
||||
err = s.ValidateBlock(context.TODO(), &types.FullBlock{Header: h}, false)
|
||||
if err == nil {
|
||||
t.Fatal("should error on block with nil election proof")
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
var ErrActorNotFound = errors.New("actor not found")
|
||||
@@ -17,7 +15,3 @@ type Actor struct {
|
||||
Nonce uint64
|
||||
Balance BigInt
|
||||
}
|
||||
|
||||
func (a *Actor) IsAccountActor() bool {
|
||||
return a.Code == builtin.AccountActorCodeID
|
||||
}
|
||||
|
||||
@@ -1648,7 +1648,7 @@ func (t *StateRoot) MarshalCBOR(w io.Writer) error {
|
||||
|
||||
scratch := make([]byte, 9)
|
||||
|
||||
// t.Version (uint64) (uint64)
|
||||
// t.Version (types.StateTreeVersion) (uint64)
|
||||
|
||||
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Version)); err != nil {
|
||||
return err
|
||||
@@ -1687,7 +1687,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Version (uint64) (uint64)
|
||||
// t.Version (types.StateTreeVersion) (uint64)
|
||||
|
||||
{
|
||||
|
||||
@@ -1698,7 +1698,7 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Version = uint64(extra)
|
||||
t.Version = StateTreeVersion(extra)
|
||||
|
||||
}
|
||||
// t.Actors (cid.Cid) (struct)
|
||||
@@ -1728,22 +1728,22 @@ func (t *StateRoot) UnmarshalCBOR(r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufStateInfo = []byte{128}
|
||||
var lengthBufStateInfo0 = []byte{128}
|
||||
|
||||
func (t *StateInfo) MarshalCBOR(w io.Writer) error {
|
||||
func (t *StateInfo0) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(lengthBufStateInfo); err != nil {
|
||||
if _, err := w.Write(lengthBufStateInfo0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *StateInfo) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = StateInfo{}
|
||||
func (t *StateInfo0) UnmarshalCBOR(r io.Reader) error {
|
||||
*t = StateInfo0{}
|
||||
|
||||
br := cbg.GetPeeker(r)
|
||||
scratch := make([]byte, 8)
|
||||
|
||||
+6
-2
@@ -12,11 +12,15 @@ import (
|
||||
type FIL BigInt
|
||||
|
||||
func (f FIL) String() string {
|
||||
return f.Unitless() + " FIL"
|
||||
}
|
||||
|
||||
func (f FIL) Unitless() string {
|
||||
r := new(big.Rat).SetFrac(f.Int, big.NewInt(int64(build.FilecoinPrecision)))
|
||||
if r.Sign() == 0 {
|
||||
return "0 FIL"
|
||||
return "0"
|
||||
}
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".") + " FIL"
|
||||
return strings.TrimRight(strings.TrimRight(r.FloatString(18), "0"), ".")
|
||||
}
|
||||
|
||||
func (f FIL) Format(s fmt.State, ch rune) {
|
||||
|
||||
+14
-3
@@ -2,9 +2,20 @@ package types
|
||||
|
||||
import "github.com/ipfs/go-cid"
|
||||
|
||||
// StateTreeVersion is the version of the state tree itself, independent of the
|
||||
// network version or the actors version.
|
||||
type StateTreeVersion uint64
|
||||
|
||||
const (
|
||||
// StateTreeVersion0 corresponds to actors < v2.
|
||||
StateTreeVersion0 StateTreeVersion = iota
|
||||
// StateTreeVersion1 corresponds to actors >= v2.
|
||||
StateTreeVersion1
|
||||
)
|
||||
|
||||
type StateRoot struct {
|
||||
// State root version. Versioned along with actors (for now).
|
||||
Version uint64
|
||||
// State tree version.
|
||||
Version StateTreeVersion
|
||||
// Actors tree. The structure depends on the state root version.
|
||||
Actors cid.Cid
|
||||
// Info. The structure depends on the state root version.
|
||||
@@ -12,4 +23,4 @@ type StateRoot struct {
|
||||
}
|
||||
|
||||
// TODO: version this.
|
||||
type StateInfo struct{}
|
||||
type StateInfo0 struct{}
|
||||
|
||||
@@ -167,12 +167,16 @@ func (ts *TipSet) Equals(ots *TipSet) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(ts.blks) != len(ots.blks) {
|
||||
if ts.height != ots.height {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, b := range ts.blks {
|
||||
if b.Cid() != ots.blks[i].Cid() {
|
||||
if len(ts.cids) != len(ots.cids) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, cid := range ts.cids {
|
||||
if cid != ots.cids[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user