Compare commits
531
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41bfeb56e2 | ||
|
|
2e7cd024df | ||
|
|
bf619862c3 | ||
|
|
29e54c40be | ||
|
|
308144ee6a | ||
|
|
ce54110228 | ||
|
|
458ea277fc | ||
|
|
58662b79b3 | ||
|
|
7dbc8965be | ||
|
|
2426700821 | ||
|
|
9c6ee802cc | ||
|
|
b61281ba4b | ||
|
|
d5cea9f402 | ||
|
|
ce548c8f95 | ||
|
|
8987defb9d | ||
|
|
1a70dbe37d | ||
|
|
87cd8c6725 | ||
|
|
5fd0bf11ba | ||
|
|
4edebcec2b | ||
|
|
9b4cac9612 | ||
|
|
8232cc8415 | ||
|
|
be74a13736 | ||
|
|
195d96ccc0 | ||
|
|
49155ace62 | ||
|
|
83624a8858 | ||
|
|
96e1dfd8d7 | ||
|
|
61661fb1f0 | ||
|
|
6c08120628 | ||
|
|
8d769f0c07 | ||
|
|
79c5d2c6d2 | ||
|
|
224a96431f | ||
|
|
2855c2bc49 | ||
|
|
65883cbb6b | ||
|
|
443131b214 | ||
|
|
8b648cf77c | ||
|
|
c0961fb63d | ||
|
|
dc4e73c737 | ||
|
|
a6b2180756 | ||
|
|
160f209f6a | ||
|
|
a9d8bc7c45 | ||
|
|
92177b5738 | ||
|
|
4ac2bee81c | ||
|
|
a2e0832a12 | ||
|
|
8fd9b5f235 | ||
|
|
a95e343dee | ||
|
|
c296e1bbca | ||
|
|
ae366972a9 | ||
|
|
b4215e5f46 | ||
|
|
df7ee610cd | ||
|
|
fda8b932ba | ||
|
|
7b4a5fc7ca | ||
|
|
d6c8276c7a | ||
|
|
2b21fdef33 | ||
|
|
6a232e7214 | ||
|
|
7ee6bafd23 | ||
|
|
753d7b71a9 | ||
|
|
bb6a354b62 | ||
|
|
8ae66d6c6a | ||
|
|
2c92157233 | ||
|
|
66d6113340 | ||
|
|
99791a6953 | ||
|
|
b35f9b56b4 | ||
|
|
23470bc38f | ||
|
|
40b2e2d0c1 | ||
|
|
00620aac57 | ||
|
|
32d95fc97a | ||
|
|
a491fc97b9 | ||
|
|
151577f04e | ||
|
|
c463582528 | ||
|
|
7245ac2b69 | ||
|
|
58f13a7d5a | ||
|
|
e7d3b2503e | ||
|
|
ee8b8b8174 | ||
|
|
4fa6afad13 | ||
|
|
a80e98dc05 | ||
|
|
23f5a99117 | ||
|
|
651522cbaa | ||
|
|
388c9afce0 | ||
|
|
9a26896c69 | ||
|
|
2db8b7efa7 | ||
|
|
18e58467f8 | ||
|
|
1401efb115 | ||
|
|
f417d39a08 | ||
|
|
11e35cf911 | ||
|
|
10d464a1eb | ||
|
|
d84f5dabab | ||
|
|
f3abd1ae82 | ||
|
|
85abca4b16 | ||
|
|
6610a247cf | ||
|
|
a6d9b302fa | ||
|
|
f32b3bf99b | ||
|
|
114a1aaffd | ||
|
|
83ba7ec8cc | ||
|
|
83dfc460d4 | ||
|
|
283fd054e8 | ||
|
|
09bff14d85 | ||
|
|
3cb1abba4f | ||
|
|
d4c92942e7 | ||
|
|
f773ab4b28 | ||
|
|
c0182f8301 | ||
|
|
c06f394b81 | ||
|
|
748d2e82a7 | ||
|
|
a5c78371fd | ||
|
|
d80e7eda93 | ||
|
|
9f9d5cb2a5 | ||
|
|
fdaa9c14ad | ||
|
|
9d8932d395 | ||
|
|
105aa40007 | ||
|
|
110f033c83 | ||
|
|
f87d325b6f | ||
|
|
ab8286fa38 | ||
|
|
4cca3f19a3 | ||
|
|
feb4b3c8b4 | ||
|
|
7f7c9e978f | ||
|
|
200a95f824 | ||
|
|
d69e4c7cf2 | ||
|
|
b2834baa4b | ||
|
|
e9e27cbbb0 | ||
|
|
ef73b964fb | ||
|
|
7b1bec91ed | ||
|
|
b32d25c562 | ||
|
|
767611247c | ||
|
|
be09a8a00a | ||
|
|
2719adc1b1 | ||
|
|
f1b1d8cec6 | ||
|
|
8fa4c0a970 | ||
|
|
00a14de094 | ||
|
|
eec13ff8dc | ||
|
|
1ffdd7d5b3 | ||
|
|
e19cd9ed01 | ||
|
|
bacac245c7 | ||
|
|
e1792ffe4d | ||
|
|
9c35762966 | ||
|
|
356137439f | ||
|
|
6cc7559b04 | ||
|
|
3cd53ad9d9 | ||
|
|
6c54d2445d | ||
|
|
6a10af626c | ||
|
|
597d065e05 | ||
|
|
791aa5c6c8 | ||
|
|
82b15d2637 | ||
|
|
7d2f06cfbd | ||
|
|
6e8efb9d2c | ||
|
|
f3dc730b05 | ||
|
|
114776f2c5 | ||
|
|
4835109470 | ||
|
|
8783c7434e | ||
|
|
2d3b61675b | ||
|
|
a23ab123d7 | ||
|
|
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 | ||
|
|
ef3987e2ab | ||
|
|
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 | ||
|
|
044674487e | ||
|
|
0070d2716c | ||
|
|
9b403e26e5 | ||
|
|
4b3b35c9de | ||
|
|
64f24fd276 | ||
|
|
124bd0c765 | ||
|
|
96f882860f | ||
|
|
9f6862a456 | ||
|
|
4c9717187f | ||
|
|
a0dffb44d3 | ||
|
|
8f3be78667 | ||
|
|
dfdcbd184d | ||
|
|
f05a40feed | ||
|
|
c33b3dfa55 | ||
|
|
9a355c4bc5 | ||
|
|
fe869c9c22 | ||
|
|
f5f23f7291 | ||
|
|
a712c109d8 | ||
|
|
e5c56da321 | ||
|
|
be5dc2c57f | ||
|
|
e4c1f090af | ||
|
|
fb3bcc4ce5 | ||
|
|
1483f1e59a | ||
|
|
10cdbadd82 | ||
|
|
8955b8d8a7 | ||
|
|
650725d71e | ||
|
|
80a7ed8116 | ||
|
|
13b38815c2 | ||
|
|
e48c525053 | ||
|
|
7eb9bec13f | ||
|
|
3c524ac0e0 | ||
|
|
c66f087f4c | ||
|
|
ad3db0e83c | ||
|
|
a5e7fd8f5c | ||
|
|
e6bbc03ca8 | ||
|
|
e39036dd49 | ||
|
|
26de0db757 | ||
|
|
9e2df907f8 | ||
|
|
3c72461969 | ||
|
|
dfd28ab0c4 | ||
|
|
784399738a | ||
|
|
bc9232544c | ||
|
|
591e32af48 | ||
|
|
a4fd356fcb | ||
|
|
6849d18b03 | ||
|
|
ca956ca57e | ||
|
|
6670d22fb5 | ||
|
|
e53aee26a3 | ||
|
|
c610bd818e | ||
|
|
780f6dba34 | ||
|
|
f90cfda2e6 | ||
|
|
bd0c6a4ccc | ||
|
|
af38c902f8 | ||
|
|
a153e1d586 | ||
|
|
fe52c47570 | ||
|
|
f58e8bc9a3 | ||
|
|
cac848c106 |
@@ -13,3 +13,4 @@
|
||||
### Conformance testing.
|
||||
conformance/ @raulk
|
||||
extern/test-vectors @raulk
|
||||
cmd/tvx @raulk
|
||||
@@ -12,6 +12,7 @@
|
||||
/lotus-bench
|
||||
/lotus-gateway
|
||||
/lotus-pcr
|
||||
/lotus-wallet
|
||||
/bench.json
|
||||
/lotuspond/front/node_modules
|
||||
/lotuspond/front/build
|
||||
|
||||
+222
-1
@@ -1,5 +1,226 @@
|
||||
# Lotus changelog
|
||||
|
||||
# 0.10.1 / 2020-10-14
|
||||
|
||||
This is an optional release of Lotus that updates markets to 0.9.0, which adds the ability to restart data transfers. This release also introduces Ledger support, and various UX improvements.
|
||||
|
||||
## Changes
|
||||
|
||||
- Test the tape upgrade (https://github.com/filecoin-project/lotus/pull/4328)
|
||||
- Adding in Ledger support (https://github.com/filecoin-project/lotus/pull/4290)
|
||||
- Improve the UX for lotus-miner sealing workers (https://github.com/filecoin-project/lotus/pull/4329)
|
||||
- Add a CLI tool for miner's to repay debt (https://github.com/filecoin-project/lotus/pull/4319)
|
||||
- Rename params_testnet to params_mainnet (https://github.com/filecoin-project/lotus/pull/4336)
|
||||
- Use seal-duration in calculating the earliest StartEpoch (https://github.com/filecoin-project/lotus/pull/4337)
|
||||
- Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173)
|
||||
- Add an API endpoint to calculate the exact circulating supply (https://github.com/filecoin-project/lotus/pull/4148)
|
||||
- lotus-pcr: ignore all other market messages (https://github.com/filecoin-project/lotus/pull/4341)
|
||||
- Add message CID to InvocResult (https://github.com/filecoin-project/lotus/pull/4382)
|
||||
- types: Add CID fields to messages in json marshalers (https://github.com/filecoin-project/lotus/pull/4338)
|
||||
- fix(sync state): set state height to actual tipset height (https://github.com/filecoin-project/lotus/pull/4347)
|
||||
- Fix off by one tipset in searchBackForMsg (https://github.com/filecoin-project/lotus/pull/4367)
|
||||
- fix a panic on startup when we fail to load the tipset (https://github.com/filecoin-project/lotus/pull/4376)
|
||||
- Avoid having the same message CID show up in execution traces (https://github.com/filecoin-project/lotus/pull/4350)
|
||||
- feat(markets): update markets 0.9.0 and add data transfer restart (https://github.com/filecoin-project/lotus/pull/4363)
|
||||
|
||||
# 0.10.0 / 2020-10-12
|
||||
|
||||
This is a consensus-breaking hotfix that addresses an issue in specs-actors v2.0.3 that made it impossible to pledge new 32GiB sectors. The change in Lotus is to update to actors v2.1.0, behind the new network version 5.
|
||||
|
||||
## Changes
|
||||
|
||||
- make pledge test pass with the race detector (https://github.com/filecoin-project/lotus/pull/4291)
|
||||
- fix a race in tipset cache usage (https://github.com/filecoin-project/lotus/pull/4282)
|
||||
- add an api for removing multisig signers (https://github.com/filecoin-project/lotus/pull/4274)
|
||||
- cli: Don't output errors to stdout (https://github.com/filecoin-project/lotus/pull/4298)
|
||||
- Fix panic in wallet export when key is not found (https://github.com/filecoin-project/lotus/pull/4299)
|
||||
- Dump the block validation cache whenever we perform an import (https://github.com/filecoin-project/lotus/pull/4287)
|
||||
- Fix two races (https://github.com/filecoin-project/lotus/pull/4301)
|
||||
- sync unmark-bad --all (https://github.com/filecoin-project/lotus/pull/4296)
|
||||
- decode parameters for multisig transactions in inspect (https://github.com/filecoin-project/lotus/pull/4312)
|
||||
- Chain is love (https://github.com/filecoin-project/lotus/pull/4321)
|
||||
- lotus-stats: optmize getting miner power (https://github.com/filecoin-project/lotus/pull/4315)
|
||||
- implement tape upgrade (https://github.com/filecoin-project/lotus/pull/4322)
|
||||
|
||||
# 0.9.1 / 2020-10-10
|
||||
|
||||
This release fixes an issue which may cause the actors v2 migration to compute the state incorrectly when more than one migration is running in parallel.
|
||||
|
||||
## Changes
|
||||
|
||||
- Make concurrent actor migrations safe (https://github.com/filecoin-project/lotus/pull/4293)
|
||||
- Remote wallet backends (https://github.com/filecoin-project/lotus/pull/3583)
|
||||
- Track funds in FundMgr correctly in case of AddFunds failing (https://github.com/filecoin-project/lotus/pull/4273)
|
||||
- Partial lite-node mode (https://github.com/filecoin-project/lotus/pull/4095)
|
||||
- Fix potential infinite loop in GetBestMiningCandidate (https://github.com/filecoin-project/lotus/pull/3444)
|
||||
- sync wait: Handle processed message offset (https://github.com/filecoin-project/lotus/pull/4253)
|
||||
- Add some new endpoints for querying Msig info (https://github.com/filecoin-project/lotus/pull/4250)
|
||||
- Update markets v0.7.1 (https://github.com/filecoin-project/lotus/pull/4254)
|
||||
- Optimize SearchForMessage and GetReceipt (https://github.com/filecoin-project/lotus/pull/4246)
|
||||
- Use FIL instead of attoFIL in CLI more consistently (https://github.com/filecoin-project/lotus/pull/4249)
|
||||
- fix: clash between daemon --api flag and cli tests (https://github.com/filecoin-project/lotus/pull/4241)
|
||||
- add more info to chain sync lookback failure (https://github.com/filecoin-project/lotus/pull/4245)
|
||||
- Add message counts to inspect chain output (https://github.com/filecoin-project/lotus/pull/4230)
|
||||
|
||||
# 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:
|
||||
@@ -51,7 +272,7 @@ We are grateful for every contribution!
|
||||
| vyzo | 22 | +287/-196 |
|
||||
| alanshaw | 15 | +761/-146 |
|
||||
| whyrusleeping | 15 | +736/-52 |
|
||||
| hannahhoward | 14 | +1237/837- |
|
||||
| hannahhoward | 14 | +1237/-837 |
|
||||
| anton | 6 | +32/-8 |
|
||||
| travisperson | 5 | +502/-6 |
|
||||
| Frank | 5 | +78/-39 |
|
||||
|
||||
@@ -186,6 +186,12 @@ lotus-health:
|
||||
.PHONY: lotus-health
|
||||
BINS+=lotus-health
|
||||
|
||||
lotus-wallet:
|
||||
rm -f lotus-wallet
|
||||
go build -o lotus-wallet ./cmd/lotus-wallet
|
||||
.PHONY: lotus-wallet
|
||||
BINS+=lotus-wallet
|
||||
|
||||
testground:
|
||||
go build -tags testground -o /dev/null ./cmd/lotus
|
||||
.PHONY: testground
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+83
-15
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
@@ -172,10 +173,16 @@ type FullNode interface {
|
||||
// SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.
|
||||
SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
|
||||
// SyncUnmarkAllBad purges bad block cache, making it possible to sync to chains previously marked as bad
|
||||
SyncUnmarkAllBad(ctx context.Context) error
|
||||
|
||||
// SyncCheckBad checks if a block was marked as bad, and if it was, returns
|
||||
// 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.
|
||||
@@ -189,6 +196,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
|
||||
@@ -220,7 +230,9 @@ type FullNode interface {
|
||||
// MethodGroup: Wallet
|
||||
|
||||
// WalletNew creates a new address in the wallet with the given sigType.
|
||||
WalletNew(context.Context, crypto.SigType) (address.Address, error)
|
||||
// Available key types: bls, secp256k1, secp256k1-ledger
|
||||
// Support for numerical types: 1 - secp256k1, 2 - BLS is deprecated
|
||||
WalletNew(context.Context, types.KeyType) (address.Address, error)
|
||||
// WalletHas indicates whether the given address is in the wallet.
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
// WalletList lists all the addresses in the wallet.
|
||||
@@ -244,6 +256,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
|
||||
|
||||
@@ -275,7 +289,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.
|
||||
@@ -285,6 +299,8 @@ type FullNode interface {
|
||||
// ClientListTransfers returns the status of all ongoing transfers of data
|
||||
ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error)
|
||||
ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error)
|
||||
// ClientRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer
|
||||
ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error
|
||||
// ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel
|
||||
// which are stuck due to insufficient funds
|
||||
ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error
|
||||
@@ -359,6 +375,10 @@ type FullNode interface {
|
||||
// StateWaitMsg looks back in the chain for a message. If not found, it blocks until the
|
||||
// message arrives on chain, and gets to the indicated confidence depth.
|
||||
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
// StateWaitMsgLimited looks back up to limit epochs in the chain for a message.
|
||||
// If not found, it blocks until the message arrives on chain, and gets to the
|
||||
// indicated confidence depth.
|
||||
StateWaitMsgLimited(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch) (*MsgLookup, error)
|
||||
// StateListMiners returns the addresses of every miner that has claimed power in the Power Actor
|
||||
StateListMiners(context.Context, types.TipSetKey) ([]address.Address, error)
|
||||
// StateListActors returns the addresses of every actor in the state
|
||||
@@ -385,16 +405,26 @@ 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)
|
||||
|
||||
// StateCirculatingSupply returns the circulating supply of Filecoin at the given tipset
|
||||
StateCirculatingSupply(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||
// StateCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.
|
||||
// This is not used anywhere in the protocol itself, and is only for external consumption.
|
||||
StateCirculatingSupply(context.Context, types.TipSetKey) (abi.TokenAmount, error)
|
||||
// StateVMCirculatingSupplyInternal returns an approximation of the circulating supply of Filecoin at the given tipset.
|
||||
// This is the value reported by the runtime interface to actors code.
|
||||
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (CirculatingSupply, error)
|
||||
// StateNetworkVersion returns the network version at the given tipset
|
||||
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
||||
|
||||
@@ -404,6 +434,8 @@ 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)
|
||||
// MsigGetVestingSchedule returns the vesting details of a given multisig.
|
||||
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)
|
||||
@@ -415,12 +447,21 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the propose msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigPropose(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigApprove approves a previously-proposed multisig message
|
||||
|
||||
// MsigApprove approves a previously-proposed multisig message by transaction ID
|
||||
// It takes the following params: <multisig address>, <proposed transaction ID> <signer address>
|
||||
MsigApprove(context.Context, address.Address, uint64, address.Address) (cid.Cid, error)
|
||||
|
||||
// MsigApproveTxnHash approves a previously-proposed multisig message, specified
|
||||
// using both transaction ID and a hash of the parameters used in the
|
||||
// proposal. This method of approval can be used to ensure you only approve
|
||||
// exactly the transaction you think you are.
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <proposer address>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the approve msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigApprove(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
MsigApproveTxnHash(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
|
||||
// MsigCancel cancels a previously-proposed multisig message
|
||||
// It takes the following params: <multisig address>, <proposed message ID>, <recipient address>, <value to transfer>,
|
||||
// It takes the following params: <multisig address>, <proposed transaction ID>, <recipient address>, <value to transfer>,
|
||||
// <sender address of the cancel msg>, <method to call in the proposed message>, <params to include in the proposed message>
|
||||
MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error)
|
||||
// MsigAddPropose proposes adding a signer in the multisig
|
||||
@@ -448,6 +489,13 @@ type FullNode interface {
|
||||
// <old signer>, <new signer>
|
||||
MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error)
|
||||
|
||||
// MsigRemoveSigner proposes the removal of a signer from the multisig.
|
||||
// It accepts the multisig to make the change on, the proposer address to
|
||||
// send the message from, the address to be removed, and a boolean
|
||||
// indicating whether or not the signing threshold should be lowered by one
|
||||
// along with the address removal.
|
||||
MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error)
|
||||
|
||||
MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error)
|
||||
// MarketFreeBalance
|
||||
|
||||
@@ -470,6 +518,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 {
|
||||
@@ -516,6 +570,7 @@ type DealInfo struct {
|
||||
DealID abi.DealID
|
||||
|
||||
CreationTime time.Time
|
||||
Verified bool
|
||||
}
|
||||
|
||||
type MsgLookup struct {
|
||||
@@ -682,6 +737,7 @@ type RetrievalOrder struct {
|
||||
}
|
||||
|
||||
type InvocResult struct {
|
||||
MsgCid cid.Cid
|
||||
Msg *types.Message
|
||||
MsgRct *types.MessageReceipt
|
||||
ExecutionTrace types.ExecutionTrace
|
||||
@@ -791,14 +847,14 @@ type CirculatingSupply struct {
|
||||
}
|
||||
|
||||
type MiningBaseInfo struct {
|
||||
MinerPower types.BigInt
|
||||
NetworkPower types.BigInt
|
||||
Sectors []builtin.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 {
|
||||
@@ -850,3 +906,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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
type GatewayAPI interface {
|
||||
ChainHead(ctx context.Context) (*types.TipSet, error)
|
||||
ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||
MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||
StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*MsgLookup, error)
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type MsgType string
|
||||
|
||||
const (
|
||||
MTUnknown = "unknown"
|
||||
|
||||
// Signing message CID. MsgMeta.Extra contains raw cbor message bytes
|
||||
MTChainMsg = "message"
|
||||
|
||||
// Signing a blockheader. signing raw cbor block bytes (MsgMeta.Extra is empty)
|
||||
MTBlock = "block"
|
||||
|
||||
// Signing a deal proposal. signing raw cbor proposal bytes (MsgMeta.Extra is empty)
|
||||
MTDealProposal = "dealproposal"
|
||||
|
||||
// TODO: Deals, Vouchers, VRF
|
||||
)
|
||||
|
||||
type MsgMeta struct {
|
||||
Type MsgType
|
||||
|
||||
// Additional data related to what is signed. Should be verifiable with the
|
||||
// signed bytes (e.g. CID(Extra).Bytes() == toSign)
|
||||
Extra []byte
|
||||
}
|
||||
|
||||
type WalletAPI interface {
|
||||
WalletNew(context.Context, types.KeyType) (address.Address, error)
|
||||
WalletHas(context.Context, address.Address) (bool, error)
|
||||
WalletList(context.Context) ([]address.Address, error)
|
||||
|
||||
WalletSign(ctx context.Context, signer address.Address, toSign []byte, meta MsgMeta) (*crypto.Signature, error)
|
||||
|
||||
WalletExport(context.Context, address.Address) (*types.KeyInfo, error)
|
||||
WalletImport(context.Context, *types.KeyInfo) (address.Address, error)
|
||||
WalletDelete(context.Context, address.Address) error
|
||||
}
|
||||
@@ -36,3 +36,9 @@ func PermissionedWorkerAPI(a api.WorkerAPI) api.WorkerAPI {
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
func PermissionedWalletAPI(a api.WalletAPI) api.WalletAPI {
|
||||
var out WalletStruct
|
||||
auth.PermissionedProxy(AllPermissions, DefaultPerms, a, &out.Internal)
|
||||
return &out
|
||||
}
|
||||
|
||||
+198
-21
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-bitfield"
|
||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||
@@ -111,7 +112,9 @@ type FullNodeStruct struct {
|
||||
SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"`
|
||||
SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"`
|
||||
SyncUnmarkAllBad func(ctx context.Context) 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"`
|
||||
@@ -121,7 +124,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"`
|
||||
@@ -129,18 +134,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, types.KeyType) (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"`
|
||||
@@ -154,12 +160,13 @@ 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"`
|
||||
ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"`
|
||||
ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"`
|
||||
ClientRestartDataTransfer func(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error `perm:"write"`
|
||||
ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"`
|
||||
|
||||
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
|
||||
@@ -186,6 +193,7 @@ type FullNodeStruct struct {
|
||||
StateReadState func(context.Context, address.Address, types.TipSetKey) (*api.ActorState, error) `perm:"read"`
|
||||
StateMsgGasCost func(context.Context, cid.Cid, types.TipSetKey) (*api.MsgGasCost, error) `perm:"read"`
|
||||
StateWaitMsg func(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateWaitMsgLimited func(context.Context, cid.Cid, uint64, abi.ChainEpoch) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateSearchMsg func(context.Context, cid.Cid) (*api.MsgLookup, error) `perm:"read"`
|
||||
StateListMiners func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
StateListActors func(context.Context, types.TipSetKey) ([]address.Address, error) `perm:"read"`
|
||||
@@ -200,16 +208,21 @@ 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"`
|
||||
StateCirculatingSupply func(context.Context, types.TipSetKey) (abi.TokenAmount, error) `perm:"read"`
|
||||
StateVMCirculatingSupplyInternal 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"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApprove func(context.Context, address.Address, uint64, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigApproveTxnHash func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"`
|
||||
@@ -217,6 +230,7 @@ type FullNodeStruct struct {
|
||||
MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"`
|
||||
MsigRemoveSigner func(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||
|
||||
@@ -237,6 +251,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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +333,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"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,6 +368,35 @@ type WorkerStruct struct {
|
||||
}
|
||||
}
|
||||
|
||||
type GatewayStruct struct {
|
||||
Internal struct {
|
||||
// TODO: does the gateway need perms?
|
||||
ChainGetTipSet func(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainGetTipSetByHeight func(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
|
||||
ChainHead func(ctx context.Context) (*types.TipSet, error)
|
||||
GasEstimateMessageGas func(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error)
|
||||
MpoolPush func(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error)
|
||||
MsigGetAvailableBalance func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error)
|
||||
MsigGetVested func(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
|
||||
StateAccountKey func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateGetActor func(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
||||
StateLookupID func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsg func(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
||||
}
|
||||
}
|
||||
|
||||
type WalletStruct struct {
|
||||
Internal struct {
|
||||
WalletNew func(context.Context, types.KeyType) (address.Address, error) `perm:"write"`
|
||||
WalletHas func(context.Context, address.Address) (bool, error) `perm:"write"`
|
||||
WalletList func(context.Context) ([]address.Address, error) `perm:"write"`
|
||||
WalletSign func(context.Context, address.Address, []byte, api.MsgMeta) (*crypto.Signature, error) `perm:"sign"`
|
||||
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"`
|
||||
}
|
||||
}
|
||||
|
||||
// CommonStruct
|
||||
|
||||
func (c *CommonStruct) AuthVerify(ctx context.Context, token string) ([]auth.Permission, error) {
|
||||
@@ -484,7 +531,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) {
|
||||
@@ -507,6 +554,10 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan
|
||||
return c.Internal.ClientDataTransferUpdates(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRestartDataTransfer(ctx context.Context, transferID datatransfer.TransferID, otherPeer peer.ID, isInitiator bool) error {
|
||||
return c.Internal.ClientRestartDataTransfer(ctx, transferID, otherPeer, isInitiator)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error {
|
||||
return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel)
|
||||
}
|
||||
@@ -551,6 +602,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)
|
||||
}
|
||||
@@ -583,7 +638,7 @@ func (c *FullNodeStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.Chain
|
||||
return c.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ crypto.SigType) (address.Address, error) {
|
||||
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||
return c.Internal.WalletNew(ctx, typ)
|
||||
}
|
||||
|
||||
@@ -631,6 +686,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)
|
||||
}
|
||||
@@ -731,10 +790,18 @@ func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error
|
||||
return c.Internal.SyncUnmarkBad(ctx, bcid)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncUnmarkAllBad(ctx context.Context) error {
|
||||
return c.Internal.SyncUnmarkAllBad(ctx)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) {
|
||||
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)
|
||||
}
|
||||
@@ -831,6 +898,10 @@ func (c *FullNodeStruct) StateWaitMsg(ctx context.Context, msgc cid.Cid, confide
|
||||
return c.Internal.StateWaitMsg(ctx, msgc, confidence)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateWaitMsgLimited(ctx context.Context, msgc cid.Cid, confidence uint64, limit abi.ChainEpoch) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateWaitMsgLimited(ctx, msgc, confidence, limit)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateSearchMsg(ctx context.Context, msgc cid.Cid) (*api.MsgLookup, error) {
|
||||
return c.Internal.StateSearchMsg(ctx, msgc)
|
||||
}
|
||||
@@ -883,18 +954,30 @@ 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)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||
func (c *FullNodeStruct) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (abi.TokenAmount, error) {
|
||||
return c.Internal.StateCirculatingSupply(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateVMCirculatingSupplyInternal(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
|
||||
return c.Internal.StateVMCirculatingSupplyInternal(ctx, tsk)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (stnetwork.Version, error) {
|
||||
return c.Internal.StateNetworkVersion(ctx, tsk)
|
||||
}
|
||||
@@ -903,6 +986,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)
|
||||
}
|
||||
@@ -915,8 +1002,12 @@ func (c *FullNodeStruct) MsigPropose(ctx context.Context, msig address.Address,
|
||||
return c.Internal.MsigPropose(ctx, msig, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigApprove(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
func (c *FullNodeStruct) MsigApprove(ctx context.Context, msig address.Address, txID uint64, signer address.Address) (cid.Cid, error) {
|
||||
return c.Internal.MsigApprove(ctx, msig, txID, signer)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigApproveTxnHash(ctx context.Context, msig address.Address, txID uint64, proposer address.Address, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
return c.Internal.MsigApproveTxnHash(ctx, msig, txID, proposer, to, amt, src, method, params)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, txID uint64, to address.Address, amt types.BigInt, src address.Address, method uint64, params []byte) (cid.Cid, error) {
|
||||
@@ -947,6 +1038,10 @@ func (c *FullNodeStruct) MsigSwapCancel(ctx context.Context, msig address.Addres
|
||||
return c.Internal.MsigSwapCancel(ctx, msig, src, txID, oldAdd, newAdd)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MsigRemoveSigner(ctx context.Context, msig address.Address, proposer address.Address, toRemove address.Address, decrease bool) (cid.Cid, error) {
|
||||
return c.Internal.MsigRemoveSigner(ctx, msig, proposer, toRemove, decrease)
|
||||
}
|
||||
|
||||
func (c *FullNodeStruct) MarketEnsureAvailable(ctx context.Context, addr, wallet address.Address, amt types.BigInt) (cid.Cid, error) {
|
||||
return c.Internal.MarketEnsureAvailable(ctx, addr, wallet, amt)
|
||||
}
|
||||
@@ -1015,6 +1110,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) {
|
||||
@@ -1255,6 +1354,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) {
|
||||
@@ -1329,7 +1432,81 @@ func (w *WorkerStruct) Closing(ctx context.Context) (<-chan struct{}, error) {
|
||||
return w.Internal.Closing(ctx)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
|
||||
return g.Internal.ChainHead(ctx)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainGetTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return g.Internal.ChainGetTipSet(ctx, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) ChainGetTipSetByHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error) {
|
||||
return g.Internal.ChainGetTipSetByHeight(ctx, h, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) GasEstimateMessageGas(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec, tsk types.TipSetKey) (*types.Message, error) {
|
||||
return g.Internal.GasEstimateMessageGas(ctx, msg, spec, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MpoolPush(ctx context.Context, sm *types.SignedMessage) (cid.Cid, error) {
|
||||
return g.Internal.MpoolPush(ctx, sm)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
|
||||
return g.Internal.MsigGetAvailableBalance(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
|
||||
return g.Internal.MsigGetVested(ctx, addr, start, end)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return g.Internal.StateAccountKey(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) {
|
||||
return g.Internal.StateGetActor(ctx, actor, ts)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return g.Internal.StateLookupID(ctx, addr, tsk)
|
||||
}
|
||||
|
||||
func (g GatewayStruct) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
|
||||
return g.Internal.StateWaitMsg(ctx, msg, confidence)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletNew(ctx context.Context, typ types.KeyType) (address.Address, error) {
|
||||
return c.Internal.WalletNew(ctx, typ)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||
return c.Internal.WalletHas(ctx, addr)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletList(ctx context.Context) ([]address.Address, error) {
|
||||
return c.Internal.WalletList(ctx)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletSign(ctx context.Context, k address.Address, msg []byte, meta api.MsgMeta) (*crypto.Signature, error) {
|
||||
return c.Internal.WalletSign(ctx, k, msg, meta)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletExport(ctx context.Context, a address.Address) (*types.KeyInfo, error) {
|
||||
return c.Internal.WalletExport(ctx, a)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletImport(ctx context.Context, ki *types.KeyInfo) (address.Address, error) {
|
||||
return c.Internal.WalletImport(ctx, ki)
|
||||
}
|
||||
|
||||
func (c *WalletStruct) WalletDelete(ctx context.Context, addr address.Address) error {
|
||||
return c.Internal.WalletDelete(ctx, addr)
|
||||
}
|
||||
|
||||
var _ api.Common = &CommonStruct{}
|
||||
var _ api.FullNode = &FullNodeStruct{}
|
||||
var _ api.StorageMiner = &StorageMinerStruct{}
|
||||
var _ api.WorkerAPI = &WorkerStruct{}
|
||||
var _ api.GatewayAPI = &GatewayStruct{}
|
||||
var _ api.WalletAPI = &WalletStruct{}
|
||||
|
||||
@@ -82,3 +82,29 @@ func NewWorkerRPC(ctx context.Context, addr string, requestHeader http.Header) (
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
// NewGatewayRPC creates a new http jsonrpc client for a gateway node.
|
||||
func NewGatewayRPC(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.GatewayAPI, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.GatewayStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
opts...,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
func NewWalletRPC(ctx context.Context, addr string, requestHeader http.Header) (api.WalletAPI, jsonrpc.ClientCloser, error) {
|
||||
var res apistruct.WalletStruct
|
||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||
[]interface{}{
|
||||
&res.Internal,
|
||||
},
|
||||
requestHeader,
|
||||
)
|
||||
|
||||
return &res, closer, err
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ func init() {
|
||||
addExample(abi.RegisteredPoStProof_StackedDrgWindow32GiBV1)
|
||||
addExample(abi.ChainEpoch(10101))
|
||||
addExample(crypto.SigTypeBLS)
|
||||
addExample(types.KTBLS)
|
||||
addExample(int64(9))
|
||||
addExample(12.3)
|
||||
addExample(123)
|
||||
|
||||
+15
-1
@@ -19,8 +19,22 @@ import (
|
||||
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, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
|
||||
+8
-5
@@ -48,7 +48,7 @@ func TestDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration, carExport
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -85,7 +85,7 @@ func TestDoubleDealFlow(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -149,7 +149,7 @@ func TestFastRetrievalDealFlow(t *testing.T, b APIBuilder, blocktime time.Durati
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -204,7 +204,7 @@ func TestSenondDealRetrieval(t *testing.T, b APIBuilder, blocktime time.Duration
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ var log = logging.Logger("apitest")
|
||||
|
||||
func (ts *testSuite) testMining(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@@ -54,7 +54,7 @@ func (ts *testSuite) testMiningReal(t *testing.T) {
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
apis, sn := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, sn := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
newHeads, err := api.ChainNotify(ctx)
|
||||
@@ -93,7 +93,7 @@ func TestDealMining(t *testing.T, b APIBuilder, blocktime time.Duration, carExpo
|
||||
// test making a deal with a fresh miner, and see if it starts to mine
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, []StorageMiner{
|
||||
n, sn := b(t, OneFull, []StorageMiner{
|
||||
{Full: 0, Preseal: PresealGenesis},
|
||||
{Full: 0, Preseal: 0}, // TODO: Add support for miners on non-first full node
|
||||
})
|
||||
|
||||
+48
-4
@@ -26,14 +26,13 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/events"
|
||||
"github.com/filecoin-project/lotus/chain/events/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
)
|
||||
|
||||
func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
||||
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 2, OneMiner)
|
||||
n, sn := b(t, TwoFull, OneMiner)
|
||||
|
||||
paymentCreator := n[0]
|
||||
paymentReceiver := n[1]
|
||||
@@ -58,7 +57,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
bm.MineBlocks()
|
||||
|
||||
// send some funds to register the receiver
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1"))
|
||||
receiverAddr, err := paymentReceiver.WalletNew(ctx, types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -71,7 +70,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)
|
||||
@@ -182,6 +181,51 @@ 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, paych0.SettleDelay)
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
"github.com/filecoin-project/lotus/node/impl"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration) {
|
||||
t.Run("before", func(t *testing.T) { testTapeFix(t, b, blocktime, false) })
|
||||
t.Run("after", func(t *testing.T) { testTapeFix(t, b, blocktime, true) })
|
||||
}
|
||||
func testTapeFix(t *testing.T, b APIBuilder, blocktime time.Duration, after bool) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
upgradeSchedule := stmgr.UpgradeSchedule{{
|
||||
Network: build.ActorUpgradeNetworkVersion,
|
||||
Height: 1,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}}
|
||||
if after {
|
||||
upgradeSchedule = append(upgradeSchedule, stmgr.Upgrade{
|
||||
Network: network.Version5,
|
||||
Height: 2,
|
||||
})
|
||||
}
|
||||
|
||||
n, sn := b(t, []FullNodeOpts{{Opts: func(_ []TestNode) node.Option {
|
||||
return node.Override(new(stmgr.UpgradeSchedule), upgradeSchedule)
|
||||
}}}, OneMiner)
|
||||
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
addrinfo, err := client.NetAddrsListen(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := miner.NetConnect(ctx, addrinfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
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
|
||||
}()
|
||||
|
||||
err = miner.PledgeSector(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Wait till done.
|
||||
var sectorNo abi.SectorNumber
|
||||
for {
|
||||
s, err := miner.SectorsList(ctx) // Note - the test builder doesn't import genesis sectors into FSM
|
||||
require.NoError(t, err)
|
||||
fmt.Printf("Sectors: %d\n", len(s))
|
||||
if len(s) == 1 {
|
||||
sectorNo = s[0]
|
||||
break
|
||||
}
|
||||
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
fmt.Printf("All sectors is fsm\n")
|
||||
|
||||
// If before, we expect the precommit to fail
|
||||
successState := api.SectorState(sealing.CommitFailed)
|
||||
failureState := api.SectorState(sealing.Proving)
|
||||
if after {
|
||||
// otherwise, it should succeed.
|
||||
successState, failureState = failureState, successState
|
||||
}
|
||||
|
||||
for {
|
||||
st, err := miner.SectorsStatus(ctx, sectorNo, false)
|
||||
require.NoError(t, err)
|
||||
if st.State == successState {
|
||||
break
|
||||
}
|
||||
require.NotEqual(t, failureState, st.State)
|
||||
build.Clock.Sleep(100 * time.Millisecond)
|
||||
fmt.Println("WaitSeal")
|
||||
}
|
||||
|
||||
}
|
||||
+93
-4
@@ -3,15 +3,23 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/miner"
|
||||
"github.com/filecoin-project/lotus/node"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
@@ -34,17 +42,27 @@ var PresealGenesis = -1
|
||||
|
||||
const GenesisPreseals = 2
|
||||
|
||||
// Options for setting up a mock storage miner
|
||||
type StorageMiner struct {
|
||||
Full int
|
||||
Preseal int
|
||||
}
|
||||
|
||||
type OptionGenerator func([]TestNode) node.Option
|
||||
|
||||
// Options for setting up a mock full node
|
||||
type FullNodeOpts struct {
|
||||
Lite bool // run node in "lite" mode
|
||||
Opts OptionGenerator // generate dependency injection options
|
||||
}
|
||||
|
||||
// APIBuilder is a function which is invoked in test suite to provide
|
||||
// test nodes and networks
|
||||
//
|
||||
// fullOpts array defines options for each full node
|
||||
// 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, full []FullNodeOpts, storage []StorageMiner) ([]TestNode, []TestStorageNode)
|
||||
type testSuite struct {
|
||||
makeNodes APIBuilder
|
||||
}
|
||||
@@ -60,15 +78,43 @@ func TestApis(t *testing.T, b APIBuilder) {
|
||||
t.Run("testConnectTwo", ts.testConnectTwo)
|
||||
t.Run("testMining", ts.testMining)
|
||||
t.Run("testMiningReal", ts.testMiningReal)
|
||||
t.Run("testSearchMsg", ts.testSearchMsg)
|
||||
}
|
||||
|
||||
func DefaultFullOpts(nFull int) []FullNodeOpts {
|
||||
full := make([]FullNodeOpts, nFull)
|
||||
for i := range full {
|
||||
full[i] = FullNodeOpts{
|
||||
Opts: func(nodes []TestNode) node.Option {
|
||||
return node.Options()
|
||||
},
|
||||
}
|
||||
}
|
||||
return full
|
||||
}
|
||||
|
||||
var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}}
|
||||
var OneFull = DefaultFullOpts(1)
|
||||
var TwoFull = DefaultFullOpts(2)
|
||||
|
||||
var FullNodeWithUpgradeAt = func(upgradeHeight abi.ChainEpoch) FullNodeOpts {
|
||||
return FullNodeOpts{
|
||||
Opts: func(nodes []TestNode) node.Option {
|
||||
return node.Override(new(stmgr.UpgradeSchedule), stmgr.UpgradeSchedule{{
|
||||
// Skip directly to tape height so precommits work.
|
||||
Network: network.Version5,
|
||||
Height: upgradeHeight,
|
||||
Migration: stmgr.UpgradeActorsV2,
|
||||
}})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ts *testSuite) testVersion(t *testing.T) {
|
||||
build.RunningNodeType = build.NodeFull
|
||||
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
v, err := api.Version(ctx)
|
||||
@@ -78,9 +124,52 @@ func (ts *testSuite) testVersion(t *testing.T) {
|
||||
require.Equal(t, v.Version, build.BuildVersion)
|
||||
}
|
||||
|
||||
func (ts *testSuite) testSearchMsg(t *testing.T) {
|
||||
apis, miners := ts.makeNodes(t, OneFull, OneMiner)
|
||||
|
||||
api := apis[0]
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
senderAddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
From: senderAddr,
|
||||
To: senderAddr,
|
||||
Value: big.Zero(),
|
||||
}
|
||||
bm := NewBlockMiner(ctx, t, miners[0], 100*time.Millisecond)
|
||||
bm.MineBlocks()
|
||||
defer bm.Stop()
|
||||
|
||||
sm, err := api.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := api.StateWaitMsg(ctx, sm.Cid(), 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Receipt.ExitCode != 0 {
|
||||
t.Fatal("did not successfully send message")
|
||||
}
|
||||
|
||||
searchRes, err := api.StateSearchMsg(ctx, sm.Cid())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if searchRes.TipSet != res.TipSet {
|
||||
t.Fatalf("search ts: %s, different from wait ts: %s", searchRes.TipSet, res.TipSet)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ts *testSuite) testID(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 1, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, OneFull, OneMiner)
|
||||
api := apis[0]
|
||||
|
||||
id, err := api.ID(ctx)
|
||||
@@ -92,7 +181,7 @@ func (ts *testSuite) testID(t *testing.T) {
|
||||
|
||||
func (ts *testSuite) testConnectTwo(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
apis, _ := ts.makeNodes(t, 2, OneMiner)
|
||||
apis, _ := ts.makeNodes(t, TwoFull, OneMiner)
|
||||
|
||||
p, err := apis[0].NetPeers(ctx)
|
||||
if err != nil {
|
||||
|
||||
+49
-29
@@ -3,6 +3,7 @@ package test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
@@ -31,8 +32,10 @@ func init() {
|
||||
}
|
||||
|
||||
func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSectors int) {
|
||||
ctx := context.Background()
|
||||
n, sn := b(t, 1, OneMiner)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
n, sn := b(t, OneFull, OneMiner)
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -46,11 +49,11 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
}
|
||||
build.Clock.Sleep(time.Second)
|
||||
|
||||
mine := true
|
||||
mine := int64(1)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
for mine {
|
||||
for atomic.LoadInt64(&mine) != 0 {
|
||||
build.Clock.Sleep(blocktime)
|
||||
if err := sn[0].MineOne(ctx, bminer.MineReq{Done: func(bool, abi.ChainEpoch, error) {
|
||||
|
||||
@@ -62,7 +65,7 @@ func TestPledgeSector(t *testing.T, b APIBuilder, blocktime time.Duration, nSect
|
||||
|
||||
pledgeSectors(t, ctx, miner, nSectors, 0, nil)
|
||||
|
||||
mine = false
|
||||
atomic.StoreInt64(&mine, 0)
|
||||
<-done
|
||||
}
|
||||
|
||||
@@ -114,8 +117,25 @@ 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, []FullNodeOpts{FullNodeWithUpgradeAt(upgradeHeight)}, OneMiner)
|
||||
|
||||
client := n[0].FullNode.(*impl.FullNodeAPI)
|
||||
miner := sn[0]
|
||||
|
||||
@@ -129,17 +149,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 +180,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 +211,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 +234,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 +259,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 +289,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 +316,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 +341,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
|
||||
}
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWK3WNs8LcC5bNVRmcfM6QMNV8btBxYwNhxaP1NCv4ueGw
|
||||
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWEq5DpaYddHQ1AyxCUamFa5y6kkWZ7mjHL5zG1jvU1GeM
|
||||
/dns4/bootstrap-0.testnet.fildev.network/tcp/1347/p2p/12D3KooWJTUBUjtzWJGWU1XSiY21CwmHaCNLNYn2E7jqHEHyZaP7
|
||||
/dns4/bootstrap-1.testnet.fildev.network/tcp/1347/p2p/12D3KooW9yeKXha4hdrJKq74zEo99T8DhriQdWNoojWnnQbsgB3v
|
||||
/dns4/bootstrap-2.testnet.fildev.network/tcp/1347/p2p/12D3KooWCrx8yVG9U9Kf7w8KLN3Edkj5ZKDhgCaeMqQbcQUoB6CT
|
||||
/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
|
||||
|
||||
Binary file not shown.
+13
-2
@@ -3,6 +3,9 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
@@ -13,8 +16,11 @@ const BreezeGasTampingDuration = 0
|
||||
|
||||
const UpgradeSmokeHeight = -1
|
||||
const UpgradeIgnitionHeight = -2
|
||||
const UpgradeLiftoffHeight = -3
|
||||
const UpgradeActorsV2 = 10
|
||||
const UpgradeRefuelHeight = -3
|
||||
const UpgradeTapeHeight = -4
|
||||
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(10)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
@@ -25,6 +31,11 @@ func init() {
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(2048))
|
||||
policy.SetMinVerifiedDealSize(abi.NewStoragePower(256))
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_V2_ACTOR_MIGRATION") == "1" {
|
||||
UpgradeActorsV2Height = math.MaxInt64
|
||||
UpgradeLiftoffHeight = 11
|
||||
}
|
||||
|
||||
BuildType |= Build2k
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
|
||||
@@ -12,17 +16,21 @@ import (
|
||||
)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
0: DrandIncentinet,
|
||||
UpgradeSmokeHeight: DrandMainnet,
|
||||
}
|
||||
|
||||
const UpgradeBreezeHeight = -1
|
||||
const UpgradeBreezeHeight = 41280
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
const UpgradeSmokeHeight = -2
|
||||
const UpgradeSmokeHeight = 51000
|
||||
|
||||
const UpgradeIgnitionHeight = -3
|
||||
const UpgradeIgnitionHeight = 94000
|
||||
const UpgradeRefuelHeight = 130800
|
||||
|
||||
const UpgradeActorsV2 = 500
|
||||
var UpgradeActorsV2Height = abi.ChainEpoch(138720)
|
||||
|
||||
const UpgradeTapeHeight = 140760
|
||||
|
||||
// This signals our tentative epoch for mainnet launch. Can make it later, but not earlier.
|
||||
// Miners, clients, developers, custodians all need time to prepare.
|
||||
@@ -30,12 +38,20 @@ const UpgradeActorsV2 = 500
|
||||
const UpgradeLiftoffHeight = 148888
|
||||
|
||||
func init() {
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(1 << 30))
|
||||
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40))
|
||||
policy.SetSupportedProofTypes(
|
||||
abi.RegisteredSealProof_StackedDrg512MiBV1,
|
||||
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
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ 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 && UpgradeActorsV2 <= 0 {
|
||||
if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 && UpgradeActorsV2Height <= 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -25,7 +25,7 @@ const UnixfsLinksPerLevel = 1024
|
||||
// Consensus / Network
|
||||
|
||||
const AllowableClockDriftSecs = uint64(1)
|
||||
const NewestNetworkVersion = network.Version4
|
||||
const NewestNetworkVersion = network.Version5
|
||||
const ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
// Epochs
|
||||
@@ -56,8 +56,6 @@ const SealRandomnessLookback = policy.SealRandomnessLookback
|
||||
// Epochs
|
||||
const TicketRandomnessLookback = abi.ChainEpoch(1)
|
||||
|
||||
const WinningPoStSectorSetLookback = abi.ChainEpoch(10)
|
||||
|
||||
// /////
|
||||
// Address
|
||||
|
||||
@@ -72,8 +70,10 @@ 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
|
||||
|
||||
@@ -81,6 +81,9 @@ 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)
|
||||
}
|
||||
|
||||
@@ -50,11 +50,11 @@ var (
|
||||
|
||||
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
|
||||
|
||||
@@ -63,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)
|
||||
@@ -75,15 +82,17 @@ var (
|
||||
|
||||
UpgradeSmokeHeight abi.ChainEpoch = -1
|
||||
UpgradeIgnitionHeight abi.ChainEpoch = -2
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -3
|
||||
UpgradeActorsV2 abi.ChainEpoch = 10
|
||||
UpgradeRefuelHeight abi.ChainEpoch = -3
|
||||
UpgradeTapeHeight abi.ChainEpoch = -4
|
||||
UpgradeActorsV2Height abi.ChainEpoch = 10
|
||||
UpgradeLiftoffHeight abi.ChainEpoch = -5
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
NewestNetworkVersion = network.Version2
|
||||
ActorUpgradeNetworkVersion = network.Version3
|
||||
NewestNetworkVersion = network.Version5
|
||||
ActorUpgradeNetworkVersion = network.Version4
|
||||
|
||||
Devnet = true
|
||||
)
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ func buildType() string {
|
||||
}
|
||||
|
||||
// BuildVersion is the local build version, set by build system
|
||||
const BuildVersion = "0.8.0"
|
||||
const BuildVersion = "0.10.1"
|
||||
|
||||
func UserVersion() string {
|
||||
return BuildVersion + buildType() + CurrentCommit
|
||||
@@ -83,7 +83,7 @@ func VersionForType(nodeType NodeType) (Version, error) {
|
||||
|
||||
// semver versions of the rpc api exposed
|
||||
var (
|
||||
FullAPIVersion = newVer(0, 16, 0)
|
||||
FullAPIVersion = newVer(0, 17, 0)
|
||||
MinerAPIVersion = newVer(0, 15, 0)
|
||||
WorkerAPIVersion = newVer(0, 15, 0)
|
||||
)
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"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"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
smoothing2 "github.com/filecoin-project/specs-actors/v2/actors/util/smoothing"
|
||||
)
|
||||
|
||||
var SystemActorAddr = builtin0.SystemActorAddr
|
||||
var BurntFundsActorAddr = builtin0.BurntFundsActorAddr
|
||||
var CronActorAddr = builtin0.CronActorAddr
|
||||
var SaftAddress = makeAddress("t0122")
|
||||
var ReserveAddress = makeAddress("t090")
|
||||
var RootVerifierAddress = makeAddress("t080")
|
||||
|
||||
// TODO: Why does actors have 2 different versions of this?
|
||||
type SectorInfo = proof0.SectorInfo
|
||||
@@ -86,3 +92,12 @@ func IsMultisigActor(c cid.Cid) bool {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@@ -32,6 +33,10 @@ func init() {
|
||||
|
||||
// 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
|
||||
|
||||
@@ -54,6 +59,7 @@ 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)
|
||||
@@ -140,6 +146,21 @@ type MinerInfo struct {
|
||||
SealProofType abi.RegisteredSealProof
|
||||
SectorSize abi.SectorSize
|
||||
WindowPoStPartitionSectors uint64
|
||||
ConsensusFaultElapsed abi.ChainEpoch
|
||||
}
|
||||
|
||||
func (mi MinerInfo) IsController(addr address.Address) bool {
|
||||
if addr == mi.Owner || addr == mi.Worker {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, ca := range mi.ControlAddresses {
|
||||
if addr == ca {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type SectorExpiration struct {
|
||||
@@ -176,3 +197,7 @@ type LockedFunds struct {
|
||||
InitialPledgeRequirement abi.TokenAmount
|
||||
PreCommitDeposits abi.TokenAmount
|
||||
}
|
||||
|
||||
func (lf LockedFunds) TotalLockedFunds() abi.TokenAmount {
|
||||
return big.Add(lf.VestingFunds, big.Add(lf.InitialPledgeRequirement, lf.PreCommitDeposits))
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"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"
|
||||
@@ -45,8 +47,16 @@ type partition0 struct {
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state0) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return s.GetAvailableBalance(bal), nil
|
||||
func (s *state0) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||
available = abi.NewTokenAmount(0)
|
||||
}
|
||||
}()
|
||||
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||
available = s.GetAvailableBalance(bal)
|
||||
return available, err
|
||||
}
|
||||
|
||||
func (s *state0) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
@@ -61,6 +71,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
|
||||
}
|
||||
@@ -287,6 +301,7 @@ func (s *state0) Info() (MinerInfo, error) {
|
||||
SealProofType: info.SealProofType,
|
||||
SectorSize: info.SectorSize,
|
||||
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||
ConsensusFaultElapsed: -1,
|
||||
}
|
||||
|
||||
if info.PendingWorkerKey != nil {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"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"
|
||||
|
||||
@@ -44,8 +45,16 @@ type partition2 struct {
|
||||
store adt.Store
|
||||
}
|
||||
|
||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
return s.GetAvailableBalance(bal), nil
|
||||
func (s *state2) AvailableBalance(bal abi.TokenAmount) (available abi.TokenAmount, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = xerrors.Errorf("failed to get available balance: %w", r)
|
||||
available = abi.NewTokenAmount(0)
|
||||
}
|
||||
}()
|
||||
// this panics if the miner doesnt have enough funds to cover their locked pledge
|
||||
available, err = s.GetAvailableBalance(bal)
|
||||
return available, err
|
||||
}
|
||||
|
||||
func (s *state2) VestedFunds(epoch abi.ChainEpoch) (abi.TokenAmount, error) {
|
||||
@@ -60,6 +69,10 @@ func (s *state2) LockedFunds() (LockedFunds, error) {
|
||||
}, 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
|
||||
}
|
||||
@@ -106,9 +119,7 @@ func (s *state2) NumLiveSectors() (uint64, error) {
|
||||
|
||||
// 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 *state2) GetSectorExpiration(num abi.SectorNumber) (*SectorExpiration, error) {
|
||||
dls, err := s.State.LoadDeadlines(s.store)
|
||||
if err != nil {
|
||||
@@ -171,7 +182,7 @@ func (s *state2) 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
|
||||
}
|
||||
@@ -289,6 +300,7 @@ func (s *state2) Info() (MinerInfo, error) {
|
||||
SealProofType: info.SealProofType,
|
||||
SectorSize: info.SectorSize,
|
||||
WindowPoStPartitionSectors: info.WindowPoStPartitionSectors,
|
||||
ConsensusFaultElapsed: info.ConsensusFaultElapsed,
|
||||
}
|
||||
|
||||
if info.PendingWorkerKey != nil {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,7 @@ type State interface {
|
||||
MinerPower(address.Address) (Claim, bool, error)
|
||||
MinerNominalPowerMeetsConsensusMinimum(address.Address) (bool, error)
|
||||
ListAllMiners() ([]address.Address, error)
|
||||
ForEachClaim(func(miner address.Address, claim Claim) error) error
|
||||
}
|
||||
|
||||
type Claim struct {
|
||||
|
||||
@@ -96,3 +96,22 @@ func (s *state0) ListAllMiners() ([]address.Address, error) {
|
||||
|
||||
return miners, nil
|
||||
}
|
||||
|
||||
func (s *state0) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
|
||||
claims, err := adt0.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var claim power0.Claim
|
||||
return claims.ForEach(&claim, func(k string) error {
|
||||
a, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, Claim{
|
||||
RawBytePower: claim.RawBytePower,
|
||||
QualityAdjPower: claim.QualityAdjPower,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,3 +96,22 @@ func (s *state2) ListAllMiners() ([]address.Address, error) {
|
||||
|
||||
return miners, nil
|
||||
}
|
||||
|
||||
func (s *state2) ForEachClaim(cb func(miner address.Address, claim Claim) error) error {
|
||||
claims, err := adt2.AsMap(s.store, s.Claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var claim power2.Claim
|
||||
return claims.ForEach(&claim, func(k string) error {
|
||||
a, err := address.NewFromBytes([]byte(k))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cb(a, Claim{
|
||||
RawBytePower: claim.RawBytePower,
|
||||
QualityAdjPower: claim.QualityAdjPower,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func (s *state0) CumsumBaseline() (abi.StoragePower, error) {
|
||||
}
|
||||
|
||||
func (s *state0) CumsumRealized() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
return s.State.CumsumRealized, nil
|
||||
}
|
||||
|
||||
func (s *state0) InitialPledgeForPower(sectorWeight abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
|
||||
@@ -60,7 +60,7 @@ func (s *state2) CumsumBaseline() (abi.StoragePower, error) {
|
||||
}
|
||||
|
||||
func (s *state2) CumsumRealized() (abi.StoragePower, error) {
|
||||
return s.State.CumsumBaseline, nil
|
||||
return s.State.CumsumRealized, nil
|
||||
}
|
||||
|
||||
func (s *state2) InitialPledgeForPower(qaPower abi.StoragePower, networkTotalPledge abi.TokenAmount, networkQAPower *builtin.FilterEstimate, circSupply abi.TokenAmount) (abi.TokenAmount, error) {
|
||||
|
||||
@@ -27,6 +27,10 @@ type state0 struct {
|
||||
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) {
|
||||
return getDataCap(s.store, actors.Version0, s.State.VerifiedClients, addr)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ type state2 struct {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ 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
|
||||
|
||||
@@ -2,12 +2,14 @@ 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"
|
||||
)
|
||||
@@ -79,3 +81,36 @@ func GetMaxProveCommitDuration(ver actors.Version, t abi.RegisteredSealProof) ab
|
||||
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
|
||||
}
|
||||
|
||||
@@ -43,5 +43,8 @@ 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))
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
type Version int
|
||||
|
||||
const (
|
||||
Version0 = 0
|
||||
Version2 = 2
|
||||
Version0 Version = 0
|
||||
Version2 Version = 2
|
||||
)
|
||||
|
||||
// Converts a network version into an actors adt version.
|
||||
@@ -18,7 +18,7 @@ func VersionForNetwork(version network.Version) Version {
|
||||
switch version {
|
||||
case network.Version0, network.Version1, network.Version2, network.Version3:
|
||||
return Version0
|
||||
case network.Version4:
|
||||
case network.Version4, network.Version5:
|
||||
return Version2
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported network version %d", version))
|
||||
|
||||
@@ -60,6 +60,10 @@ func (bts *BadBlockCache) Remove(c cid.Cid) {
|
||||
bts.badBlocks.Remove(c)
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Purge() {
|
||||
bts.badBlocks.Purge()
|
||||
}
|
||||
|
||||
func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) {
|
||||
rval, ok := bts.badBlocks.Get(c)
|
||||
if !ok {
|
||||
|
||||
+24
-2
@@ -2,6 +2,7 @@ package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -17,6 +18,8 @@ type tsCacheAPI interface {
|
||||
// tipSetCache implements a simple ring-buffer cache to keep track of recent
|
||||
// tipsets
|
||||
type tipSetCache struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
cache []*types.TipSet
|
||||
start int
|
||||
len int
|
||||
@@ -35,6 +38,9 @@ func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache {
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
||||
tsc.mu.Lock()
|
||||
defer tsc.mu.Unlock()
|
||||
|
||||
if tsc.len > 0 {
|
||||
if tsc.cache[tsc.start].Height() >= ts.Height() {
|
||||
return xerrors.Errorf("tipSetCache.add: expected new tipset height to be at least %d, was %d", tsc.cache[tsc.start].Height()+1, ts.Height())
|
||||
@@ -65,6 +71,13 @@ func (tsc *tipSetCache) add(ts *types.TipSet) error {
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) revert(ts *types.TipSet) error {
|
||||
tsc.mu.Lock()
|
||||
defer tsc.mu.Unlock()
|
||||
|
||||
return tsc.revertUnlocked(ts)
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) revertUnlocked(ts *types.TipSet) error {
|
||||
if tsc.len == 0 {
|
||||
return nil // this can happen, and it's fine
|
||||
}
|
||||
@@ -77,7 +90,7 @@ func (tsc *tipSetCache) revert(ts *types.TipSet) error {
|
||||
tsc.start = normalModulo(tsc.start-1, len(tsc.cache))
|
||||
tsc.len--
|
||||
|
||||
_ = tsc.revert(nil) // revert null block gap
|
||||
_ = tsc.revertUnlocked(nil) // revert null block gap
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -95,7 +108,10 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error)
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
tsc.mu.RLock()
|
||||
|
||||
if tsc.len == 0 {
|
||||
tsc.mu.RUnlock()
|
||||
log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height)
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK)
|
||||
}
|
||||
@@ -103,6 +119,7 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
headH := tsc.cache[tsc.start].Height()
|
||||
|
||||
if height > headH {
|
||||
tsc.mu.RUnlock()
|
||||
return nil, xerrors.Errorf("tipSetCache.get: requested tipset not in cache (req: %d, cache head: %d)", height, headH)
|
||||
}
|
||||
|
||||
@@ -116,15 +133,20 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) {
|
||||
}
|
||||
|
||||
if height < tail.Height() {
|
||||
tsc.mu.RUnlock()
|
||||
log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height())
|
||||
return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key())
|
||||
}
|
||||
|
||||
return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil
|
||||
ts := tsc.cache[normalModulo(tsc.start-int(headH-height), clen)]
|
||||
tsc.mu.RUnlock()
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (tsc *tipSetCache) best() (*types.TipSet, error) {
|
||||
tsc.mu.RLock()
|
||||
best := tsc.cache[tsc.start]
|
||||
tsc.mu.RUnlock()
|
||||
if best == nil {
|
||||
return tsc.storage.ChainHead(context.TODO())
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ func (c *client) doRequest(
|
||||
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
|
||||
|
||||
+26
-13
@@ -9,6 +9,7 @@ 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"
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||
"github.com/filecoin-project/lotus/genesis"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/blockstore"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
@@ -70,7 +72,7 @@ type ChainGen struct {
|
||||
|
||||
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
||||
|
||||
w *wallet.Wallet
|
||||
w *wallet.LocalWallet
|
||||
|
||||
eppProvs map[address.Address]WinningPoStProver
|
||||
Miners []address.Address
|
||||
@@ -121,6 +123,7 @@ var DefaultRemainderAccountActor = genesis.Actor{
|
||||
}
|
||||
|
||||
func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
j := journal.NilJournal()
|
||||
// TODO: we really shouldn't modify a global variable here.
|
||||
policy.SetSupportedProofTypes(abi.RegisteredSealProof_StackedDrg2KiBV1)
|
||||
|
||||
@@ -152,14 +155,14 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
|
||||
}
|
||||
|
||||
banker, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
banker, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
||||
}
|
||||
|
||||
receievers := make([]address.Address, msgsPerBlock)
|
||||
for r := range receievers {
|
||||
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS)
|
||||
receievers[r], err = w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
||||
}
|
||||
@@ -189,11 +192,11 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mk1, err := w.Import(k1)
|
||||
mk1, err := w.WalletImport(context.Background(), k1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mk2, err := w.Import(k2)
|
||||
mk2, err := w.WalletImport(context.Background(), k2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -224,16 +227,16 @@ 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()),
|
||||
}
|
||||
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
||||
genb, err := genesis2.MakeGenesisBlock(context.TODO(), j, bs, sys, tpl)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
||||
}
|
||||
|
||||
cs := store.NewChainStore(bs, ds, sys)
|
||||
cs := store.NewChainStore(bs, ds, sys, j)
|
||||
|
||||
genfb := &types.FullBlock{Header: genb.Genesis}
|
||||
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
||||
@@ -373,7 +376,13 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
|
||||
return nil, nil, nil, xerrors.Errorf("get miner worker: %w", err)
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand)
|
||||
sf := func(ctx context.Context, a address.Address, i []byte) (*crypto.Signature, error) {
|
||||
return cg.w.WalletSign(ctx, a, i, api.MsgMeta{
|
||||
Type: api.MTUnknown,
|
||||
})
|
||||
}
|
||||
|
||||
vrfout, err := ComputeVRF(ctx, sf, worker, ticketRand)
|
||||
if err != nil {
|
||||
return nil, nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
||||
}
|
||||
@@ -505,7 +514,7 @@ func (cg *ChainGen) Banker() address.Address {
|
||||
return cg.banker
|
||||
}
|
||||
|
||||
func (cg *ChainGen) Wallet() *wallet.Wallet {
|
||||
func (cg *ChainGen) Wallet() *wallet.LocalWallet {
|
||||
return cg.w
|
||||
}
|
||||
|
||||
@@ -527,7 +536,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
|
||||
sig, err := cg.w.WalletSign(context.TODO(), cg.banker, msg.Cid().Bytes(), api.MsgMeta{
|
||||
Type: api.MTUnknown, // testing
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -558,7 +569,7 @@ type MiningCheckAPI interface {
|
||||
}
|
||||
|
||||
type mca struct {
|
||||
w *wallet.Wallet
|
||||
w *wallet.LocalWallet
|
||||
sm *stmgr.StateManager
|
||||
pv ffiwrapper.Verifier
|
||||
bcn beacon.Schedule
|
||||
@@ -587,7 +598,9 @@ func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoc
|
||||
}
|
||||
|
||||
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) {
|
||||
return mca.w.Sign(ctx, a, v)
|
||||
return mca.w.WalletSign(ctx, a, v, api.MsgMeta{
|
||||
Type: api.MTUnknown,
|
||||
})
|
||||
}
|
||||
|
||||
type WinningPoStProver interface {
|
||||
|
||||
@@ -6,6 +6,9 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
@@ -24,7 +27,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"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@@ -115,7 +117,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, actors.Version0)
|
||||
state, err := state.NewStateTree(cst, types.StateTreeVersion0)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("making new state tree: %w", err)
|
||||
}
|
||||
@@ -296,14 +298,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)
|
||||
}
|
||||
|
||||
@@ -470,7 +467,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) {
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
st, keyIDs, err := MakeInitialStateTree(ctx, bs, template)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||
@@ -482,7 +482,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
|
||||
}
|
||||
|
||||
// temp chainstore
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys)
|
||||
cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys, j)
|
||||
|
||||
// Verify PreSealed Data
|
||||
stateroot, err = VerifyPreSealedData(ctx, cs, stateroot, template, keyIDs)
|
||||
|
||||
+4
-3
@@ -15,11 +15,10 @@ import (
|
||||
"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/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
)
|
||||
|
||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.WalletAPI, bt *api.BlockTemplate) (*types.FullBlock, error) {
|
||||
|
||||
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
|
||||
if err != nil {
|
||||
@@ -131,7 +130,9 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
|
||||
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
|
||||
}
|
||||
|
||||
sig, err := w.Sign(ctx, waddr, nosigbytes)
|
||||
sig, err := w.WalletSign(ctx, waddr, nosigbytes, api.MsgMeta{
|
||||
Type: api.MTBlock,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to sign new block: %w", 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)
|
||||
}
|
||||
|
||||
|
||||
@@ -120,9 +120,10 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
return cid.Undef, err
|
||||
}
|
||||
fm.lk.Lock()
|
||||
defer fm.lk.Unlock()
|
||||
|
||||
bal, err := fm.api.StateMarketBalance(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
fm.lk.Unlock()
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -138,7 +139,6 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
toAdd = types.NewInt(0)
|
||||
}
|
||||
fm.available[idAddr] = big.Add(avail, toAdd)
|
||||
fm.lk.Unlock()
|
||||
|
||||
log.Infof("Funds operation w/ Expected Balance: %s, In State: %s, Requested: %s, Adding: %s", avail.String(), stateAvail.String(), amt.String(), toAdd.String())
|
||||
|
||||
@@ -148,6 +148,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
|
||||
params, err := actors.SerializeParams(&addr)
|
||||
if err != nil {
|
||||
fm.available[idAddr] = avail
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
@@ -159,6 +160,7 @@ func (fm *FundMgr) EnsureAvailable(ctx context.Context, addr, wallet address.Add
|
||||
Params: params,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
fm.available[idAddr] = avail
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,10 @@ func addFundsMsg(toAdd abi.TokenAmount, addr address.Address, wallet address.Add
|
||||
}
|
||||
|
||||
type expectedResult struct {
|
||||
addAmt abi.TokenAmount
|
||||
shouldAdd bool
|
||||
err error
|
||||
addAmt abi.TokenAmount
|
||||
shouldAdd bool
|
||||
err error
|
||||
cachedAvailable abi.TokenAmount
|
||||
}
|
||||
|
||||
func TestAddFunds(t *testing.T) {
|
||||
@@ -88,8 +89,9 @@ func TestAddFunds(t *testing.T) {
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -102,18 +104,21 @@ func TestAddFunds(t *testing.T) {
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
addAmt: abi.NewTokenAmount(100),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(200),
|
||||
},
|
||||
{
|
||||
addAmt: abi.NewTokenAmount(50),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
addAmt: abi.NewTokenAmount(50),
|
||||
shouldAdd: true,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(250),
|
||||
},
|
||||
{
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
shouldAdd: false,
|
||||
err: nil,
|
||||
cachedAvailable: abi.NewTokenAmount(250),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -132,7 +137,8 @@ func TestAddFunds(t *testing.T) {
|
||||
addAmounts: []abi.TokenAmount{abi.NewTokenAmount(100)},
|
||||
expectedResults: []expectedResult{
|
||||
{
|
||||
err: errors.New("something went wrong"),
|
||||
err: errors.New("something went wrong"),
|
||||
cachedAvailable: abi.NewTokenAmount(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -183,6 +189,10 @@ func TestAddFunds(t *testing.T) {
|
||||
} else {
|
||||
require.EqualError(t, err, expected.err.Error())
|
||||
}
|
||||
|
||||
if !expected.cachedAvailable.Nil() {
|
||||
require.Equal(t, expected.cachedAvailable, fundMgr.available[addr])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ var Costs = map[CostKey]int64{
|
||||
{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,
|
||||
|
||||
@@ -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 (
|
||||
@@ -160,6 +159,7 @@ type MessagePool struct {
|
||||
sigValCache *lru.TwoQueueCache
|
||||
|
||||
evtTypes [3]journal.EventType
|
||||
journal journal.Journal
|
||||
}
|
||||
|
||||
type msgSet struct {
|
||||
@@ -197,9 +197,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 +216,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 +252,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
|
||||
}
|
||||
@@ -309,7 +317,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
|
||||
return types.BigInt{Int: requiredFunds}
|
||||
}
|
||||
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
|
||||
func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName, j journal.Journal) (*MessagePool, error) {
|
||||
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
|
||||
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
|
||||
|
||||
@@ -318,6 +326,10 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
return nil, xerrors.Errorf("error loading mpool config: %w", err)
|
||||
}
|
||||
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
|
||||
mp := &MessagePool{
|
||||
ds: ds,
|
||||
addSema: make(chan struct{}, 1),
|
||||
@@ -337,10 +349,11 @@ func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*Messa
|
||||
netName: netName,
|
||||
cfg: cfg,
|
||||
evtTypes: [...]journal.EventType{
|
||||
evtTypeMpoolAdd: journal.J.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: journal.J.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: journal.J.RegisterEventType("mpool", "repub"),
|
||||
evtTypeMpoolAdd: j.RegisterEventType("mpool", "add"),
|
||||
evtTypeMpoolRemove: j.RegisterEventType("mpool", "remove"),
|
||||
evtTypeMpoolRepub: j.RegisterEventType("mpool", "repub"),
|
||||
},
|
||||
journal: j,
|
||||
}
|
||||
|
||||
// enable initial prunes
|
||||
@@ -486,7 +499,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 +566,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 +634,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 +656,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 {
|
||||
@@ -657,6 +670,10 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error {
|
||||
|
||||
curTs := mp.curTs
|
||||
|
||||
if curTs == nil {
|
||||
return xerrors.Errorf("current tipset not loaded")
|
||||
}
|
||||
|
||||
snonce, err := mp.getStateNonce(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure)
|
||||
@@ -678,17 +695,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 +732,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
|
||||
@@ -737,7 +754,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error {
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolAdd], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "add",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}},
|
||||
@@ -795,96 +812,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) {
|
||||
@@ -906,7 +875,7 @@ func (mp *MessagePool) remove(from address.Address, nonce uint64, applied bool)
|
||||
Message: m,
|
||||
}, localUpdates)
|
||||
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRemove], func() interface{} {
|
||||
return MessagePoolEvt{
|
||||
Action: "remove",
|
||||
Messages: []MessagePoolEvtMessage{{Message: m.Message, CID: m.Cid()}}}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
@@ -225,14 +224,14 @@ func TestMessagePool(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -266,14 +265,14 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -315,7 +314,7 @@ func TestRevertMessages(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -323,7 +322,7 @@ func TestRevertMessages(t *testing.T) {
|
||||
a := tma.nextBlock()
|
||||
b := tma.nextBlock()
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -378,7 +377,7 @@ func TestPruningSimple(t *testing.T) {
|
||||
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -386,7 +385,7 @@ func TestPruningSimple(t *testing.T) {
|
||||
a := tma.nextBlock()
|
||||
tma.applyBlock(t, a)
|
||||
|
||||
sender, err := w.GenerateKey(crypto.SigTypeBLS)
|
||||
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -422,7 +421,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -433,7 +432,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -443,7 +442,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -465,7 +464,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mp, err = New(tma, ds, "mptest")
|
||||
mp, err = New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -494,7 +493,7 @@ func TestClearAll(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -505,7 +504,7 @@ func TestClearAll(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -515,7 +514,7 @@ func TestClearAll(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -548,7 +547,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -559,7 +558,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -569,7 +568,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -609,7 +608,7 @@ func TestUpdates(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -620,7 +619,7 @@ func TestUpdates(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -630,7 +629,7 @@ func TestUpdates(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
@@ -148,14 +147,14 @@ loop:
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
journal.J.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
msgs := make([]MessagePoolEvtMessage, 0, len(msgs))
|
||||
mp.journal.RecordEvent(mp.evtTypes[evtTypeMpoolRepub], func() interface{} {
|
||||
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,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package messagepool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-datastore"
|
||||
@@ -21,7 +22,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
|
||||
mp, err := New(tma, ds, "mptest")
|
||||
mp, err := New(tma, ds, "mptest", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -32,7 +33,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -42,7 +43,7 @@ func TestRepubMessages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -13,20 +13,21 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
logging "github.com/ipfs/go-log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -34,7 +35,7 @@ func init() {
|
||||
MaxActorPendingMessages = 1000000
|
||||
}
|
||||
|
||||
func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
|
||||
func makeTestMessage(w *wallet.LocalWallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
|
||||
msg := &types.Message{
|
||||
From: from,
|
||||
To: to,
|
||||
@@ -45,7 +46,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
||||
GasFeeCap: types.NewInt(100 + gasPrice),
|
||||
GasPremium: types.NewInt(gasPrice),
|
||||
}
|
||||
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -58,7 +59,7 @@ func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, g
|
||||
func makeTestMpool() (*MessagePool, *testMpoolAPI) {
|
||||
tma := newTestMpoolAPI()
|
||||
ds := datastore.NewMapDatastore()
|
||||
mp, err := New(tma, ds, "test")
|
||||
mp, err := New(tma, ds, "test", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -75,7 +76,7 @@ func TestMessageChains(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -85,7 +86,7 @@ func TestMessageChains(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -313,7 +314,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -323,7 +324,7 @@ func TestMessageChainSkipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -389,7 +390,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -399,7 +400,7 @@ func TestBasicMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -533,7 +534,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -543,7 +544,7 @@ func TestMessageSelectionTrimming(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -596,7 +597,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -606,7 +607,7 @@ func TestPriorityMessageSelection(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -675,7 +676,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -685,7 +686,7 @@ func TestPriorityMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -744,7 +745,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -754,7 +755,7 @@ func TestPriorityMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -841,7 +842,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -851,7 +852,7 @@ func TestOptimalMessageSelection1(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -908,7 +909,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -918,7 +919,7 @@ func TestOptimalMessageSelection2(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -984,7 +985,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
nActors := 10
|
||||
// the actors
|
||||
var actors []address.Address
|
||||
var wallets []*wallet.Wallet
|
||||
var wallets []*wallet.LocalWallet
|
||||
|
||||
for i := 0; i < nActors; i++ {
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -992,7 +993,7 @@ func TestOptimalMessageSelection3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1064,7 +1065,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
||||
nActors := 300
|
||||
// the actors
|
||||
var actors []address.Address
|
||||
var wallets []*wallet.Wallet
|
||||
var wallets []*wallet.LocalWallet
|
||||
|
||||
for i := 0; i < nActors; i++ {
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@@ -1072,7 +1073,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1330,7 +1331,7 @@ readLoop:
|
||||
}
|
||||
|
||||
actorMap := make(map[address.Address]address.Address)
|
||||
actorWallets := make(map[address.Address]*wallet.Wallet)
|
||||
actorWallets := make(map[address.Address]api.WalletAPI)
|
||||
|
||||
for _, m := range msgs {
|
||||
baseNonce := baseNonces[m.Message.From]
|
||||
@@ -1342,7 +1343,7 @@ readLoop:
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
a, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
||||
a, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1360,7 +1361,7 @@ readLoop:
|
||||
m.Message.From = localActor
|
||||
m.Message.Nonce -= baseNonce
|
||||
|
||||
sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), localActor, m.Message.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package messagesigner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
const dsKeyActorNonce = "ActorNextNonce"
|
||||
|
||||
var log = logging.Logger("messagesigner")
|
||||
|
||||
type MpoolNonceAPI 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 api.WalletAPI
|
||||
lk sync.Mutex
|
||||
mpool MpoolNonceAPI
|
||||
ds datastore.Batching
|
||||
}
|
||||
|
||||
func NewMessageSigner(wallet api.WalletAPI, mpool MpoolNonceAPI, 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
|
||||
|
||||
mb, err := msg.ToStorageBlock()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("serializing message: %w", err)
|
||||
}
|
||||
|
||||
sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{
|
||||
Type: api.MTChainMsg,
|
||||
Extra: mb.RawData(),
|
||||
})
|
||||
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,200 @@
|
||||
package messagesigner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
|
||||
"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.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
from2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to1, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
require.NoError(t, err)
|
||||
to2, err := w.WalletNew(ctx, types.KTSecp256k1)
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+40
-16
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"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 actors.Version // TODO
|
||||
version types.StateTreeVersion
|
||||
info cid.Cid
|
||||
Store cbor.IpldStore
|
||||
|
||||
@@ -120,21 +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 actors.Version) (*StateTree, error) {
|
||||
// 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
|
||||
}
|
||||
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 version {
|
||||
case actors.Version0:
|
||||
switch ver {
|
||||
case types.StateTreeVersion0:
|
||||
// info is undefined
|
||||
case actors.Version2:
|
||||
case types.StateTreeVersion1:
|
||||
var err error
|
||||
info, err = cst.Put(context.TODO(), new(types.StateInfo))
|
||||
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", version)
|
||||
return nil, xerrors.Errorf("unsupported state tree version: %d", ver)
|
||||
}
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), version)
|
||||
root, err := adt.NewMap(adt.WrapStore(context.TODO(), cst), adtForSTVersion(ver))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,7 +163,7 @@ func NewStateTree(cst cbor.IpldStore, version actors.Version) (*StateTree, error
|
||||
return &StateTree{
|
||||
root: root,
|
||||
info: info,
|
||||
version: version,
|
||||
version: ver,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
@@ -154,13 +175,16 @@ 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 = actors.Version0
|
||||
root.Version = types.StateTreeVersion0
|
||||
}
|
||||
|
||||
switch root.Version {
|
||||
case actors.Version0, actors.Version2:
|
||||
case types.StateTreeVersion0, types.StateTreeVersion1:
|
||||
// Load the actual state-tree HAMT.
|
||||
nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), root.Actors, actors.Version(root.Version))
|
||||
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
|
||||
@@ -169,7 +193,7 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) {
|
||||
return &StateTree{
|
||||
root: nd,
|
||||
info: root.Info,
|
||||
version: actors.Version(root.Version),
|
||||
version: root.Version,
|
||||
Store: cst,
|
||||
snaps: newStateSnaps(),
|
||||
}, nil
|
||||
@@ -309,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 == actors.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 {
|
||||
@@ -400,7 +424,7 @@ 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() actors.Version {
|
||||
func (st *StateTree) Version() types.StateTreeVersion {
|
||||
return st.version
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,12 @@ import (
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func BenchmarkStateTreeSet(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -46,7 +45,7 @@ func BenchmarkStateTreeSet(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -76,7 +75,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) {
|
||||
|
||||
func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -118,7 +117,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) {
|
||||
|
||||
func TestSetCache(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -155,7 +154,7 @@ func TestSetCache(t *testing.T) {
|
||||
func TestSnapshots(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cst := cbor.NewMemCborStore()
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(build.NewestNetworkVersion))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(build.NewestNetworkVersion))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -239,7 +238,7 @@ func assertNotHas(t *testing.T, st *StateTree, addr address.Address) {
|
||||
func TestStateTreeConsistency(t *testing.T) {
|
||||
cst := cbor.NewMemCborStore()
|
||||
// TODO: ActorUpgrade: this test tests pre actors v2
|
||||
st, err := NewStateTree(cst, actors.VersionForNetwork(network.Version3))
|
||||
st, err := NewStateTree(cst, VersionForNetwork(network.Version3))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+66
-20
@@ -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,22 +18,55 @@ 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,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
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)
|
||||
}
|
||||
@@ -80,6 +113,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
|
||||
}
|
||||
|
||||
return &api.InvocResult{
|
||||
MsgCid: msg.Cid(),
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
@@ -89,24 +123,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 +154,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() {
|
||||
@@ -130,11 +175,11 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
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)
|
||||
}
|
||||
@@ -184,6 +229,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
|
||||
}
|
||||
|
||||
return &api.InvocResult{
|
||||
MsgCid: msg.Cid(),
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
|
||||
+311
-76
@@ -6,9 +6,12 @@ import (
|
||||
"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/go-state-types/network"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -21,31 +24,137 @@ import (
|
||||
|
||||
"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"
|
||||
"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, ExecCallback, cid.Cid, *types.TipSet) (cid.Cid, error){
|
||||
build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery,
|
||||
build.UpgradeIgnitionHeight: UpgradeIgnition,
|
||||
build.UpgradeActorsV2: UpgradeActorsV2,
|
||||
build.UpgradeLiftoffHeight: UpgradeLiftoff,
|
||||
// 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
|
||||
}
|
||||
|
||||
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.UpgradeTapeHeight,
|
||||
Network: network.Version5,
|
||||
}, {
|
||||
Height: build.UpgradeLiftoffHeight,
|
||||
Network: network.Version5,
|
||||
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
|
||||
}
|
||||
|
||||
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 := ForksAtHeight[height]
|
||||
f, ok := sm.stateMigrations[height]
|
||||
if ok {
|
||||
retCid, err = f(ctx, sm, cb, root, ts)
|
||||
retCid, err = f(ctx, sm, cb, root, height, ts)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
@@ -54,7 +163,12 @@ func (sm *StateManager) handleStateForks(ctx context.Context, root cid.Cid, heig
|
||||
return retCid, nil
|
||||
}
|
||||
|
||||
func doTransfer(cb ExecCallback, 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(tree types.StateTree, from, to address.Address, amt abi.TokenAmount, cb func(trace types.ExecutionTrace)) error {
|
||||
fromAct, err := tree.GetActor(from)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err)
|
||||
@@ -87,7 +201,6 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
||||
From: from,
|
||||
To: to,
|
||||
Value: amt,
|
||||
Nonce: math.MaxUint64,
|
||||
}
|
||||
fakeRct := &types.MessageReceipt{
|
||||
ExitCode: 0,
|
||||
@@ -95,28 +208,20 @@ func doTransfer(cb ExecCallback, tree types.StateTree, from, to address.Address,
|
||||
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)
|
||||
}
|
||||
cb(types.ExecutionTrace{
|
||||
Msg: fakeMsg,
|
||||
MsgRct: fakeRct,
|
||||
Error: "",
|
||||
Duration: 0,
|
||||
GasCharges: nil,
|
||||
Subcalls: nil,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, 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)
|
||||
@@ -151,11 +256,6 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
return cid.Undef, xerrors.Errorf("loading state tree failed: %w", err)
|
||||
}
|
||||
|
||||
ReserveAddress, err := address.NewFromString("t090")
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to parse reserve address: %w", err)
|
||||
}
|
||||
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
@@ -168,6 +268,10 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
var transfers []transfer
|
||||
subcalls := make([]types.ExecutionTrace, 0)
|
||||
transferCb := func(trace types.ExecutionTrace) {
|
||||
subcalls = append(subcalls, trace)
|
||||
}
|
||||
|
||||
// Take all excess funds away, put them into the reserve account
|
||||
err = tree.ForEach(func(addr address.Address, act *types.Actor) error {
|
||||
@@ -181,7 +285,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
if !sysAcc {
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
To: builtin.ReserveAddress,
|
||||
Amt: act.Balance,
|
||||
})
|
||||
}
|
||||
@@ -203,11 +307,13 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
available = st.GetAvailableBalance(act.Balance)
|
||||
}
|
||||
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: ReserveAddress,
|
||||
Amt: available,
|
||||
})
|
||||
if !available.IsZero() {
|
||||
transfers = append(transfers, transfer{
|
||||
From: addr,
|
||||
To: builtin.ReserveAddress,
|
||||
Amt: available,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -217,7 +323,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
// Execute transfers from previous step
|
||||
for _, t := range transfers {
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
@@ -256,7 +362,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
nbalance := big.Min(prevBalance, AccountCap)
|
||||
if nbalance.Sign() != 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: addr,
|
||||
Amt: nbalance,
|
||||
})
|
||||
@@ -283,7 +389,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
mfunds := minerFundsAlloc(power, totalPower)
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: mfunds,
|
||||
})
|
||||
@@ -303,7 +409,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
|
||||
if lbsectors.Length() > 0 {
|
||||
transfersBack = append(transfersBack, transfer{
|
||||
From: ReserveAddress,
|
||||
From: builtin.ReserveAddress,
|
||||
To: minfo.Worker,
|
||||
Amt: BaseMinerBalance,
|
||||
})
|
||||
@@ -320,7 +426,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
for _, t := range transfersBack {
|
||||
if err := doTransfer(cb, tree, t.From, t.To, t.Amt); err != nil {
|
||||
if err := doTransfer(tree, t.From, t.To, t.Amt, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err)
|
||||
}
|
||||
}
|
||||
@@ -330,7 +436,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load burnt funds actor: %w", err)
|
||||
}
|
||||
if err := doTransfer(cb, tree, builtin0.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil {
|
||||
if err := doTransfer(tree, builtin0.BurntFundsActorAddr, builtin.ReserveAddress, burntAct.Balance, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to unburn funds: %w", err)
|
||||
}
|
||||
|
||||
@@ -346,7 +452,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
}
|
||||
|
||||
difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance)
|
||||
if err := doTransfer(cb, tree, ReserveAddress, reimbAddr, difference); err != nil {
|
||||
if err := doTransfer(tree, builtin.ReserveAddress, reimbAddr, difference, transferCb); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to top up reimbursement account: %w", err)
|
||||
}
|
||||
|
||||
@@ -365,13 +471,50 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, cb ExecCal
|
||||
return cid.Undef, xerrors.Errorf("resultant state tree account balance was not correct: %s", total)
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
// record the transfer in execution traces
|
||||
|
||||
fakeMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: builtin.SystemActorAddr,
|
||||
Value: big.Zero(),
|
||||
Nonce: uint64(epoch),
|
||||
}
|
||||
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: subcalls,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("recording transfers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
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)
|
||||
|
||||
nst, err := nv3.MigrateStateTree(ctx, store, root, build.UpgradeIgnitionHeight)
|
||||
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)
|
||||
}
|
||||
@@ -396,22 +539,22 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return cid.Undef, xerrors.Errorf("second split address: %w", err)
|
||||
}
|
||||
|
||||
err = resetGenesisMsigs(ctx, sm, store, tree)
|
||||
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)
|
||||
err = splitGenesisMultisig(ctx, cb, split1, store, tree, 50, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting first msig: %w", err)
|
||||
}
|
||||
|
||||
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50)
|
||||
err = splitGenesisMultisig(ctx, cb, split2, store, tree, 50, epoch)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("splitting second msig: %w", err)
|
||||
}
|
||||
|
||||
err = nv3.CheckStateTree(ctx, store, nst, build.UpgradeIgnitionHeight, builtin0.TotalFilecoin)
|
||||
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)
|
||||
}
|
||||
@@ -419,35 +562,48 @@ func UpgradeIgnition(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
return tree.Flush(ctx)
|
||||
}
|
||||
|
||||
func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
store := sm.cs.Store(ctx)
|
||||
func UpgradeRefuel(ctx context.Context, sm *StateManager, cb ExecCallback, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
|
||||
info, err := store.Put(ctx, new(types.StateInfo))
|
||||
store := sm.cs.Store(ctx)
|
||||
tree, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
err = resetMultisigVesting(ctx, store, tree, builtin.SaftAddress, 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)
|
||||
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{
|
||||
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
|
||||
Version: actors.Version2,
|
||||
Version: types.StateTreeVersion1,
|
||||
Actors: newHamtRoot,
|
||||
Info: info,
|
||||
})
|
||||
@@ -466,10 +622,19 @@ func UpgradeActorsV2(ctx context.Context, sm *StateManager, cb ExecCallback, roo
|
||||
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, ts *types.TipSet) (cid.Cid, error) {
|
||||
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)
|
||||
@@ -510,7 +675,7 @@ func setNetworkName(ctx context.Context, store adt.Store, tree *state.StateTree,
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64) error {
|
||||
func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Address, store adt0.Store, tree *state.StateTree, portions uint64, epoch abi.ChainEpoch) error {
|
||||
if portions < 1 {
|
||||
return xerrors.Errorf("cannot split into 0 portions")
|
||||
}
|
||||
@@ -579,6 +744,11 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
|
||||
}
|
||||
|
||||
i := uint64(0)
|
||||
subcalls := make([]types.ExecutionTrace, 0, portions)
|
||||
transferCb := func(trace types.ExecutionTrace) {
|
||||
subcalls = append(subcalls, trace)
|
||||
}
|
||||
|
||||
for i < portions {
|
||||
keyAddr, err := makeKeyAddr(addr, i)
|
||||
if err != nil {
|
||||
@@ -595,13 +765,46 @@ func splitGenesisMultisig(ctx context.Context, cb ExecCallback, addr address.Add
|
||||
return xerrors.Errorf("setting new msig actor state: %w", err)
|
||||
}
|
||||
|
||||
if err := doTransfer(cb, tree, addr, idAddr, newIbal); err != nil {
|
||||
if err := doTransfer(tree, addr, idAddr, newIbal, transferCb); err != nil {
|
||||
return xerrors.Errorf("transferring split msig balance: %w", err)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if cb != nil {
|
||||
// record the transfer in execution traces
|
||||
|
||||
fakeMsg := &types.Message{
|
||||
From: builtin.SystemActorAddr,
|
||||
To: addr,
|
||||
Value: big.Zero(),
|
||||
Nonce: uint64(epoch),
|
||||
}
|
||||
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: subcalls,
|
||||
},
|
||||
Duration: 0,
|
||||
GasCosts: vm.ZeroGasOutputs(),
|
||||
}); err != nil {
|
||||
return xerrors.Errorf("recording transfers: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -627,7 +830,8 @@ func makeKeyAddr(splitAddr address.Address, count uint64) (address.Address, erro
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store, tree *state.StateTree) error {
|
||||
// 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)
|
||||
@@ -656,7 +860,7 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
||||
return xerrors.Errorf("reading multisig state: %w", err)
|
||||
}
|
||||
|
||||
currState.StartEpoch = build.UpgradeLiftoffHeight
|
||||
currState.StartEpoch = startEpoch
|
||||
|
||||
currActor.Head, err = store.Put(ctx, &currState)
|
||||
if err != nil {
|
||||
@@ -676,3 +880,34 @@ func resetGenesisMsigs(ctx context.Context, sm *StateManager, store adt0.Store,
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+128
-40
@@ -6,30 +6,31 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ipldcbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/stretchr/testify/require"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
init0 "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"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"
|
||||
|
||||
"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() {
|
||||
@@ -77,7 +78,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
|
||||
}
|
||||
@@ -110,51 +111,57 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sm := NewStateManager(cg.ChainStore())
|
||||
|
||||
inv := vm.NewActorRegistry()
|
||||
|
||||
// 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, cb ExecCallback, root cid.Cid, ts *types.TipSet) (cid.Cid, error) {
|
||||
cst := ipldcbor.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())
|
||||
|
||||
st, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
st, err := sm.StateTree(root)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("getting state tree: %w", err)
|
||||
}
|
||||
|
||||
act, err := st.GetActor(taddr)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
act, err := st.GetActor(taddr)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
var tas testActorState
|
||||
if err := cst.Get(ctx, act.Head, &tas); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("in fork handler, failed to run get: %w", err)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
tas.HasUpgraded = 55
|
||||
tas.HasUpgraded = 55
|
||||
|
||||
ns, err := cst.Put(ctx, &tas)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
ns, err := cst.Put(ctx, &tas)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
act.Head = ns
|
||||
act.Head = ns
|
||||
|
||||
if err := st.SetActor(taddr, act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
if err := st.SetActor(taddr, act); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
|
||||
return st.Flush(ctx)
|
||||
return st.Flush(ctx)
|
||||
}}})
|
||||
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 {
|
||||
@@ -168,7 +175,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
|
||||
var msgs []*types.SignedMessage
|
||||
|
||||
enc, err := actors.SerializeParams(&init_.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
enc, err := actors.SerializeParams(&init0.ExecParams{CodeCID: (testActor{}).Code()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -180,7 +187,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
Params: enc,
|
||||
GasLimit: types.TestGasLimit,
|
||||
}
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -208,7 +215,7 @@ func TestForkHeightTriggers(t *testing.T) {
|
||||
}
|
||||
nonce++
|
||||
|
||||
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
|
||||
sig, err := cg.Wallet().WalletSign(ctx, cg.Banker(), m.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -228,3 +235,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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+272
-94
@@ -2,10 +2,16 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/verifreg"
|
||||
|
||||
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
@@ -37,11 +43,35 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
const LookbackNoLimit = abi.ChainEpoch(-1)
|
||||
|
||||
var log = logging.Logger("statemgr")
|
||||
|
||||
type StateManagerAPI interface {
|
||||
LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
}
|
||||
|
||||
type versionSpec struct {
|
||||
networkVersion network.Version
|
||||
atOrBelow abi.ChainEpoch
|
||||
}
|
||||
|
||||
type StateManager struct {
|
||||
cs *store.ChainStore
|
||||
|
||||
// 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
|
||||
@@ -52,12 +82,54 @@ type StateManager struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -128,6 +200,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
|
||||
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{
|
||||
MsgCid: mcid,
|
||||
Msg: msg,
|
||||
MsgRct: &ret.MessageReceipt,
|
||||
ExecutionTrace: ret.ExecutionTrace,
|
||||
@@ -162,7 +235,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
NtwkVersion: sm.GetNtwkVersion,
|
||||
BaseFee: baseFee,
|
||||
}
|
||||
@@ -175,17 +248,12 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
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(builtin0.SystemActorAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runCron := func(epoch abi.ChainEpoch) error {
|
||||
|
||||
cronMsg := &types.Message{
|
||||
To: builtin0.CronActorAddr,
|
||||
From: builtin0.SystemActorAddr,
|
||||
Nonce: ca.Nonce,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
@@ -210,6 +278,18 @@ 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(i); err != nil {
|
||||
return cid.Undef, cid.Undef, err
|
||||
}
|
||||
|
||||
pstate, err = vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// handle state forks
|
||||
// XXX: The state tree
|
||||
newState, err := sm.handleStateForks(ctx, pstate, i, cb, ts)
|
||||
@@ -224,18 +304,6 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
}
|
||||
|
||||
if i > parentEpoch {
|
||||
// run cron for null rounds if any
|
||||
if err := runCron(); err != nil {
|
||||
return cid.Cid{}, cid.Cid{}, err
|
||||
}
|
||||
|
||||
newState, err = vmi.Flush(ctx)
|
||||
if err != nil {
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("flushing vm: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
vmi.SetBlockHeight(i + 1)
|
||||
pstate = newState
|
||||
}
|
||||
@@ -278,15 +346,10 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %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", err)
|
||||
}
|
||||
|
||||
rwMsg := &types.Message{
|
||||
From: builtin0.SystemActorAddr,
|
||||
To: reward.Address,
|
||||
Nonce: sysAct.Nonce,
|
||||
Nonce: uint64(epoch),
|
||||
Value: types.NewInt(0),
|
||||
GasFeeCap: types.NewInt(0),
|
||||
GasPremium: types.NewInt(0),
|
||||
@@ -296,7 +359,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
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, err)
|
||||
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 {
|
||||
@@ -309,7 +372,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
|
||||
}
|
||||
}
|
||||
|
||||
if err := runCron(); err != nil {
|
||||
if err := runCron(epoch); err != nil {
|
||||
return cid.Cid{}, cid.Cid{}, err
|
||||
}
|
||||
|
||||
@@ -449,16 +512,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, LookbackNoLimit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to look back through chain for message: %w", err)
|
||||
}
|
||||
@@ -467,9 +521,9 @@ func (sm *StateManager) GetReceipt(ctx context.Context, msg cid.Cid, ts *types.T
|
||||
}
|
||||
|
||||
// WaitForMessage blocks until a message appears on chain. It looks backwards in the chain to see if this has already
|
||||
// happened. It guarantees that the message has been on chain for at least confidence epochs without being reverted
|
||||
// before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
// happened, with an optional limit to how many epochs it will search. It guarantees that the message has been on
|
||||
// chain for at least confidence epochs without being reverted before returning.
|
||||
func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confidence uint64, lookbackLimit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -507,7 +561,7 @@ func (sm *StateManager) WaitForMessage(ctx context.Context, mcid cid.Cid, confid
|
||||
var backFm cid.Cid
|
||||
backSearchWait := make(chan struct{})
|
||||
go func() {
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg)
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head[0].Val, msg, lookbackLimit)
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message: %w", err)
|
||||
return
|
||||
@@ -599,7 +653,7 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
return head, r, foundMsg, nil
|
||||
}
|
||||
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg)
|
||||
fts, r, foundMsg, err := sm.searchBackForMsg(ctx, head, msg, LookbackNoLimit)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("failed to look back through chain for message %s", mcid)
|
||||
@@ -613,11 +667,33 @@ func (sm *StateManager) SearchForMessage(ctx context.Context, mcid cid.Cid) (*ty
|
||||
return fts, r, foundMsg, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
// searchBackForMsg searches up to limit tipsets backwards from the given
|
||||
// tipset for a message receipt.
|
||||
// If limit is
|
||||
// - 0 then no tipsets are searched
|
||||
// - 5 then five tipset are searched
|
||||
// - LookbackNoLimit then there is no limit
|
||||
func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet, m types.ChainMsg, limit abi.ChainEpoch) (*types.TipSet, *types.MessageReceipt, cid.Cid, error) {
|
||||
limitHeight := from.Height() - limit
|
||||
noLimit := limit == LookbackNoLimit
|
||||
|
||||
cur := from
|
||||
curActor, err := sm.LoadActor(ctx, m.VMMessage().From, cur)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset")
|
||||
}
|
||||
|
||||
mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from)
|
||||
if err != nil {
|
||||
return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err)
|
||||
}
|
||||
|
||||
mNonce := m.VMMessage().Nonce
|
||||
|
||||
for {
|
||||
if cur.Height() == 0 {
|
||||
// If we've reached the genesis block, or we've reached the limit of
|
||||
// how far back to look
|
||||
if cur.Height() == 0 || !noLimit && cur.Height() <= limitHeight {
|
||||
// it ain't here!
|
||||
return nil, nil, cid.Undef, nil
|
||||
}
|
||||
@@ -628,32 +704,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 cur, r, foundMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
cur = ts
|
||||
cur = pts
|
||||
curActor = act
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1122,14 +1203,27 @@ func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// 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(reward.Address)
|
||||
if err != nil {
|
||||
@@ -1196,7 +1290,16 @@ func GetFilBurnt(ctx context.Context, st *state.StateTree) (abi.TokenAmount, err
|
||||
return burnt.Balance, nil
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
cs, err := sm.GetVMCirculatingSupplyDetailed(ctx, height, st)
|
||||
if err != nil {
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return cs.FilCirculating, err
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
sm.genesisMsigLk.Lock()
|
||||
defer sm.genesisMsigLk.Unlock()
|
||||
if sm.preIgnitionGenInfos == nil {
|
||||
@@ -1217,6 +1320,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)
|
||||
@@ -1233,6 +1344,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)
|
||||
|
||||
@@ -1250,38 +1362,102 @@ func (sm *StateManager) GetCirculatingSupplyDetailed(ctx context.Context, height
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
csi, err := sm.GetCirculatingSupplyDetailed(ctx, height, st)
|
||||
circ := big.Zero()
|
||||
unCirc := big.Zero()
|
||||
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
|
||||
switch {
|
||||
case actor.Balance.IsZero():
|
||||
// Do nothing for zero-balance actors
|
||||
break
|
||||
case a == _init.Address ||
|
||||
a == reward.Address ||
|
||||
a == verifreg.Address ||
|
||||
// The power actor itself should never receive funds
|
||||
a == power.Address ||
|
||||
a == builtin.SystemActorAddr ||
|
||||
a == builtin.CronActorAddr ||
|
||||
a == builtin.BurntFundsActorAddr ||
|
||||
a == builtin.SaftAddress ||
|
||||
a == builtin.ReserveAddress:
|
||||
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
|
||||
case a == market.Address:
|
||||
mst, err := market.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.TotalLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||
unCirc = big.Add(unCirc, lb)
|
||||
|
||||
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
|
||||
circ = big.Add(circ, actor.Balance)
|
||||
|
||||
case builtin.IsStorageMinerActor(actor.Code):
|
||||
mst, err := miner.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab, err := mst.AvailableBalance(actor.Balance)
|
||||
|
||||
if err == nil {
|
||||
circ = big.Add(circ, ab)
|
||||
unCirc = big.Add(unCirc, big.Sub(actor.Balance, ab))
|
||||
} else {
|
||||
// Assume any error is because the miner state is "broken" (lower actor balance than locked funds)
|
||||
// In this case, the actor's entire balance is considered "uncirculating"
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
}
|
||||
|
||||
case builtin.IsMultisigActor(actor.Code):
|
||||
mst, err := multisig.Load(sm.cs.Store(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.LockedBalance(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ab := big.Sub(actor.Balance, lb)
|
||||
circ = big.Add(circ, big.Max(ab, big.Zero()))
|
||||
unCirc = big.Add(unCirc, big.Min(actor.Balance, lb))
|
||||
default:
|
||||
return xerrors.Errorf("unexpected actor: %s", a)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return big.Zero(), err
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return csi.FilCirculating, nil
|
||||
total := big.Add(circ, unCirc)
|
||||
if !total.Equals(types.TotalFilecoinInt) {
|
||||
return types.EmptyInt, xerrors.Errorf("total filecoin didn't add to expected amount: %s != %s", total, types.TotalFilecoinInt)
|
||||
}
|
||||
|
||||
return circ, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if height <= build.UpgradeIgnitionHeight {
|
||||
return network.Version2
|
||||
}
|
||||
|
||||
if height <= build.UpgradeActorsV2 {
|
||||
return network.Version3
|
||||
}
|
||||
|
||||
return build.NewestNetworkVersion
|
||||
return sm.latestVersion
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
||||
@@ -1319,3 +1495,5 @@ func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (m
|
||||
}
|
||||
return actState, nil
|
||||
}
|
||||
|
||||
var _ StateManagerAPI = (*StateManager)(nil)
|
||||
|
||||
+91
-16
@@ -9,6 +9,11 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
|
||||
"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"
|
||||
"golang.org/x/xerrors"
|
||||
@@ -21,11 +26,10 @@ import (
|
||||
|
||||
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||
exported2 "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"
|
||||
@@ -379,11 +383,11 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
Rand: r,
|
||||
Bstore: sm.cs.Blockstore(),
|
||||
Syscalls: sm.cs.VMSys(),
|
||||
CircSupplyCalc: sm.GetCirculatingSupply,
|
||||
CircSupplyCalc: sm.GetVMCirculatingSupply,
|
||||
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
|
||||
}
|
||||
@@ -409,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
|
||||
@@ -490,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)
|
||||
}
|
||||
@@ -505,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
|
||||
}
|
||||
|
||||
@@ -595,7 +606,7 @@ 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) {
|
||||
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)
|
||||
@@ -609,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())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestIndexSeeks(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
nbs := blockstore.NewTemporarySync()
|
||||
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil)
|
||||
cs := store.NewChainStore(nbs, syncds.MutexWrap(datastore.NewMapDatastore()), nil, nil)
|
||||
|
||||
_, err = cs.Import(bytes.NewReader(gencar))
|
||||
if err != nil {
|
||||
|
||||
+98
-21
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -38,7 +39,9 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
block "github.com/ipfs/go-block-format"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-datastore"
|
||||
dstore "github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-datastore/query"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
car "github.com/ipld/go-car"
|
||||
@@ -102,7 +105,7 @@ type HeadChangeEvt struct {
|
||||
// 2. a block => messages references cache.
|
||||
type ChainStore struct {
|
||||
bs bstore.Blockstore
|
||||
ds dstore.Datastore
|
||||
ds dstore.Batching
|
||||
|
||||
heaviestLk sync.Mutex
|
||||
heaviest *types.TipSet
|
||||
@@ -124,11 +127,15 @@ type ChainStore struct {
|
||||
vmcalls vm.SyscallBuilder
|
||||
|
||||
evtTypes [1]journal.EventType
|
||||
journal journal.Journal
|
||||
}
|
||||
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore {
|
||||
func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder, j journal.Journal) *ChainStore {
|
||||
c, _ := lru.NewARC(DefaultMsgMetaCacheSize)
|
||||
tsc, _ := lru.NewARC(DefaultTipSetCacheSize)
|
||||
if j == nil {
|
||||
j = journal.NilJournal()
|
||||
}
|
||||
cs := &ChainStore{
|
||||
bs: bs,
|
||||
ds: ds,
|
||||
@@ -137,10 +144,11 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallB
|
||||
mmCache: c,
|
||||
tsCache: tsc,
|
||||
vmcalls: vmcalls,
|
||||
journal: j,
|
||||
}
|
||||
|
||||
cs.evtTypes = [1]journal.EventType{
|
||||
evtTypeHeadChange: journal.J.RegisterEventType("sync", "head_change"),
|
||||
evtTypeHeadChange: j.RegisterEventType("sync", "head_change"),
|
||||
}
|
||||
|
||||
ci := NewChainIndex(cs.LoadTipSet)
|
||||
@@ -288,6 +296,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 {
|
||||
@@ -369,7 +387,7 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo
|
||||
continue
|
||||
}
|
||||
|
||||
journal.J.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
cs.journal.RecordEvent(cs.evtTypes[evtTypeHeadChange], func() interface{} {
|
||||
return HeadChangeEvt{
|
||||
From: r.old.Key(),
|
||||
FromHeight: r.old.Height(),
|
||||
@@ -431,6 +449,53 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlushValidationCache removes all results of block validation from the
|
||||
// chain metadata store. Usually the first step after a new chain import.
|
||||
func (cs *ChainStore) FlushValidationCache() error {
|
||||
log.Infof("clearing block validation cache...")
|
||||
|
||||
dsWalk, err := cs.ds.Query(query.Query{
|
||||
// Potential TODO: the validation cache is not a namespace on its own
|
||||
// but is rather constructed as prefixed-key `foo:bar` via .Instance(), which
|
||||
// in turn does not work with the filter, which can match only on `foo/bar`
|
||||
//
|
||||
// If this is addressed (blockcache goes into its own sub-namespace) then
|
||||
// strings.HasPrefix(...) below can be skipped
|
||||
//
|
||||
//Prefix: blockValidationCacheKeyPrefix.String()
|
||||
KeysOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to initialize key listing query: %w", err)
|
||||
}
|
||||
|
||||
allKeys, err := dsWalk.Rest()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to run key listing query: %w", err)
|
||||
}
|
||||
|
||||
batch, err := cs.ds.Batch()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open a DS batch: %w", err)
|
||||
}
|
||||
|
||||
delCnt := 0
|
||||
for _, k := range allKeys {
|
||||
if strings.HasPrefix(k.Key, blockValidationCacheKeyPrefix.String()) {
|
||||
delCnt++
|
||||
batch.Delete(datastore.RawKey(k.Key)) // nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
if err := batch.Commit(); err != nil {
|
||||
return xerrors.Errorf("failed to commit the DS batch: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("%d block validation entries cleared.", delCnt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetHead sets the chainstores current 'best' head node.
|
||||
// This should only be called if something is broken and needs fixing
|
||||
func (cs *ChainStore) SetHead(ts *types.TipSet) error {
|
||||
@@ -1185,13 +1250,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,
|
||||
@@ -1201,6 +1259,28 @@ 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()
|
||||
|
||||
@@ -1209,15 +1289,15 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
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)
|
||||
@@ -1264,14 +1344,11 @@ 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ func BenchmarkGetRandomness(b *testing.B) {
|
||||
|
||||
bs := blockstore.NewBlockstore(bds)
|
||||
|
||||
cs := store.NewChainStore(bs, mds, nil)
|
||||
cs := store.NewChainStore(bs, mds, nil, nil)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
}
|
||||
|
||||
nbs := blockstore.NewTemporary()
|
||||
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil)
|
||||
cs := store.NewChainStore(nbs, datastore.NewMapDatastore(), nil, nil)
|
||||
|
||||
root, err := cs.Import(buf)
|
||||
if err != nil {
|
||||
|
||||
+48
-44
@@ -44,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 {
|
||||
@@ -65,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
|
||||
@@ -98,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))
|
||||
@@ -109,12 +120,6 @@ func FetchMessagesByCids(
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: We already sort in `fetchCids`, we are duplicating too much work,
|
||||
// we don't need to pass the index.
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = msg
|
||||
return nil
|
||||
})
|
||||
@@ -127,7 +132,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))
|
||||
@@ -138,10 +143,6 @@ func FetchSignedMessagesByCids(
|
||||
return err
|
||||
}
|
||||
|
||||
if out[i] != nil {
|
||||
return fmt.Errorf("received duplicate message")
|
||||
}
|
||||
|
||||
out[i] = smsg
|
||||
return nil
|
||||
})
|
||||
@@ -157,42 +158,45 @@ 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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
ix, ok := cidIndex[block.Cid()]
|
||||
if !ok {
|
||||
return fmt.Errorf("received message we didnt ask for")
|
||||
}
|
||||
|
||||
if err := cb(ix, block); err != nil {
|
||||
return err
|
||||
}
|
||||
for block := range bserv.GetBlocks(ctx, cids) {
|
||||
ix, ok := cidIndex[block.Cid()]
|
||||
if !ok {
|
||||
// Ignore duplicate/unexpected blocks. This shouldn't
|
||||
// happen, but we can be safe.
|
||||
log.Errorw("received duplicate/unexpected block when syncing", "cid", block.Cid())
|
||||
continue
|
||||
}
|
||||
|
||||
// Record that we've received the block.
|
||||
delete(cidIndex, block.Cid())
|
||||
|
||||
if err := cb(ix, block); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(cidIndex) > 0 {
|
||||
err := ctx.Err()
|
||||
if err == nil {
|
||||
err = fmt.Errorf("failed to fetch %d messages for unknown reasons", len(cidIndex))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -475,14 +479,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])
|
||||
}
|
||||
}
|
||||
+69
-44
@@ -217,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")
|
||||
@@ -601,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()
|
||||
|
||||
@@ -617,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()))
|
||||
}
|
||||
@@ -684,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 {
|
||||
@@ -693,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()
|
||||
@@ -729,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)
|
||||
@@ -786,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)
|
||||
@@ -821,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
|
||||
@@ -931,6 +943,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
|
||||
winnerCheck,
|
||||
msgsCheck,
|
||||
baseFeeCheck,
|
||||
stateRootCheck,
|
||||
}
|
||||
|
||||
var merr error
|
||||
@@ -958,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
|
||||
@@ -1272,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())
|
||||
@@ -1368,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
|
||||
}
|
||||
|
||||
@@ -1457,11 +1478,11 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know
|
||||
|
||||
func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []*types.TipSet) error {
|
||||
ss := extractSyncState(ctx)
|
||||
ss.SetHeight(0)
|
||||
ss.SetHeight(headers[len(headers)-1].Height())
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1505,7 +1526,7 @@ func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipS
|
||||
ss.SetStage(api.StageMessages)
|
||||
|
||||
if batchErr != nil {
|
||||
return xerrors.Errorf("failed to fetch messages: %w", err)
|
||||
return xerrors.Errorf("failed to fetch messages: %w", batchErr)
|
||||
}
|
||||
|
||||
for bsi := 0; bsi < len(bstout); bsi++ {
|
||||
@@ -1705,7 +1726,7 @@ func VerifyElectionPoStVRF(ctx context.Context, worker address.Address, rand []b
|
||||
return gen.VerifyVRF(ctx, worker, rand, evrf)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) State() []SyncerState {
|
||||
func (syncer *Syncer) State() []SyncerStateSnapshot {
|
||||
return syncer.syncmgr.State()
|
||||
}
|
||||
|
||||
@@ -1719,6 +1740,10 @@ func (syncer *Syncer) UnmarkBad(blk cid.Cid) {
|
||||
syncer.bad.Remove(blk)
|
||||
}
|
||||
|
||||
func (syncer *Syncer) UnmarkAllBad() {
|
||||
syncer.bad.Purge()
|
||||
}
|
||||
|
||||
func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) {
|
||||
bbr, ok := syncer.bad.Has(blk)
|
||||
return bbr.String(), ok
|
||||
|
||||
@@ -38,7 +38,7 @@ type SyncManager interface {
|
||||
SetPeerHead(ctx context.Context, p peer.ID, ts *types.TipSet)
|
||||
|
||||
// State retrieves the state of the sync workers.
|
||||
State() []SyncerState
|
||||
State() []SyncerStateSnapshot
|
||||
}
|
||||
|
||||
type syncManager struct {
|
||||
@@ -79,7 +79,7 @@ type syncResult struct {
|
||||
const syncWorkerCount = 3
|
||||
|
||||
func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
return &syncManager{
|
||||
sm := &syncManager{
|
||||
bspThresh: 1,
|
||||
peerHeads: make(map[peer.ID]*types.TipSet),
|
||||
syncTargets: make(chan *types.TipSet),
|
||||
@@ -90,6 +90,10 @@ func NewSyncManager(sync SyncFunc) SyncManager {
|
||||
doSync: sync,
|
||||
stop: make(chan struct{}),
|
||||
}
|
||||
for i := range sm.syncStates {
|
||||
sm.syncStates[i] = new(SyncerState)
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *syncManager) Start() {
|
||||
@@ -128,8 +132,8 @@ func (sm *syncManager) SetPeerHead(ctx context.Context, p peer.ID, ts *types.Tip
|
||||
sm.incomingTipSets <- ts
|
||||
}
|
||||
|
||||
func (sm *syncManager) State() []SyncerState {
|
||||
ret := make([]SyncerState, 0, len(sm.syncStates))
|
||||
func (sm *syncManager) State() []SyncerStateSnapshot {
|
||||
ret := make([]SyncerStateSnapshot, 0, len(sm.syncStates))
|
||||
for _, s := range sm.syncStates {
|
||||
ret = append(ret, s.Snapshot())
|
||||
}
|
||||
@@ -405,8 +409,7 @@ func (sm *syncManager) scheduleWorkSent() {
|
||||
}
|
||||
|
||||
func (sm *syncManager) syncWorker(id int) {
|
||||
ss := &SyncerState{}
|
||||
sm.syncStates[id] = ss
|
||||
ss := sm.syncStates[id]
|
||||
for {
|
||||
select {
|
||||
case ts, ok := <-sm.syncTargets:
|
||||
|
||||
+8
-8
@@ -221,8 +221,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
|
||||
var out api.FullNode
|
||||
|
||||
// TODO: Don't ignore stop
|
||||
_, err := node.New(tu.ctx,
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Repo(sourceRepo),
|
||||
@@ -232,6 +231,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
|
||||
)
|
||||
require.NoError(tu.t, err)
|
||||
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
lastTs := blocks[len(blocks)-1].Blocks
|
||||
for _, lastB := range lastTs {
|
||||
@@ -253,8 +253,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
||||
|
||||
var out api.FullNode
|
||||
|
||||
// TODO: Don't ignore stop
|
||||
_, err := node.New(tu.ctx,
|
||||
stop, err := node.New(tu.ctx,
|
||||
node.FullAPI(&out),
|
||||
node.Online(),
|
||||
node.Repo(repo.NewMemory(nil)),
|
||||
@@ -264,6 +263,7 @@ func (tu *syncTestUtil) addClientNode() int {
|
||||
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
|
||||
)
|
||||
require.NoError(tu.t, err)
|
||||
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
tu.nds = append(tu.nds, out)
|
||||
return len(tu.nds) - 1
|
||||
@@ -593,7 +593,7 @@ func TestDuplicateNonce(t *testing.T) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
|
||||
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &types.SignedMessage{
|
||||
@@ -685,7 +685,7 @@ func TestBadNonce(t *testing.T) {
|
||||
GasPremium: types.NewInt(0),
|
||||
}
|
||||
|
||||
sig, err := tu.g.Wallet().Sign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes())
|
||||
sig, err := tu.g.Wallet().WalletSign(context.TODO(), tu.g.Banker(), msg.Cid().Bytes(), api.MsgMeta{})
|
||||
require.NoError(t, err)
|
||||
|
||||
return &types.SignedMessage{
|
||||
@@ -732,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")
|
||||
}
|
||||
@@ -741,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")
|
||||
}
|
||||
|
||||
+21
-25
@@ -11,8 +11,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type SyncerState struct {
|
||||
lk sync.Mutex
|
||||
type SyncerStateSnapshot struct {
|
||||
Target *types.TipSet
|
||||
Base *types.TipSet
|
||||
Stage api.SyncStateStage
|
||||
@@ -22,6 +21,11 @@ type SyncerState struct {
|
||||
End time.Time
|
||||
}
|
||||
|
||||
type SyncerState struct {
|
||||
lk sync.Mutex
|
||||
data SyncerStateSnapshot
|
||||
}
|
||||
|
||||
func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||
if ss == nil {
|
||||
return
|
||||
@@ -29,9 +33,9 @@ func (ss *SyncerState) SetStage(v api.SyncStateStage) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Stage = v
|
||||
ss.data.Stage = v
|
||||
if v == api.StageSyncComplete {
|
||||
ss.End = build.Clock.Now()
|
||||
ss.data.End = build.Clock.Now()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,13 +46,13 @@ func (ss *SyncerState) Init(base, target *types.TipSet) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Target = target
|
||||
ss.Base = base
|
||||
ss.Stage = api.StageHeaders
|
||||
ss.Height = 0
|
||||
ss.Message = ""
|
||||
ss.Start = build.Clock.Now()
|
||||
ss.End = time.Time{}
|
||||
ss.data.Target = target
|
||||
ss.data.Base = base
|
||||
ss.data.Stage = api.StageHeaders
|
||||
ss.data.Height = 0
|
||||
ss.data.Message = ""
|
||||
ss.data.Start = build.Clock.Now()
|
||||
ss.data.End = time.Time{}
|
||||
}
|
||||
|
||||
func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
||||
@@ -58,7 +62,7 @@ func (ss *SyncerState) SetHeight(h abi.ChainEpoch) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Height = h
|
||||
ss.data.Height = h
|
||||
}
|
||||
|
||||
func (ss *SyncerState) Error(err error) {
|
||||
@@ -68,21 +72,13 @@ func (ss *SyncerState) Error(err error) {
|
||||
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
ss.Message = err.Error()
|
||||
ss.Stage = api.StageSyncErrored
|
||||
ss.End = build.Clock.Now()
|
||||
ss.data.Message = err.Error()
|
||||
ss.data.Stage = api.StageSyncErrored
|
||||
ss.data.End = build.Clock.Now()
|
||||
}
|
||||
|
||||
func (ss *SyncerState) Snapshot() SyncerState {
|
||||
func (ss *SyncerState) Snapshot() SyncerStateSnapshot {
|
||||
ss.lk.Lock()
|
||||
defer ss.lk.Unlock()
|
||||
return SyncerState{
|
||||
Base: ss.Base,
|
||||
Target: ss.Target,
|
||||
Stage: ss.Stage,
|
||||
Height: ss.Height,
|
||||
Message: ss.Message,
|
||||
Start: ss.Start,
|
||||
End: ss.End,
|
||||
}
|
||||
return ss.data
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+45
-1
@@ -1,7 +1,10 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -9,9 +12,50 @@ var (
|
||||
ErrKeyExists = fmt.Errorf("key already exists")
|
||||
)
|
||||
|
||||
// KeyType defines a type of a key
|
||||
type KeyType string
|
||||
|
||||
func (kt *KeyType) UnmarshalJSON(bb []byte) error {
|
||||
{
|
||||
// first option, try unmarshaling as string
|
||||
var s string
|
||||
err := json.Unmarshal(bb, &s)
|
||||
if err == nil {
|
||||
*kt = KeyType(s)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var b byte
|
||||
err := json.Unmarshal(bb, &b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unmarshal KeyType either as string nor integer: %w", err)
|
||||
}
|
||||
bst := crypto.SigType(b)
|
||||
|
||||
switch bst {
|
||||
case crypto.SigTypeBLS:
|
||||
*kt = KTBLS
|
||||
case crypto.SigTypeSecp256k1:
|
||||
*kt = KTSecp256k1
|
||||
default:
|
||||
return fmt.Errorf("unknown sigtype: %d", bst)
|
||||
}
|
||||
log.Warnf("deprecation: integer style 'KeyType' is deprecated, switch to string style")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
KTBLS KeyType = "bls"
|
||||
KTSecp256k1 KeyType = "secp256k1"
|
||||
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
|
||||
)
|
||||
|
||||
// KeyInfo is used for storing keys in KeyStore
|
||||
type KeyInfo struct {
|
||||
Type string
|
||||
Type KeyType
|
||||
PrivateKey []byte
|
||||
}
|
||||
|
||||
|
||||
+16
-1
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
@@ -106,6 +107,20 @@ func (m *Message) Cid() cid.Cid {
|
||||
return b.Cid()
|
||||
}
|
||||
|
||||
type mCid struct {
|
||||
*RawMessage
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
type RawMessage Message
|
||||
|
||||
func (m *Message) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&mCid{
|
||||
RawMessage: (*RawMessage)(m),
|
||||
CID: m.Cid(),
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Message) RequiredFunds() BigInt {
|
||||
return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
|
||||
}
|
||||
@@ -180,7 +195,7 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error {
|
||||
|
||||
// since prices might vary with time, this is technically semantic validation
|
||||
if m.GasLimit < minGas {
|
||||
return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
|
||||
return xerrors.Errorf("'GasLimit' field cannot be less than the cost of storing a message on chain %d < %d", m.GasLimit, minGas)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
)
|
||||
|
||||
@@ -70,3 +73,66 @@ func TestEqualCall(t *testing.T) {
|
||||
require.True(t, m1.EqualCall(m3))
|
||||
require.False(t, m1.EqualCall(m4))
|
||||
}
|
||||
|
||||
func TestMessageJson(t *testing.T) {
|
||||
m := &Message{
|
||||
To: builtin.StoragePowerActorAddr,
|
||||
From: builtin.SystemActorAddr,
|
||||
Nonce: 34,
|
||||
Value: big.Zero(),
|
||||
|
||||
GasLimit: 123,
|
||||
GasFeeCap: big.NewInt(234),
|
||||
GasPremium: big.NewInt(234),
|
||||
|
||||
Method: 6,
|
||||
Params: []byte("hai"),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(m)
|
||||
require.NoError(t, err)
|
||||
|
||||
exp := []byte("{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}}")
|
||||
fmt.Println(string(b))
|
||||
|
||||
require.Equal(t, exp, b)
|
||||
|
||||
var um Message
|
||||
require.NoError(t, json.Unmarshal(b, &um))
|
||||
|
||||
require.EqualValues(t, *m, um)
|
||||
}
|
||||
|
||||
func TestSignedMessageJson(t *testing.T) {
|
||||
m := Message{
|
||||
To: builtin.StoragePowerActorAddr,
|
||||
From: builtin.SystemActorAddr,
|
||||
Nonce: 34,
|
||||
Value: big.Zero(),
|
||||
|
||||
GasLimit: 123,
|
||||
GasFeeCap: big.NewInt(234),
|
||||
GasPremium: big.NewInt(234),
|
||||
|
||||
Method: 6,
|
||||
Params: []byte("hai"),
|
||||
}
|
||||
|
||||
sm := &SignedMessage{
|
||||
Message: m,
|
||||
Signature: crypto.Signature{},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(sm)
|
||||
require.NoError(t, err)
|
||||
|
||||
exp := []byte("{\"Message\":{\"Version\":0,\"To\":\"f04\",\"From\":\"f00\",\"Nonce\":34,\"Value\":\"0\",\"GasLimit\":123,\"GasFeeCap\":\"234\",\"GasPremium\":\"234\",\"Method\":6,\"Params\":\"aGFp\",\"CID\":{\"/\":\"bafy2bzaced5rdpz57e64sc7mdwjn3blicglhpialnrph2dlbufhf6iha63dmc\"}},\"Signature\":{\"Type\":0,\"Data\":null},\"CID\":{\"/\":\"bafy2bzacea5ainifngxj3rygaw2hppnyz2cw72x5pysqty2x6dxmjs5qg2uus\"}}")
|
||||
fmt.Println(string(b))
|
||||
|
||||
require.Equal(t, exp, b)
|
||||
|
||||
var um SignedMessage
|
||||
require.NoError(t, json.Unmarshal(b, &um))
|
||||
|
||||
require.EqualValues(t, *sm, um)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
@@ -22,7 +23,7 @@ func Address(i uint64) address.Address {
|
||||
return a
|
||||
}
|
||||
|
||||
func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage {
|
||||
func MkMessage(from, to address.Address, nonce uint64, w *wallet.LocalWallet) *types.SignedMessage {
|
||||
msg := &types.Message{
|
||||
To: to,
|
||||
From: from,
|
||||
@@ -33,7 +34,7 @@ func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.
|
||||
GasPremium: types.NewInt(1),
|
||||
}
|
||||
|
||||
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
|
||||
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -59,9 +60,11 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
||||
var pcids []cid.Cid
|
||||
var height abi.ChainEpoch
|
||||
weight := types.NewInt(weightInc)
|
||||
var timestamp uint64
|
||||
if parents != nil {
|
||||
pcids = parents.Cids()
|
||||
height = parents.Height() + 1
|
||||
timestamp = parents.MinTimestamp() + build.BlockDelaySecs
|
||||
weight = types.BigAdd(parents.Blocks()[0].ParentWeight, weight)
|
||||
}
|
||||
|
||||
@@ -79,6 +82,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types
|
||||
ParentWeight: weight,
|
||||
Messages: c,
|
||||
Height: height,
|
||||
Timestamp: timestamp,
|
||||
ParentStateRoot: pstateRoot,
|
||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
|
||||
ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)),
|
||||
|
||||
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
@@ -62,8 +63,29 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type smCid struct {
|
||||
*RawSignedMessage
|
||||
CID cid.Cid
|
||||
}
|
||||
|
||||
type RawSignedMessage SignedMessage
|
||||
|
||||
func (sm *SignedMessage) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&smCid{
|
||||
RawSignedMessage: (*RawSignedMessage)(sm),
|
||||
CID: sm.Cid(),
|
||||
})
|
||||
}
|
||||
|
||||
func (sm *SignedMessage) ChainLength() int {
|
||||
ser, err := sm.Serialize()
|
||||
var ser []byte
|
||||
var err error
|
||||
if sm.Signature.Type == crypto.SigTypeBLS {
|
||||
// BLS chain message length doesn't include signature
|
||||
ser, err = sm.Message.Serialize()
|
||||
} else {
|
||||
ser, err = sm.Serialize()
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
+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{}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user